From 1f987006db8c27ab949a987380a094503c4296e3 Mon Sep 17 00:00:00 2001 From: xeolabs Date: Tue, 9 Aug 2022 18:06:34 +0200 Subject: [PATCH] Rebuild --- assets/lib/xeokit-sdk.es.js | 206040 +++++++++++++++++---------------- 1 file changed, 103772 insertions(+), 102268 deletions(-) diff --git a/assets/lib/xeokit-sdk.es.js b/assets/lib/xeokit-sdk.es.js index 757e6b0..1e1d147 100644 --- a/assets/lib/xeokit-sdk.es.js +++ b/assets/lib/xeokit-sdk.es.js @@ -100,7 +100,7 @@ class Item { * * Dynamically enable or disable items * * Dynamically show or hide items * * Supports cascading sub-menus - * * Configure custom style with custom CSS (see examples above) + * * Configure custom style with CSS (see examples above) * * ## Usage * @@ -1275,7 +1275,7 @@ const math = { * Returns true if the two 3-element vectors are the same. * @param v1 * @param v2 - * @returns {boolean} + * @returns {Boolean} */ compareVec3(v1, v2) { return (v1[0] === v2[0] && v1[1] === v2[1] && v1[2] === v2[2]); @@ -3431,7 +3431,7 @@ const math = { * Returns true if the two 4x4 matrices are the same. * @param m1 * @param m2 - * @returns {boolean} + * @returns {Boolean} */ compareMat4(m1, m2) { return m1[0] === m2[0] && @@ -4338,7 +4338,7 @@ const math = { /** Returns true if the first AABB contains the second AABB. * @param aabb1 * @param aabb2 - * @returns {boolean} + * @returns {Boolean} */ containsAABB3: function (aabb1, aabb2) { const result = ( @@ -6734,7 +6734,7 @@ function isArray(value) { /** Tests if the given value is a string @param value - @returns {boolean} + @returns {Boolean} @private */ function isString(value) { @@ -6744,7 +6744,7 @@ function isString(value) { /** Tests if the given value is a number @param value - @returns {boolean} + @returns {Boolean} @private */ function isNumeric(value) { @@ -6754,7 +6754,7 @@ function isNumeric(value) { /** Tests if the given value is an ID @param value - @returns {boolean} + @returns {Boolean} @private */ function isID(value) { @@ -6765,7 +6765,7 @@ function isID(value) { Tests if the given components are the same, where the components can be either IDs or instances. @param c1 @param c2 - @returns {boolean} + @returns {Boolean} @private */ function isSameComponent(c1, c2) { @@ -6780,7 +6780,7 @@ function isSameComponent(c1, c2) { /** Tests if the given value is a function @param value - @returns {boolean} + @returns {Boolean} @private */ function isFunction$1(value) { @@ -6790,7 +6790,7 @@ function isFunction$1(value) { /** Tests if the given value is a JavaScript JSON object, eg, ````{ foo: "bar" }````. @param value - @returns {boolean} + @returns {Boolean} @private */ function isObject$1(value) { @@ -6848,7 +6848,7 @@ function applyIf(o, o2) { /** Returns true if the given map is empty. @param obj - @returns {boolean} + @returns {Boolean} @private */ function isEmptyObject$1(obj) { @@ -8791,7 +8791,7 @@ class VBOSceneModelNode { } -const tempVec3a$13 = math.vec3(); +const tempVec3a$14 = math.vec3(); /** * Given a view matrix and a relative-to-center (RTC) coordinate origin, returns a view matrix @@ -8869,9 +8869,9 @@ function worldToRTCPos(worldPos, rtcCenter, rtcPos) { * ````false````, we can safely ignore the data returned in ````rtcPositions```` and ````rtcCenter````, * since ````rtcCenter```` will equal ````[0,0,0]````, and ````rtcPositions```` will contain identical values to ````positions````. */ -function worldToRTCPositions(worldPositions, rtcPositions, rtcCenter, cellSize = 1000000) { +function worldToRTCPositions(worldPositions, rtcPositions, rtcCenter, cellSize = 1000) { - const center = math.getPositionsCenter(worldPositions, tempVec3a$13); + const center = math.getPositionsCenter(worldPositions, tempVec3a$14); const rtcCenterX = Math.round(center[0] / cellSize) * cellSize; const rtcCenterY = Math.round(center[1] / cellSize) * cellSize; @@ -8907,7 +8907,7 @@ function worldToRTCPositions(worldPositions, rtcPositions, rtcCenter, cellSize = */ function getPlaneRTCPos(dist, dir, rtcCenter, rtcPlanePos) { const rtcCenterToPlaneDist = math.dotVec3(dir, rtcCenter) + dist; - const dirNormalized = math.normalizeVec3(dir, tempVec3a$13); + const dirNormalized = math.normalizeVec3(dir, tempVec3a$14); math.mulVec3Scalar(dirNormalized, -rtcCenterToPlaneDist, rtcPlanePos); return rtcPlanePos; } @@ -9183,6 +9183,7 @@ class Marker extends Component { } this._viewPosDirty = true; this.fire("worldPos", this._worldPos); + this._needUpdate(); } /** @@ -9402,7 +9403,7 @@ class Dot { style["z-index"] = cfg.zIndex === undefined ? "40000005" : cfg.zIndex ; style.width = 8 + "px"; style.height = 8 + "px"; - style.visibility = "visible"; + style.visibility = cfg.visible !== false ? "visible" : "hidden"; style.top = 0 + "px"; style.left = 0 + "px"; style["box-shadow"] = "0 2px 5px 0 #182A3D;"; @@ -9595,21 +9596,34 @@ class AngleMeasurement extends Component { this._originDot = new Dot(this._container, { fillColor: this._color, - zIndex: plugin.zIndex + 1 + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined }); this._cornerDot = new Dot(this._container, { fillColor: this._color, - zIndex: plugin.zIndex + 1 + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined }); this._targetDot = new Dot(this._container, { fillColor: this._color, - zIndex: plugin.zIndex + 1 + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined }); - this._originWire = new Wire(this._container, {color: this._color || "blue", thickness: 1, zIndex: plugin.zIndex}); - this._targetWire = new Wire(this._container, {color: this._color || "red", thickness: 1, zIndex: plugin.zIndex}); + this._originWire = new Wire(this._container, { + color: this._color || "blue", + thickness: 1, + zIndex: plugin.zIndex + }); + this._targetWire = new Wire(this._container, { + color: this._color || "red", + thickness: 1, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined + }); - this._angleLabel = new Label(this._container, {fillColor: this._color || "#00BBFF", prefix: "", text: "", zIndex: plugin.zIndex + 2}); + this._angleLabel = new Label(this._container, { + fillColor: this._color || "#00BBFF", + prefix: "", + text: "", + zIndex: plugin.zIndex + 2 + }); this._wpDirty = false; this._vpDirty = false; @@ -9864,10 +9878,23 @@ class AngleMeasurement extends Component { return this._angle; } + /** + * Gets the color of the angle measurement. + * + * The color is an HTML string representation, eg. "#00BBFF" and "blue". + * + * @type {String} + */ get color() { return this._color; } + /** Sets the color of the angle measurement. + * + * The color is given as an HTML string representation, eg. "#00BBFF" and "blue". + * + * @type {String} + */ set color(value) { this._originDot.setFillColor(value); this._cornerDot.setFillColor(value); @@ -9882,7 +9909,7 @@ class AngleMeasurement extends Component { /** * Sets whether this AngleMeasurement is visible or not. * - * @type Boolean + * @type {Boolean} */ set visible(value) { value = value !== false; @@ -9898,7 +9925,7 @@ class AngleMeasurement extends Component { /** * Gets whether this AngleMeasurement is visible or not. * - * @type Boolean + * @type {Boolean} */ get visible() { return this._visible; @@ -10054,10 +10081,9 @@ class AngleMeasurement extends Component { } } -const HOVERING = 0; -const FINDING_ORIGIN = 1; -const FINDING_CORNER = 2; -const FINDING_TARGET = 3; +const FINDING_ORIGIN = 0; +const FINDING_CORNER = 1; +const FINDING_TARGET = 2; /** * Creates {@link AngleMeasurement}s from mouse and touch input. @@ -10084,17 +10110,28 @@ class AngleMeasurementsControl extends Component { this.plugin = plugin; this._active = false; - this._state = HOVERING; + this._state = FINDING_ORIGIN; this._currentAngleMeasurement = null; - this._onhoverSurface = null; - this._onPickedSurface = null; + + // Event handles from CameraControl + this._onMouseHoverSurface = null; this._onHoverNothing = null; + this._onMouseHoverOff = null; this._onPickedNothing = null; + this._onPickedSurface = null; + + // Event handles from Scene.input + this._onInputMouseDown = null; + this._onInputMouseUp = null; + + // Event handles from Canvas element + this._onCanvasTouchStart = null; + this._onCanvasTouchEnd = null; } /** Gets if this AngleMeasurementsControl is currently active, where it is responding to input. * - * @returns {boolean} + * @returns {Boolean} */ get active() { return this._active; @@ -10109,37 +10146,33 @@ class AngleMeasurementsControl extends Component { return; } - this.startDot = new Dot(this.plugin._container, - { - fillColor: this.plugin.defaultColor, - zIndex: this.plugin.zIndex + 1 - }); - - const cameraControl = this.plugin.viewer.cameraControl; - - let over = false; - let entity = null; - let worldPos = math.vec3(); - const hoverCanvasPos = math.vec2(); + const plugin = this.plugin; + const scene = this.scene; + const cameraControl = plugin.viewer.cameraControl; + const canvas = scene.canvas.canvas; + const input = scene.input; - const pickSurfacePrecisionEnabled = this.plugin.viewer.scene.pickSurfacePrecisionEnabled; + const pickSurfacePrecisionEnabled = scene.pickSurfacePrecisionEnabled; - this._onhoverSurface = cameraControl.on("hoverSurface", e => { + let isMouseHoveringEntity = false; + let mouseHoverEntity = null; + let mouseWorldPos = math.vec3(); + const mouseHoverCanvasPos = math.vec2(); - over = true; - entity = e.entity; - worldPos.set(e.worldPos); - hoverCanvasPos.set(e.canvasPos); + let lastMouseCanvasX; + let lastMouseCanvasY; + const mouseCanvasClickTolerance = 5; - if (this._state === HOVERING) { - if (this.startDot) { - this.startDot.setVisible(true); - this.startDot.setPos(e.canvasPos[0], e.canvasPos[1]); - } - this.plugin.viewer.scene.canvas.canvas.style.cursor = "pointer"; - return; - } + const touchCanvasClickTolerance = 5; + const touchStartCanvasPos = math.vec2(); + const touchEndCanvasPos = math.vec2(); + math.vec3(); + this._onMouseHoverSurface = cameraControl.on("hoverSurface", event => { + isMouseHoveringEntity = true; + mouseHoverEntity = event.entity; + mouseWorldPos.set(event.worldPos); + mouseHoverCanvasPos.set(event.canvasPos); if (this._currentAngleMeasurement) { switch (this._state) { case FINDING_CORNER: @@ -10147,51 +10180,42 @@ class AngleMeasurementsControl extends Component { this._currentAngleMeasurement.targetWireVisible = false; this._currentAngleMeasurement.cornerVisible = true; this._currentAngleMeasurement.angleVisible = false; - this._currentAngleMeasurement.corner.entity = e.entity; - this._currentAngleMeasurement.corner.worldPos = e.worldPos; - this.plugin.viewer.scene.canvas.canvas.style.cursor = "pointer"; + this._currentAngleMeasurement.corner.entity = event.entity; + this._currentAngleMeasurement.corner.worldPos = event.worldPos; + canvas.style.cursor = "pointer"; break; case FINDING_TARGET: this._currentAngleMeasurement.targetWireVisible = true; this._currentAngleMeasurement.targetVisible = true; this._currentAngleMeasurement.angleVisible = true; - this._currentAngleMeasurement.target.entity = e.entity; - this._currentAngleMeasurement.target.worldPos = e.worldPos; - this.plugin.viewer.scene.canvas.canvas.style.cursor = "pointer"; + this._currentAngleMeasurement.target.entity = event.entity; + this._currentAngleMeasurement.target.worldPos = event.worldPos; + canvas.style.cursor = "pointer"; break; } } }); - let lastX; - let lastY; - const tolerance = 5; - - this._onInputMouseDown = this.plugin.viewer.scene.input.on("mousedown", (coords) => { - lastX = coords[0]; - lastY = coords[1]; + this._onInputMouseDown = input.on("mousedown", (coords) => { + lastMouseCanvasX = coords[0]; + lastMouseCanvasY = coords[1]; }); - this._onInputMouseUp = this.plugin.viewer.scene.input.on("mouseup", (coords) => { - - if (coords[0] > lastX + tolerance || coords[0] < lastX - tolerance || coords[1] > lastY + tolerance || coords[1] < lastY - tolerance) { + this._onInputMouseUp = input.on("mouseup", (coords) => { + if (coords[0] > lastMouseCanvasX + mouseCanvasClickTolerance || + coords[0] < lastMouseCanvasX - mouseCanvasClickTolerance || + coords[1] > lastMouseCanvasY + mouseCanvasClickTolerance || + coords[1] < lastMouseCanvasY - mouseCanvasClickTolerance) { return; } - - if (this.startDot) { - this.startDot.destroy(); - this.startDot = null; - } - switch (this._state) { - - case HOVERING: - if (over) { + case FINDING_ORIGIN: + if (isMouseHoveringEntity) { if (pickSurfacePrecisionEnabled) { - const pickResult = this.plugin.viewer.scene.pick({ - canvasPos: hoverCanvasPos, + const pickResult = scene.pick({ + canvasPos: mouseHoverCanvasPos, pickSurface: true, - pickSurfacePrecision: true + pickSurfacePrecision: pickSurfacePrecisionEnabled }); if (pickResult && pickResult.worldPos) { worldPos.set(pickResult.worldPos); @@ -10200,16 +10224,16 @@ class AngleMeasurementsControl extends Component { this._currentAngleMeasurement = this.plugin.createMeasurement({ id: math.createUUID(), origin: { - entity: entity, - worldPos: worldPos + entity: mouseHoverEntity, + worldPos: mouseWorldPos }, corner: { - entity: entity, - worldPos: worldPos + entity: mouseHoverEntity, + worldPos: mouseWorldPos }, target: { - entity: entity, - worldPos: worldPos + entity: mouseHoverEntity, + worldPos: mouseWorldPos }, approximate: true }); @@ -10220,16 +10244,14 @@ class AngleMeasurementsControl extends Component { this._currentAngleMeasurement.targetVisible = false; this._currentAngleMeasurement.angleVisible = false; this._state = FINDING_CORNER; - this.fire("measurementStart", this._currentAngleMeasurement); } break; - case FINDING_CORNER: - if (over) { + if (isMouseHoveringEntity) { if (pickSurfacePrecisionEnabled) { - const pickResult = this.plugin.viewer.scene.pick({ - canvasPos: hoverCanvasPos, + const pickResult = scene.pick({ + canvasPos: mouseHoverCanvasPos, pickSurface: true, pickSurfacePrecision: true }); @@ -10245,18 +10267,16 @@ class AngleMeasurementsControl extends Component { if (this._currentAngleMeasurement) { this._currentAngleMeasurement.destroy(); this._currentAngleMeasurement = null; - this._state = HOVERING; - + this._state = FINDING_ORIGIN; this.fire("measurementCancel", this._currentAngleMeasurement); } } break; - case FINDING_TARGET: - if (over) { + if (isMouseHoveringEntity) { if (pickSurfacePrecisionEnabled) { - const pickResult = this.plugin.viewer.scene.pick({ - canvasPos: hoverCanvasPos, + const pickResult = scene.pick({ + canvasPos: mouseHoverCanvasPos, pickSurface: true, pickSurfacePrecision: true }); @@ -10269,13 +10289,12 @@ class AngleMeasurementsControl extends Component { this._currentAngleMeasurement.angleVisible = true; this.fire("measurementEnd", this._currentAngleMeasurement); this._currentAngleMeasurement = null; - this._state = HOVERING; + this._state = FINDING_ORIGIN; } else { if (this._currentAngleMeasurement) { this._currentAngleMeasurement.destroy(); this._currentAngleMeasurement = null; - this._state = HOVERING; - + this._state = FINDING_ORIGIN; this.fire("measurementCancel", this._currentAngleMeasurement); } } @@ -10283,14 +10302,11 @@ class AngleMeasurementsControl extends Component { } }); - this._onHoverNothing = cameraControl.on("hoverOff", e => { - if (this.startDot) { - this.startDot.setVisible(false); - } - over = false; + this._onHoverNothing = cameraControl.on("hoverOff", event => { + + isMouseHoveringEntity = false; if (this._currentAngleMeasurement) { switch (this._state) { - case HOVERING: case FINDING_ORIGIN: this._currentAngleMeasurement.originVisible = false; break; @@ -10308,10 +10324,91 @@ class AngleMeasurementsControl extends Component { break; } - this.plugin.viewer.scene.canvas.canvas.style.cursor = "default"; + canvas.style.cursor = "default"; } }); + canvas.addEventListener("touchstart", this._onCanvasTouchStart = (event) => { + const touches = event.touches; + const changedTouches = event.changedTouches; + if (touches.length === 1 && changedTouches.length === 1) { + getCanvasPosFromEvent$5(touches[0], touchStartCanvasPos); + } + }, {passive: true}); + + canvas.addEventListener("touchend", this._onCanvasTouchEnd = (event) => { + const touches = event.touches; + const changedTouches = event.changedTouches; + if (touches.length === 0 && changedTouches.length === 1) { + getCanvasPosFromEvent$5(changedTouches[0], touchEndCanvasPos); + if (touchEndCanvasPos[0] > touchStartCanvasPos[0] + touchCanvasClickTolerance || + touchEndCanvasPos[0] < touchStartCanvasPos[0] - touchCanvasClickTolerance || + touchEndCanvasPos[1] > touchStartCanvasPos[1] + touchCanvasClickTolerance || + touchEndCanvasPos[1] < touchStartCanvasPos[1] - touchCanvasClickTolerance) { + return; // User is repositioning the camera or model + } + const pickResult = scene.pick({ + canvasPos: touchEndCanvasPos, + pickSurface: true, + pickSurfacePrecision: false + }); + if (pickResult && pickResult.worldPos) { + switch (this._state) { + case FINDING_ORIGIN: + this._currentAngleMeasurement = this.plugin.createMeasurement({ + id: math.createUUID(), + origin: { + entity: pickResult.entity, + worldPos: pickResult.worldPos + }, + corner: { + entity: pickResult.entity, + worldPos: pickResult.worldPos + }, + target: { + entity: pickResult.entity, + worldPos: pickResult.worldPos + }, + approximate: true + }); + this._currentAngleMeasurement.originVisible = true; + this._currentAngleMeasurement.originWireVisible = true; + this._currentAngleMeasurement.cornerVisible = false; + this._currentAngleMeasurement.targetWireVisible = false; + this._currentAngleMeasurement.targetVisible = false; + this._currentAngleMeasurement.angleVisible = false; + this._state = FINDING_CORNER; + this.fire("measurementStart", this._currentAngleMeasurement); + break; + case FINDING_CORNER: + this._currentAngleMeasurement.corner.worldPos = pickResult.worldPos; + this._currentAngleMeasurement.targetWireVisible = false; + this._currentAngleMeasurement.targetVisible = true; + this._currentAngleMeasurement.angleVisible = true; + this._state = FINDING_TARGET; + break; + case FINDING_TARGET: + this._currentAngleMeasurement.target.worldPos = pickResult.worldPos; + // this._currentAngleMeasurement.approximate = false; + this._currentAngleMeasurement.targetVisible = true; + this._currentAngleMeasurement.angleVisible = true; + this.fire("measurementEnd", this._currentAngleMeasurement); + this._currentAngleMeasurement = null; + this._state = FINDING_ORIGIN; + break; + } + } else { + if (this._currentAngleMeasurement) { + this._currentAngleMeasurement.destroy(); + this._currentAngleMeasurement = null; + this._state = FINDING_ORIGIN; + this.fire("measurementCancel", this._currentAngleMeasurement); + } + } + } + // event.stopPropagation(); + }, {passive: true}); + this._active = true; } @@ -10326,24 +10423,23 @@ class AngleMeasurementsControl extends Component { return; } - if (this.startDot) { - this.startDot.destroy(); - this.startDot = null; - } - this.reset(); - const cameraControl = this.plugin.viewer.cameraControl; const input = this.plugin.viewer.scene.input; + const cameraControl = this.plugin.viewer.cameraControl; + const canvas = this.plugin.viewer.scene.canvas.canvas; input.off(this._onInputMouseDown); input.off(this._onInputMouseUp); - cameraControl.off(this._onhoverSurface); + cameraControl.off(this._onMouseHoverSurface); cameraControl.off(this._onPickedSurface); cameraControl.off(this._onHoverNothing); cameraControl.off(this._onPickedNothing); + canvas.removeEventListener("touchstart", this._onCanvasTouchStart); + canvas.removeEventListener("touchend", this._onCanvasTouchEnd); + this._currentAngleMeasurement = null; this._active = false; @@ -10367,7 +10463,7 @@ class AngleMeasurementsControl extends Component { this._currentAngleMeasurement = null; } - this._state = HOVERING; + this._state = FINDING_ORIGIN; } /** @@ -10380,6 +10476,26 @@ class AngleMeasurementsControl extends Component { } +const getCanvasPosFromEvent$5 = function (event, canvasPos) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + let element = event.target; + let totalOffsetLeft = 0; + let totalOffsetTop = 0; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + canvasPos[0] = event.pageX - totalOffsetLeft; + canvasPos[1] = event.pageY - totalOffsetTop; + } + return canvasPos; +}; + /** * {@link Viewer} plugin for measuring angles. * @@ -10524,7 +10640,7 @@ class AngleMeasurementsPlugin extends Plugin { this._measurements = {}; this.defaultColor = cfg.defaultColor; - this.zIndex = cfg.zIndex; + this.zIndex = cfg.zIndex || 10000; } /** @@ -11002,9 +11118,9 @@ class Annotation extends Marker { } } -const tempVec3a$12 = math.vec3(); -const tempVec3b$a = math.vec3(); -const tempVec3c$7 = math.vec3(); +const tempVec3a$13 = math.vec3(); +const tempVec3b$b = math.vec3(); +const tempVec3c$8 = math.vec3(); /** * {@link Viewer} plugin that creates {@link Annotation}s. @@ -11480,9 +11596,9 @@ class AnnotationsPlugin extends Plugin { if (!pickResult.worldPos || !pickResult.worldNormal) { this.error("Param 'pickResult' does not have both worldPos and worldNormal"); } else { - const normalizedWorldNormal = math.normalizeVec3(pickResult.worldNormal, tempVec3a$12); - const offsetVec = math.mulVec3Scalar(normalizedWorldNormal, this._surfaceOffset, tempVec3b$a); - const offsetWorldPos = math.addVec3(pickResult.worldPos, offsetVec, tempVec3c$7); + const normalizedWorldNormal = math.normalizeVec3(pickResult.worldNormal, tempVec3a$13); + const offsetVec = math.mulVec3Scalar(normalizedWorldNormal, this._surfaceOffset, tempVec3b$b); + const offsetWorldPos = math.addVec3(pickResult.worldPos, offsetVec, tempVec3c$8); worldPos = offsetWorldPos; entity = pickResult.entity; } @@ -12102,34 +12218,27 @@ class Canvas extends Component { let lastParent = null; - let tickCount = 0; // chipmunk + let tickCount = 0; this._tick = this.scene.on("tick", () => { - tickCount++; // chipmunk + tickCount++; self._canvasSizeChanged = false; - if (self.optimizeResizeDetection) - { - if (tickCount < 60) // chipmunk - { // chipmunk - return; // chipmunk - } // chipmunk + if (self.optimizeResizeDetection) { + if (tickCount < 10) { + return; + } } - tickCount = 0; // chipmunk + tickCount = 0; const canvas = this.canvas; const newResolutionScale = (this._resolutionScale !== lastResolutionScale); const newWindowSize = (window.innerWidth !== lastWindowWidth || window.innerHeight !== lastWindowHeight); - if (!newWindowSize) // chipmunk - { // chipmunk - return; // chipmunk - } // chipmunk - const newCanvasSize = (canvas.clientWidth !== lastCanvasWidth || canvas.clientHeight !== lastCanvasHeight); const newCanvasPos = (canvas.offsetLeft !== lastCanvasOffsetLeft || canvas.offsetTop !== lastCanvasOffsetTop); @@ -12170,13 +12279,7 @@ class Canvas extends Component { boundary[2] = newWidth; boundary[3] = newHeight; - /** - * Fired whenever this Canvas's {@link Canvas/boundary} property changes. - * - * @event boundary - * @param value The property's new value - */ - if (!newResolutionScale || newCanvasSize) { + if (!newResolutionScale) { this.fire("boundary", boundary); } @@ -12727,7 +12830,6 @@ class PickResult { /** * @private - * @param value */ constructor() { @@ -12764,6 +12866,12 @@ class PickResult { */ this.pickSurfacePrecision = false; + /** + * True when picked from touch input, else false when from mouse input. + * @type {boolean} + */ + this.touchInput = false; + this._canvasPos = new Int16Array([0, 0]); this._origin = new Float64Array([0, 0, 0]); this._direction = new Float64Array([0, 0, 0]); @@ -13041,6 +13149,7 @@ class PickResult { this._gotBary = false; this._gotWorldNormal = false; this._gotUV = false; + this.touchInput = false; } } @@ -13637,7 +13746,7 @@ const MARKER_COLOR = math.vec3([1.0, 0.0, 0.0]); const POINT_SIZE = 20; const MARKER_SPRITE_CLIPZ_OFFSET = -0.001; // Amount that we offset sprite clip Z coords to raise them from surfaces -const tempVec3a$11 = math.vec3(); +const tempVec3a$12 = math.vec3(); /** * Manages occlusion testing. Private member of a Renderer. @@ -13749,7 +13858,7 @@ class OcclusionTester { /** * Returns true if an occlusion test is needed. * - * @returns {boolean} + * @returns {Boolean} */ get needOcclusionTest() { return this._occlusionTestListDirty; @@ -13974,7 +14083,7 @@ class OcclusionTester { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$11)); + gl.uniform3fv(sectionPlaneUniforms.pos, getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$12)); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -14605,7 +14714,8 @@ class SAODepthLimitedBlurRenderer { } outColor = packFloatToRGBA(occlusionSum / weightSum); - }`] + }` + ] }); if (this._program.errors) { @@ -14695,7 +14805,7 @@ class SAODepthLimitedBlurRenderer { gl.uniform1fv(this._uSampleWeights, sampleWeights); - const depthTexture = depthRenderBuffer.getDepthTexture(); + const depthTexture = depthRenderBuffer.getDepthTexture(); const occlusionTexture = occlusionRenderBuffer.getTexture(); program.bindTexture(this._uDepthTexture, depthTexture, 0); // TODO: use FrameCtx.textureUnit @@ -15501,7 +15611,7 @@ const Renderer = function (scene, options) { /** * Returns true if the next call to render() will draw something - * @returns {boolean} + * @returns {Boolean} */ this.needsRender = function () { return (imageDirty || drawableListDirty || stateSortDirty); @@ -15943,6 +16053,19 @@ const Renderer = function (scene, options) { //------------------------------------------------------------------------------------------------------ // Render deferred bins + // + // Order: + // + // 1. Opaque color fill + // 2. Opaque edges + // 3. Opaque X-ray fill + // 4. Opaque X-ray edges + // 5. Opaque highlight + // 6. Transparent highlight + // 7. Selected opaque + // 8. Selected transparent + // 9. Normal transparent + // 10. X-rayed transparent //------------------------------------------------------------------------------------------------------ // Opaque color with SAO @@ -15978,65 +16101,6 @@ const Renderer = function (scene, options) { } } - // Transparent - - if (xrayedFillTransparentBinLen > 0 || xrayEdgesTransparentBinLen > 0 || normalFillTransparentBinLen > 0 || normalEdgesTransparentBinLen > 0) { - gl.enable(gl.CULL_FACE); - gl.enable(gl.BLEND); - if (canvasTransparent) { - gl.blendEquation(gl.FUNC_ADD); - gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); - } else { - gl.blendEquation(gl.FUNC_ADD); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - } - frameCtx.backfaces = false; - if (!alphaDepthMask) { - gl.depthMask(false); - } - - // Transparent X-ray edges - - if (xrayEdgesTransparentBinLen > 0) { - for (i = 0; i < xrayEdgesTransparentBinLen; i++) { - xrayEdgesTransparentBin[i].drawEdgesXRayed(frameCtx); - } - } - - // Transparent X-ray fill - - if (xrayedFillTransparentBinLen > 0) { - for (i = 0; i < xrayedFillTransparentBinLen; i++) { - xrayedFillTransparentBin[i].drawSilhouetteXRayed(frameCtx); - } - } - - // Transparent color edges - - if (normalFillTransparentBinLen > 0 || normalEdgesTransparentBinLen > 0) { - gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - } - if (normalEdgesTransparentBinLen > 0) { - for (i = 0; i < normalEdgesTransparentBinLen; i++) { - drawable = normalEdgesTransparentBin[i]; - drawable.drawEdgesColorTransparent(frameCtx); - } - } - - // Transparent color fill - - if (normalFillTransparentBinLen > 0) { - for (i = 0; i < normalFillTransparentBinLen; i++) { - drawable = normalFillTransparentBin[i]; - drawable.drawColorTransparent(frameCtx); - } - } - gl.disable(gl.BLEND); - if (!alphaDepthMask) { - gl.depthMask(true); - } - } - // Opaque highlight if (highlightedFillOpaqueBinLen > 0 || highlightedEdgesOpaqueBinLen > 0) { @@ -16155,6 +16219,66 @@ const Renderer = function (scene, options) { gl.disable(gl.BLEND); } + // Transparent + + if (xrayedFillTransparentBinLen > 0 || xrayEdgesTransparentBinLen > 0 || normalFillTransparentBinLen > 0 || normalEdgesTransparentBinLen > 0) { + gl.enable(gl.CULL_FACE); + gl.enable(gl.BLEND); + if (canvasTransparent) { + gl.blendEquation(gl.FUNC_ADD); + gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); + } else { + gl.blendEquation(gl.FUNC_ADD); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + } + frameCtx.backfaces = false; + if (!alphaDepthMask) { + gl.depthMask(false); + } + + // Transparent color edges + + if (normalFillTransparentBinLen > 0 || normalEdgesTransparentBinLen > 0) { + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + } + if (normalEdgesTransparentBinLen > 0) { + for (i = 0; i < normalEdgesTransparentBinLen; i++) { + drawable = normalEdgesTransparentBin[i]; + drawable.drawEdgesColorTransparent(frameCtx); + } + } + + // Transparent color fill + + if (normalFillTransparentBinLen > 0) { + for (i = 0; i < normalFillTransparentBinLen; i++) { + drawable = normalFillTransparentBin[i]; + drawable.drawColorTransparent(frameCtx); + } + } + + // Transparent X-ray edges + + if (xrayEdgesTransparentBinLen > 0) { + for (i = 0; i < xrayEdgesTransparentBinLen; i++) { + xrayEdgesTransparentBin[i].drawEdgesXRayed(frameCtx); + } + } + + // Transparent X-ray fill + + if (xrayedFillTransparentBinLen > 0) { + for (i = 0; i < xrayedFillTransparentBinLen; i++) { + xrayedFillTransparentBin[i].drawSilhouetteXRayed(frameCtx); + } + } + + gl.disable(gl.BLEND); + if (!alphaDepthMask) { + gl.depthMask(true); + } + } + const endTime = Date.now(); const frameStats = stats.frame; @@ -19313,8 +19437,8 @@ class CustomProjection extends Component { } const tempVec3$5 = math.vec3(); -const tempVec3b$9 = math.vec3(); -const tempVec3c$6 = math.vec3(); +const tempVec3b$a = math.vec3(); +const tempVec3c$7 = math.vec3(); const tempVec3d$3 = math.vec3(); const tempVec3e$2 = math.vec3(); const tempVec3f$2 = math.vec3(); @@ -19623,8 +19747,8 @@ class Camera extends Component { orbitYaw(angleInc) { let lookEyeVec = math.subVec3(this._eye, this._look, tempVec3$5); math.rotationMat4v(angleInc * 0.0174532925, this._gimbalLock ? this._worldUp : this._up, tempMat); - lookEyeVec = math.transformPoint3(tempMat, lookEyeVec, tempVec3b$9); - this.eye = math.addVec3(this._look, lookEyeVec, tempVec3c$6); // Set eye position as 'look' plus 'eye' vector + lookEyeVec = math.transformPoint3(tempMat, lookEyeVec, tempVec3b$a); + this.eye = math.addVec3(this._look, lookEyeVec, tempVec3c$7); // Set eye position as 'look' plus 'eye' vector this.up = math.transformPoint3(tempMat, this._up, tempVec3d$3); // Rotate 'up' vector } @@ -19641,7 +19765,7 @@ class Camera extends Component { } } let eye2 = math.subVec3(this._eye, this._look, tempVec3$5); - const left = math.cross3Vec3(math.normalizeVec3(eye2, tempVec3b$9), math.normalizeVec3(this._up, tempVec3c$6)); + const left = math.cross3Vec3(math.normalizeVec3(eye2, tempVec3b$a), math.normalizeVec3(this._up, tempVec3c$7)); math.rotationMat4v(angleInc * 0.0174532925, left, tempMat); eye2 = math.transformPoint3(tempMat, eye2, tempVec3d$3); this.up = math.transformPoint3(tempMat, this._up, tempVec3e$2); @@ -19656,8 +19780,8 @@ class Camera extends Component { yaw(angleInc) { let look2 = math.subVec3(this._look, this._eye, tempVec3$5); math.rotationMat4v(angleInc * 0.0174532925, this._gimbalLock ? this._worldUp : this._up, tempMat); - look2 = math.transformPoint3(tempMat, look2, tempVec3b$9); - this.look = math.addVec3(look2, this._eye, tempVec3c$6); + look2 = math.transformPoint3(tempMat, look2, tempVec3b$a); + this.look = math.addVec3(look2, this._eye, tempVec3c$7); if (this._gimbalLock) { this.up = math.transformPoint3(tempMat, this._up, tempVec3d$3); } @@ -19676,7 +19800,7 @@ class Camera extends Component { } } let look2 = math.subVec3(this._look, this._eye, tempVec3$5); - const left = math.cross3Vec3(math.normalizeVec3(look2, tempVec3b$9), math.normalizeVec3(this._up, tempVec3c$6)); + const left = math.cross3Vec3(math.normalizeVec3(look2, tempVec3b$a), math.normalizeVec3(this._up, tempVec3c$7)); math.rotationMat4v(angleInc * 0.0174532925, left, tempMat); this.up = math.transformPoint3(tempMat, this._up, tempVec3f$2); look2 = math.transformPoint3(tempMat, look2, tempVec3d$3); @@ -19693,14 +19817,14 @@ class Camera extends Component { const vec = [0, 0, 0]; let v; if (pan[0] !== 0) { - const left = math.cross3Vec3(math.normalizeVec3(eye2, []), math.normalizeVec3(this._up, tempVec3b$9)); + const left = math.cross3Vec3(math.normalizeVec3(eye2, []), math.normalizeVec3(this._up, tempVec3b$a)); v = math.mulVec3Scalar(left, pan[0]); vec[0] += v[0]; vec[1] += v[1]; vec[2] += v[2]; } if (pan[1] !== 0) { - v = math.mulVec3Scalar(math.normalizeVec3(this._up, tempVec3c$6), pan[1]); + v = math.mulVec3Scalar(math.normalizeVec3(this._up, tempVec3c$7), pan[1]); vec[0] += v[0]; vec[1] += v[1]; vec[2] += v[2]; @@ -19722,12 +19846,12 @@ class Camera extends Component { */ zoom(delta) { const vec = math.subVec3(this._eye, this._look, tempVec3$5); - const lenLook = Math.abs(math.lenVec3(vec, tempVec3b$9)); + const lenLook = Math.abs(math.lenVec3(vec, tempVec3b$a)); const newLenLook = Math.abs(lenLook + delta); if (newLenLook < 0.5) { return; } - const dir = math.normalizeVec3(vec, tempVec3c$6); + const dir = math.normalizeVec3(vec, tempVec3c$7); this.eye = math.addVec3(this._look, math.mulVec3Scalar(dir, newLenLook), tempVec3d$3); } @@ -19883,7 +20007,7 @@ class Camera extends Component { /** * Gets if the World-space X-axis is "up". - * @returns {boolean} + * @returns {Boolean} */ get xUp() { return this._worldUp[0] > this._worldUp[1] && this._worldUp[0] > this._worldUp[2]; @@ -19891,7 +20015,7 @@ class Camera extends Component { /** * Gets if the World-space Y-axis is "up". - * @returns {boolean} + * @returns {Boolean} */ get yUp() { return this._worldUp[1] > this._worldUp[0] && this._worldUp[1] > this._worldUp[2]; @@ -19899,7 +20023,7 @@ class Camera extends Component { /** * Gets if the World-space Z-axis is "up". - * @returns {boolean} + * @returns {Boolean} */ get zUp() { return this._worldUp[2] > this._worldUp[0] && this._worldUp[2] > this._worldUp[1]; @@ -21295,7 +21419,7 @@ class ReadableGeometry extends Geometry { /** * @private - * @returns {boolean} + * @returns {Boolean} */ get isReadableGeometry() { return true; @@ -24492,7 +24616,7 @@ class SAO extends Component { * Returns true if SAO is currently possible, where it is supported, enabled, and the current scene state is compatible. * Called internally by renderer logic. * @private - * @returns {boolean} + * @returns {Boolean} */ get possible() { if (!this._supported) { @@ -25912,6 +26036,20 @@ class Scene extends Component { */ this.reflectionMaps = {}; + /** + * The {@link Bitmap}s in this Scene, each mapped to its {@link Bitmap#id}. + * + * @type {{String:Bitmap}} + */ + this.bitmaps = {}; + + /** + * The {@link LineSet}s in this Scene, each mapped to its {@link LineSet#id}. + * + * @type {{String:LineSet}} + */ + this.lineSets = {}; + /** * The real world offset for this Scene * @@ -26270,6 +26408,16 @@ class Scene extends Component { this._needRecompile = true; } + _bitmapCreated(bitmap) { + this.bitmaps[bitmap.id] = bitmap; + this.scene.fire("bitmapCreated", bitmap, true /* Don't retain event */); + } + + _lineSetCreated(lineSet) { + this.lineSets[lineSet.id] = lineSet; + this.scene.fire("lineSetCreated", lineSet, true /* Don't retain event */); + } + _lightCreated(light) { this.lights[light.id] = light; this.scene._lightsState.addLight(light._state); @@ -26295,6 +26443,16 @@ class Scene extends Component { this._needRecompile = true; } + _bitmapDestroyed(bitmap) { + delete this.bitmaps[bitmap.id]; + this.scene.fire("bitmapDestroyed", bitmap, true /* Don't retain event */); + } + + _lineSetDestroyed(lineSet) { + delete this.lineSets[lineSet.id]; + this.scene.fire("lineSetDestroyed", lineSet, true /* Don't retain event */); + } + _lightDestroyed(light) { delete this.lights[light.id]; this.scene._lightsState.removeLight(light._state); @@ -27450,6 +27608,27 @@ class Scene extends Component { } } + /** + * Destroys all {@link Line}s in this Scene. + */ + clearBitmaps() { + const ids = Object.keys(this.bitmaps); + for (let i = 0, len = ids.length; i < len; i++) { + this.bitmaps[ids[i]].destroy(); + } + } + + + /** + * Destroys all {@link Line}s in this Scene. + */ + clearLines() { + const ids = Object.keys(this.lineSets); + for (let i = 0, len = ids.length; i < len; i++) { + this.lineSets[ids[i]].destroy(); + } + } + /** * Gets the collective axis-aligned boundary (AABB) of a batch of {@link Entity}s that represent objects. * @@ -27792,74 +27971,377 @@ class Scene extends Component { } } +/** + * Texture wrapping mode in which the texture repeats to infinity. + */ const RepeatWrapping = 1000; + +/** + * Texture wrapping mode in which the last pixel of the texture stretches to the edge of the mesh. + */ const ClampToEdgeWrapping = 1001; + +/** + * Texture wrapping mode in which the texture repeats to infinity, mirroring on each repeat. + */ const MirroredRepeatWrapping = 1002; + +/** + * Texture magnification and minification filter that returns the nearest texel to the given sample coordinates. + */ const NearestFilter = 1003; + +/** + * Texture minification filter that chooses the mipmap that most closely matches the size of the pixel being textured and returns the nearest texel to the given sample coordinates. + */ const NearestMipMapNearestFilter = 1004; + +/** + * Texture minification filter that chooses the mipmap that most closely matches the size of the pixel being textured + * and returns the nearest texel to the given sample coordinates. + */ const NearestMipmapNearestFilter = 1004; + +/** + * Texture minification filter that chooses two mipmaps that most closely match the size of the pixel being textured + * and returns the nearest texel to the center of the pixel at the given sample coordinates. + */ const NearestMipmapLinearFilter = 1005; + +/** + * Texture minification filter that chooses two mipmaps that most closely match the size of the pixel being textured + * and returns the nearest texel to the center of the pixel at the given sample coordinates. + */ const NearestMipMapLinearFilter = 1005; + +/** + * Texture magnification and minification filter that returns the weighted average of the four nearest texels to the given sample coordinates. + */ const LinearFilter = 1006; + +/** + * Texture minification filter that chooses the mipmap that most closely matches the size of the pixel being textured and + * returns the weighted average of the four nearest texels to the given sample coordinates. + */ const LinearMipmapNearestFilter = 1007; + +/** + * Texture minification filter that chooses the mipmap that most closely matches the size of the pixel being textured and + * returns the weighted average of the four nearest texels to the given sample coordinates. + */ const LinearMipMapNearestFilter = 1007; + +/** + * Texture minification filter that chooses two mipmaps that most closely match the size of the pixel being textured, + * finds within each mipmap the weighted average of the nearest texel to the center of the pixel, then returns the + * weighted average of those two values. + */ const LinearMipmapLinearFilter = 1008; + +/** + * Texture minification filter that chooses two mipmaps that most closely match the size of the pixel being textured, + * finds within each mipmap the weighted average of the nearest texel to the center of the pixel, then returns the + * weighted average of those two values. + */ const LinearMipMapLinearFilter = 1008; + +/** + * Unsigned 8-bit integer type. + */ const UnsignedByteType = 1009; + +/** + * Signed 8-bit integer type. + */ const ByteType = 1010; + +/** + * Signed 16-bit integer type. + */ const ShortType = 1011; + +/** + * Unsigned 16-bit integer type. + */ const UnsignedShortType = 1012; + +/** + * Signed 32-bit integer type. + */ const IntType = 1013; + +/** + * Unsigned 32-bit integer type. + */ const UnsignedIntType = 1014; + +/** + * Signed 32-bit floating-point type. + */ const FloatType = 1015; + +/** + * Signed 16-bit half-precision floating-point type. + */ const HalfFloatType = 1016; + +/** + * Texture packing mode in which each ````RGBA```` channel is packed into 4 bits, for a combined total of 16 bits. + */ const UnsignedShort4444Type = 1017; + +/** + * Texture packing mode in which the ````RGB```` channels are each packed into 5 bits, and the ````A```` channel is packed into 1 bit, for a combined total of 16 bits. + */ const UnsignedShort5551Type = 1018; + +/** + * Unsigned integer type for 24-bit depth texture data. + */ const UnsignedInt248Type = 1020; + +/** + * Texture sampling mode that discards the ````RGBA```` components and just reads the ````A```` component. + */ const AlphaFormat = 1021; + +/** + * Texture sampling mode that discards the ````A```` component and reads the ````RGB```` components. + */ const RGBFormat = 1022; + +/** + * Texture sampling mode that reads the ````RGBA```` components. + */ const RGBAFormat = 1023; + +/** + * Texture sampling mode that reads each ````RGB```` texture component as a luminance value, converted to a float and clamped + * to ````[0,1]````, while always reading the ````A```` channel as ````1.0````. + */ const LuminanceFormat = 1024; + +/** + * Texture sampling mode that reads each of the ````RGBA```` texture components as a luminance/alpha value, converted to a float and clamped to ````[0,1]````. + */ const LuminanceAlphaFormat = 1025; + +/** + * Texture sampling mode that reads each element as a single depth value, converts it to a float and clamps to ````[0,1]````. + */ const DepthFormat = 1026; + +/** + * Texture sampling mode that + */ const DepthStencilFormat = 1027; + +/** + * Texture sampling mode that discards the ````GBA```` components and just reads the ````R```` component. + */ const RedFormat = 1028; + +/** + * Texture sampling mode that discards the ````GBA```` components and just reads the ````R```` component, as an integer instead of as a float. + */ const RedIntegerFormat = 1029; + +/** + * Texture sampling mode that discards the ````A```` and ````B```` components and just reads the ````R```` and ````G```` components. + */ const RGFormat = 1030; + +/** + * Texture sampling mode that discards the ````A```` and ````B```` components and just reads the ````R```` and ````G```` components, as integers instead of floats. + */ const RGIntegerFormat = 1031; + +/** + * Texture sampling mode that reads the ````RGBA```` components as integers instead of floats. + */ const RGBAIntegerFormat = 1033; + +/** + * Texture format mode in which the texture is formatted as a DXT1 compressed ````RGB```` image. + */ const RGB_S3TC_DXT1_Format = 33776; + +/** + * Texture format mode in which the texture is formatted as a DXT1 compressed ````RGBA```` image. + */ const RGBA_S3TC_DXT1_Format = 33777; + +/** + * Texture format mode in which the texture is formatted as a DXT3 compressed ````RGBA```` image. + */ const RGBA_S3TC_DXT3_Format = 33778; + +/** + * Texture format mode in which the texture is formatted as a DXT5 compressed ````RGBA```` image. + */ const RGBA_S3TC_DXT5_Format = 33779; + +/** + * Texture format mode in which the texture is formatted as a PVRTC compressed + * image, with ````RGB```` compression in 4-bit mode and one block for each 4×4 pixels. + */ const RGB_PVRTC_4BPPV1_Format = 35840; + +/** + * Texture format mode in which the texture is formatted as a PVRTC compressed + * image, with ````RGB```` compression in 2-bit mode and one block for each 8×4 pixels. + */ const RGB_PVRTC_2BPPV1_Format = 35841; + +/** + * Texture format mode in which the texture is formatted as a PVRTC compressed + * image, with ````RGBA```` compression in 4-bit mode and one block for each 4×4 pixels. + */ const RGBA_PVRTC_4BPPV1_Format = 35842; + +/** + * Texture format mode in which the texture is formatted as a PVRTC compressed + * image, with ````RGBA```` compression in 2-bit mode and one block for each 8×4 pixels. + */ const RGBA_PVRTC_2BPPV1_Format = 35843; + +/** + * Texture format mode in which the texture is formatted as an ETC1 compressed + * ````RGB```` image. + */ const RGB_ETC1_Format = 36196; + +/** + * Texture format mode in which the texture is formatted as an ETC2 compressed + * ````RGB```` image. + */ const RGB_ETC2_Format = 37492; + +/** + * Texture format mode in which the texture is formatted as an ETC2 compressed + * ````RGBA```` image. + */ const RGBA_ETC2_EAC_Format = 37496; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_4x4_Format = 37808; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_5x4_Format = 37809; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_5x5_Format = 37810; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_6x5_Format = 37811; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_6x6_Format = 37812; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_8x5_Format = 37813; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_8x6_Format = 37814; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_8x8_Format = 37815; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_10x5_Format = 37816; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_10x6_Format = 37817; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_10x8_Format = 37818; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_10x10_Format = 37819; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_12x10_Format = 37820; + +/** + * Texture format mode in which the texture is formatted as an ATSC compressed + * ````RGBA```` image. + */ const RGBA_ASTC_12x12_Format = 37821; + +/** + * Texture format mode in which the texture is formatted as an BPTC compressed + * ````RGBA```` image. + */ const RGBA_BPTC_Format = 36492; -const _SRGBAFormat = 1035; // fallback for WebGL 1 +/** + * Texture encoding mode in which the texture image is in linear color space. + */ const LinearEncoding = 3000; + +/** + * Texture encoding mode in which the texture image is in sRGB color space. + */ const sRGBEncoding = 3001; -const BasicDepthPacking = 3200; -const RGBADepthPacking = 3201; + +/** + * Media type for GIF images. + */ +const GIFMediaType = 10000; + +/** + * Media type for JPEG images. + */ +const JPEGMediaType = 10001; + +/** + * Media type for PNG images. + */ +const PNGMediaType = 10002; + +/** + * Media type for compressed texture data. + */ +const CompressedMediaType = 10003; /** * @private @@ -29407,7 +29889,7 @@ function buildFragmentDraw(mesh) { * @author xeolabs / https://github.com/xeolabs */ -const tempVec3a$10 = math.vec3(); +const tempVec3a$11 = math.vec3(); const ids$2 = new Map$1({}); @@ -29506,7 +29988,7 @@ DrawRenderer.prototype.drawMesh = function (frameCtx, mesh) { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$10) : sectionPlane.pos); + gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$11) : sectionPlane.pos); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -30644,7 +31126,7 @@ function buildFragment$5(mesh) { const ids$1 = new Map$1({}); -const tempVec3a$$ = math.vec3(); +const tempVec3a$10 = math.vec3(); /** * @private @@ -30728,7 +31210,7 @@ EmphasisFillRenderer.prototype.drawMesh = function (frameCtx, mesh, mode) { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$$) : sectionPlane.pos); + gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$10) : sectionPlane.pos); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -31064,7 +31546,7 @@ function buildFragment$4(mesh) { const ids = new Map$1({}); -const tempVec3a$_ = math.vec3(); +const tempVec3a$$ = math.vec3(); /** * @private @@ -31147,7 +31629,7 @@ EmphasisEdgesRenderer.prototype.drawMesh = function (frameCtx, mesh, mode) { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$_) : sectionPlane.pos); + gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$$) : sectionPlane.pos); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -31442,7 +31924,7 @@ function buildFragment$3(mesh) { * @author xeolabs / https://github.com/xeolabs */ -const tempVec3a$Z = math.vec3(); +const tempVec3a$_ = math.vec3(); // No ID, because there is exactly one PickMeshRenderer per scene @@ -31526,7 +32008,7 @@ PickMeshRenderer.prototype.drawMesh = function (frameCtx, mesh) { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$Z) : sectionPlane.pos); + gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$_) : sectionPlane.pos); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -31759,7 +32241,7 @@ function buildFragment$2(mesh) { * @author xeolabs / https://github.com/xeolabs */ -const tempVec3a$Y = math.vec3(); +const tempVec3a$Z = math.vec3(); /** * @private @@ -31851,7 +32333,7 @@ PickTriangleRenderer.prototype.drawMesh = function (frameCtx, mesh) { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$Y) : sectionPlane.pos); + gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$Z) : sectionPlane.pos); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -32088,7 +32570,7 @@ function buildFragment$1(mesh) { * @author xeolabs / https://github.com/xeolabs */ -const tempVec3a$X = math.vec3(); +const tempVec3a$Y = math.vec3(); // No ID, because there is exactly one PickMeshRenderer per scene @@ -32196,7 +32678,7 @@ OcclusionRenderer.prototype.drawMesh = function (frameCtx, mesh) { gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; - gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$X) : sectionPlane.pos); + gl.uniform3fv(sectionPlaneUniforms.pos, origin ? getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$Y) : sectionPlane.pos); gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } @@ -37614,12383 +38096,15034 @@ class SectionPlane extends Component { } } -const tempVec3$4 = math.vec3(); +const angleAxis = math.vec4(4); +const q1 = math.vec4(); +const q2 = math.vec4(); +const xAxis = math.vec3([1, 0, 0]); +const yAxis = math.vec3([0, 1, 0]); +const zAxis = math.vec3([0, 0, 1]); + +const veca = math.vec3(3); +const vecb = math.vec3(3); + +const identityMat = math.identityMat4(); /** - * {@link Viewer} plugin that saves and loads BCF viewpoints as JSON objects. - * - * BCF is a format for managing issues on a BIM project. This plugin's viewpoints conform to - * the BCF Version 2.1 specification. - * - * ## Saving a BCF Viewpoint - * - * In the example below we'll create a {@link Viewer}, load an ````.XKT```` model into it using an {@link XKTLoaderPlugin}, - * slice the model in half using a {@link SectionPlanesPlugin}, then use a {@link BCFViewpointsPlugin#getViewpoint} - * to save a viewpoint to JSON, which we'll log to the JavaScript developer console. - * - * * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#BCF_SaveViewpoint)] - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, SectionPlanesPlugin, BCFViewpointsPlugin} from "xeokit-sdk.es.js"; - * - * // Create a Viewer - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * // Add a XKTLoaderPlugin - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * // Add a SectionPlanesPlugin - * const sectionPlanes = new SectionPlanesPlugin(viewer); - * - * // Add a BCFViewpointsPlugin - * const bcfViewpoints = new BCFViewpointsPlugin(viewer); - * - * // Load an .XKT model - * const modelNode = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/Schependomlaan.xkt", - * edges: true // Emphasise edges - * }); - * - * // Slice it in half - * sectionPlanes.createSectionPlane({ - * id: "myClip", - * pos: [0, 0, 0], - * dir: [0.5, 0.0, 0.5] - * }); - * - * // When model is loaded, set camera, select some objects and capture a BCF viewpoint to the console - * modelNode.on("loaded", () => { - * - * const scene = viewer.scene; - * const camera = scene.camera; - * - * camera.eye = [-2.37, 18.97, -26.12]; - * camera.look = [10.97, 5.82, -11.22]; - * camera.up = [0.36, 0.83, 0.40]; + * @desc An {@link Entity} that is a scene graph node that can have child Nodes and {@link Mesh}es. * - * scene.setObjectsSelected([ - * "3b2U496P5Ebhz5FROhTwFH", - * "2MGtJUm9nD$Re1_MDIv0g2", - * "3IbuwYOm5EV9Q6cXmwVWqd", - * "3lhisrBxL8xgLCRdxNG$2v", - * "1uDn0xT8LBkP15zQc9MVDW" - * ], true); + * ## Usage * - * const viewpoint = bcfViewpoints.getViewpoint(); - * const viewpointStr = JSON.stringify(viewpoint, null, 4); + * The example below is the same as the one given for {@link Mesh}, since the two classes work together. In this example, + * we'll create a scene graph in which a root Node represents a group and the {@link Mesh}s are leaves. Since Node + * implements {@link Entity}, we can designate the root Node as a model, causing it to be registered by its ID in {@link Scene#models}. * - * console.log(viewpointStr); - * }); - * ```` + * Since {@link Mesh} also implements {@link Entity}, we can designate the leaf {@link Mesh}es as objects, causing them to + * be registered by their IDs in {@link Scene#objects}. * - * ## Saving View Setup Hints + * We can then find those {@link Entity} types in {@link Scene#models} and {@link Scene#objects}. * - * BCFViewpointsPlugin can optionally save hints in the viewpoint, which indicate how to set up the view when - * loading it again. + * We can also update properties of our object-Meshes via calls to {@link Scene#setObjectsHighlighted} etc. * - * Here's the {@link BCFViewpointsPlugin#getViewpoint} call again, this time saving some hints: + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_SceneGraph)] * * ````javascript - * const viewpoint = bcfViewpoints.getViewpoint({ // Options - * spacesVisible: true, // Force IfcSpace types visible in the viewpoint (default is false) - * spaceBoundariesVisible: false, // Show IfcSpace boundaries in the viewpoint (default is false) - * openingsVisible: true // Force IfcOpening types visible in the viewpoint (default is false) - * }); - * ```` + * import {Viewer, Mesh, Node, PhongMaterial} from "xeokit-sdk.es.js"; * - * ## Loading a BCF Viewpoint + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); * - * Assuming that we have our BCF viewpoint in a JSON object, let's now restore it with {@link BCFViewpointsPlugin#setViewpoint}: + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; * - * ````javascript - * bcfViewpoints.setViewpoint(viewpoint); - * ```` + * new Node(viewer.scene, { + * id: "table", + * isModel: true, // <---------- Node represents a model, so is registered by ID in viewer.scene.models + * rotation: [0, 50, 0], + * position: [0, 0, 0], + * scale: [1, 1, 1], * - * ## Handling BCF Incompatibility with xeokit's Camera + * children: [ * - * xeokit's {@link Camera#look} is the current 3D *point-of-interest* (POI). + * new Mesh(viewer.scene, { // Red table leg + * id: "redLeg", + * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects + * position: [-4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * material: new PhongMaterial(viewer.scene, { + * diffuse: [1, 0.3, 0.3] + * }) + * }), * - * A BCF viewpoint, however, has a direction vector instead of a POI, and so {@link BCFViewpointsPlugin#getViewpoint} saves - * xeokit's POI as a normalized vector from {@link Camera#eye} to {@link Camera#look}, which unfortunately loses - * that positional information. Loading the viewpoint with {@link BCFViewpointsPlugin#setViewpoint} will restore {@link Camera#look} to - * the viewpoint's camera position, offset by the normalized vector. + * new Mesh(viewer.scene, { // Green table leg + * id: "greenLeg", + * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects + * position: [4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * material: new PhongMaterial(viewer.scene, { + * diffuse: [0.3, 1.0, 0.3] + * }) + * }), * - * As shown below, providing a ````rayCast```` option to ````setViewpoint```` will set {@link Camera#look} to the closest - * surface intersection on the direction vector. Internally, ````setViewpoint```` supports this option by firing a ray - * along the vector, and if that hits an {@link Entity}, sets {@link Camera#look} to ray's intersection point with the - * Entity's surface. + * new Mesh(viewer.scene, {// Blue table leg + * id: "blueLeg", + * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects + * position: [4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * material: new PhongMaterial(viewer.scene, { + * diffuse: [0.3, 0.3, 1.0] + * }) + * }), * - * ````javascript - * bcfViewpoints.setViewpoint(viewpoint, { - * rayCast: true // <<--------------- Attempt to set Camera#look to surface intersection point (default) - * }); - * ```` + * new Mesh(viewer.scene, { // Yellow table leg + * id: "yellowLeg", + * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects + * position: [-4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * material: new PhongMaterial(viewer.scene, { + * diffuse: [1.0, 1.0, 0.0] + * }) + * }), * - * ## Dealing With Loaded Models That Are Not in the Viewpoint + * new Mesh(viewer.scene, { // Purple table top + * id: "tableTop", + * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects + * position: [0, -3, 0], + * scale: [6, 0.5, 6], + * rotation: [0, 0, 0], + * material: new PhongMaterial(viewer.scene, { + * diffuse: [1.0, 0.3, 1.0] + * }) + * }) + * ] + * }); * - * If, for example, we load model "duplex", hide some objects, then save a BCF viewpoint with - * ````BCFViewpointsPlugin#getViewpoint````, then load another model, "schependomlaan", then load the viewpoint again - * with ````BCFViewpointsPlugin#setViewpoint````, then sometimes all of the objects in model "schependomlaan" become - * visible, along with the visible objects in the viewpoint, which belong to model "duplex". + * // Find Nodes and Meshes by their IDs * - * The reason is that, when saving a BCF viewpoint, BCF logic works like the following pseudo code: + * var table = viewer.scene.models["table"]; // Since table Node has isModel == true * - * ```` - * If numVisibleObjects < numInvisibleObjects - * save IDs of visible objects in BCF - * exceptions = "visible objects" - * else - * save IDS of invisible objects in BCF - * exceptions = "invisible objects" - * ```` + * var redLeg = viewer.scene.objects["redLeg"]; // Since the Meshes have isObject == true + * var greenLeg = viewer.scene.objects["greenLeg"]; + * var blueLeg = viewer.scene.objects["blueLeg"]; * - * When loading the viewpoint again: + * // Highlight one of the table leg Meshes * - * ```` - * If exceptions = "visible objects" - * hide all objects - * show visible objects in BCF - * else - * show all objects - * hide invisible objects in BCF - * ```` + * viewer.scene.setObjectsHighlighted(["redLeg"], true); // Since the Meshes have isObject == true * - * When the exception is "visible objects", loading the viewpoint shows all the objects in the first, which includes - * objects in "schependomlaan", which can be confusing, because those were not even loaded when we first - * saved the viewpoint.. + * // Periodically update transforms on our Nodes and Meshes * - * To solve this, we can supply a ````defaultInvisible```` option to {@link BCFViewpointsPlugin#getViewpoint}, which - * will force the plugin to save the IDs of all visible objects while making invisible objects the exception. + * viewer.scene.on("tick", function () { * - * That way, when we load the viewpoint again, after loading model "schependomlaan", the plugin will hide all objects - * in the scene first (which will include objects belonging to model "schependomlaan"), then make the objects in the - * viewpoint visible (which will only be those of object "duplex"). + * // Rotate legs + * redLeg.rotateY(0.5); + * greenLeg.rotateY(0.5); + * blueLeg.rotateY(0.5); * - * ````javascript - * const viewpoint = bcfViewpoints.getViewpoint({ // Options - * //.. - * defaultInvisible: true - * }); + * // Rotate table + * table.rotateY(0.5); + * table.rotateX(0.3); + * }); * ```` * - * [[Run an example](http://xeokit.github.io/xeokit-sdk/examples/#BCF_LoadViewpoint_defaultInvisible)] - * - * ## Behaviour with XKTLoaderPlugin globalizeObjectIds - * - * Whenever we use {@link XKTLoaderPlugin} to load duplicate copies of the same model, after configuring - * {@link XKTLoaderPlugin#globalizeObjectIds} ````true```` to avoid ````Entity```` ID clashes, this has consequences - * for BCF viewpoints created by {@link BCFViewpointsPlugin#getViewpoint}. - * - * When no duplicate copies of a model are loaded like this, viewpoints created by {@link BCFViewpointsPlugin#getViewpoint} will - * continue to load as usual in other BIM viewers. Conversely, a viewpoint created for a single model in other BIM viewers - * will continue to load as usual with ````BCFViewpointsPlugin````. - * - * When duplicate copies of a model are loaded, however, viewpoints created by {@link BCFViewpointsPlugin#getViewpoint} - * will contain certain changes that will affect the viewpoint's portability, however. Such viewpoints will - * use ````authoring_tool_id```` fields to save the globalized ````Entity#id```` values, which enables the viewpoints to - * capture the states of the individual ````Entitys```` that represent the duplicate IFC elements. Take a look at the - * following two examples to learn more. + * ## Metadata * - * * [Example: Saving a BCF viewpoint containing duplicate models](https://xeokit.github.io/xeokit-sdk/examples/#BCF_SaveViewpoint_MultipleModels) - * * [Example: Loading a BCF viewpoint containing duplicate models](https://xeokit.github.io/xeokit-sdk/examples/#BCF_LoadViewpoint_MultipleModels) + * As mentioned, we can also associate {@link MetaModel}s and {@link MetaObject}s with our Nodes and {@link Mesh}es, + * within a {@link MetaScene}. See {@link MetaScene} for an example. * - * **Caveat:** when loading a BCF viewpoint, we always assume that we have loaded in our target BIM viewer the same models that were - * loaded in the viewpoint's original authoring application when the viewpoint was created. In the case of multi-model - * viewpoints, the target BIM viewer, whether it be xeokit or another BIM viewer, will need to first have those exact - * models loaded, with their objects having globalized IDs, following the same prefixing scheme we're using in - * xeokit. Then, the viewpoint's ````authoring_tool_id```` fields will be able to resolve to their objects within the - * target viewer. -* - * @class BCFViewpointsPlugin + * @implements {Entity} */ -class BCFViewpointsPlugin extends Plugin { +class Node$1 extends Component { /** * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="BCFViewpoints"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {String} [cfg.originatingSystem] Identifies the originating system for BCF records. - * @param {String} [cfg.authoringTool] Identifies the authoring tool for BCF records. + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent scene, generated automatically when omitted. + * @param {Boolean} [cfg.isModel] Specify ````true```` if this Mesh represents a model, in which case the Mesh will be registered by {@link Mesh#id} in {@link Scene#models} and may also have a corresponding {@link MetaModel} with matching {@link MetaModel#id}, registered by that ID in {@link MetaScene#metaModels}. + * @param {Boolean} [cfg.isObject] Specify ````true```` if this Mesh represents an object, in which case the Mesh will be registered by {@link Mesh#id} in {@link Scene#objects} and may also have a corresponding {@link MetaObject} with matching {@link MetaObject#id}, registered by that ID in {@link MetaScene#metaObjects}. + * @param {Node} [cfg.parent] The parent Node. + * @param {Number[]} [cfg.origin] World-space origin for this Node. + * @param {Number[]} [cfg.rtcCenter] Deprecated - renamed to ````origin````. + * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position. + * @param {Number[]} [cfg.scale=[1,1,1]] Local scale. + * @param {Number[]} [cfg.rotation=[0,0,0]] Local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] Local modelling transform matrix. Overrides the position, scale and rotation parameters. + * @param {Number[]} [cfg.offset=[0,0,0]] World-space 3D translation offset. Translates the Node in World space, after modelling transforms. + * @param {Boolean} [cfg.visible=true] Indicates if the Node is initially visible. + * @param {Boolean} [cfg.culled=false] Indicates if the Node is initially culled from view. + * @param {Boolean} [cfg.pickable=true] Indicates if the Node is initially pickable. + * @param {Boolean} [cfg.clippable=true] Indicates if the Node is initially clippable. + * @param {Boolean} [cfg.collidable=true] Indicates if the Node is initially included in boundary calculations. + * @param {Boolean} [cfg.castsShadow=true] Indicates if the Node initially casts shadows. + * @param {Boolean} [cfg.receivesShadow=true] Indicates if the Node initially receives shadows. + * @param {Boolean} [cfg.xrayed=false] Indicates if the Node is initially xrayed. + * @param {Boolean} [cfg.highlighted=false] Indicates if the Node is initially highlighted. + * @param {Boolean} [cfg.selected=false] Indicates if the Mesh is initially selected. + * @param {Boolean} [cfg.edges=false] Indicates if the Node's edges are initially emphasized. + * @param {Number[]} [cfg.colorize=[1.0,1.0,1.0]] Node's initial RGB colorize color, multiplies by the rendered fragment colors. + * @param {Number} [cfg.opacity=1.0] Node's initial opacity factor, multiplies by the rendered fragment alpha. + * @param {Array} [cfg.children] Child Nodes or {@link Mesh}es to add initially. Children must be in the same {@link Scene} and will be removed first from whatever parents they may already have. + * @param {Boolean} [cfg.inheritStates=true] Indicates if children given to this constructor should inherit rendering state from this parent as they are added. Rendering state includes {@link Node#visible}, {@link Node#culled}, {@link Node#pickable}, {@link Node#clippable}, {@link Node#castsShadow}, {@link Node#receivesShadow}, {@link Node#selected}, {@link Node#highlighted}, {@link Node#colorize} and {@link Node#opacity}. */ - constructor(viewer, cfg = {}) { + constructor(owner, cfg = {}) { - super("BCFViewpoints", viewer, cfg); + super(owner, cfg); - /** - * Identifies the originating system to include in BCF viewpoints saved by this plugin. - * @property originatingSystem - * @type {string} - */ - this.originatingSystem = cfg.originatingSystem || "xeokit.io"; + this._parentNode = null; + this._children = []; - /** - * Identifies the authoring tool to include in BCF viewpoints saved by this plugin. - * @property authoringTool - * @type {string} - */ - this.authoringTool = cfg.authoringTool || "xeokit.io"; - } + this._aabb = null; + this._aabbDirty = true; - /** - * Saves viewer state to a BCF viewpoint. - * - * Note that xeokit's {@link Camera#look} is the **point-of-interest**, whereas the BCF ````camera_direction```` is a - * direction vector. Therefore, we save ````camera_direction```` as the vector from {@link Camera#eye} to {@link Camera#look}. - * - * @param {*} [options] Options for getting the viewpoint. - * @param {Boolean} [options.spacesVisible=false] Indicates whether ````IfcSpace```` types should be forced visible in the viewpoint. - * @param {Boolean} [options.openingsVisible=false] Indicates whether ````IfcOpening```` types should be forced visible in the viewpoint. - * @param {Boolean} [options.spaceBoundariesVisible=false] Indicates whether the boundaries of ````IfcSpace```` types should be visible in the viewpoint. - * @param {Boolean} [options.snapshot=true] Indicates whether the snapshot should be included in the viewpoint. - * @param {Boolean} [options.defaultInvisible=false] When ````true````, will save the default visibility of all objects - * as ````false````. This means that when we load the viewpoint again, and there are additional models loaded that - * were not saved in the viewpoint, those models will be hidden when we load the viewpoint, and that only the - * objects in the viewpoint will be visible. - * @param {Boolean} [options.reverseClippingPlanes=false] When ````true````, clipping planes are reversed (https://github.com/buildingSMART/BCF-XML/issues/193) - * @returns {*} BCF JSON viewpoint object - * @example - * - * const viewer = new Viewer(); - * - * const bcfPlugin = new BCFPlugin(viewer, { - * //... - * }); - * - * const viewpoint = bcfPlugin.getViewpoint({ // Options - see constructor - * spacesVisible: false, // Default - * spaceBoundariesVisible: false, // Default - * openingsVisible: false // Default - * }); - * - * // viewpoint will resemble the following: - * - * { - * perspective_camera: { - * camera_view_point: { - * x: 0.0, - * y: 0.0, - * z: 0.0 - * }, - * camera_direction: { - * x: 1.0, - * y: 1.0, - * z: 2.0 - * }, - * camera_up_vector: { - * x: 0.0, - * y: 0.0, - * z: 1.0 - * }, - * field_of_view: 90.0 - * }, - * lines: [], - * clipping_planes: [{ - * location: { - * x: 0.5, - * y: 0.5, - * z: 0.5 - * }, - * direction: { - * x: 1.0, - * y: 0.0, - * z: 0.0 - * } - * }], - * bitmaps: [], - * snapshot: { - * snapshot_type: png, - * snapshot_data: "data:image/png;base64,......" - * }, - * components: { - * visibility: { - * default_visibility: false, - * exceptions: [{ - * ifc_guid: 4$cshxZO9AJBebsni$z9Yk, - * originating_system: xeokit.io, - * authoring_tool_id: xeokit/v1.0 - * }] - * }, - * selection: [{ - * ifc_guid: "4$cshxZO9AJBebsni$z9Yk", - * }] - * } - * } - */ - getViewpoint(options = {}) { - const scene = this.viewer.scene; - const camera = scene.camera; - const realWorldOffset = scene.realWorldOffset; - const reverseClippingPlanes = (options.reverseClippingPlanes === true); - let bcfViewpoint = {}; + this.scene._aabbDirty = true; - // Camera - let lookDirection = math.normalizeVec3(math.subVec3(camera.look, camera.eye, math.vec3())); - let eye = camera.eye; - let up = camera.up; + this._numTriangles = 0; - if (camera.yUp) { - // BCF is Z up - lookDirection = YToZ(lookDirection); - eye = YToZ(eye); - up = YToZ(up); - } + this._scale = math.vec3(); + this._quaternion = math.identityQuaternion(); + this._rotation = math.vec3(); + this._position = math.vec3(); + this._offset = math.vec3(); - const camera_view_point = xyzArrayToObject(math.addVec3(eye, realWorldOffset)); + this._localMatrix = math.identityMat4(); + this._worldMatrix = math.identityMat4(); - if (camera.projection === "ortho") { - bcfViewpoint.orthogonal_camera = { - camera_view_point: camera_view_point, - camera_direction: xyzArrayToObject(lookDirection), - camera_up_vector: xyzArrayToObject(up), - view_to_world_scale: camera.ortho.scale, - }; + this._localMatrixDirty = true; + this._worldMatrixDirty = true; + + if (cfg.matrix) { + this.matrix = cfg.matrix; } else { - bcfViewpoint.perspective_camera = { - camera_view_point: camera_view_point, - camera_direction: xyzArrayToObject(lookDirection), - camera_up_vector: xyzArrayToObject(up), - field_of_view: camera.perspective.fov, - }; + this.scale = cfg.scale; + this.position = cfg.position; + if (cfg.quaternion) ; else { + this.rotation = cfg.rotation; + } } - // Clipping planes - - const sectionPlanes = scene.sectionPlanes; - for (let id in sectionPlanes) { - if (sectionPlanes.hasOwnProperty(id)) { - let sectionPlane = sectionPlanes[id]; + this._isModel = cfg.isModel; + if (this._isModel) { + this.scene._registerModel(this); + } - let location = sectionPlane.pos; + this._isObject = cfg.isObject; + if (this._isObject) { + this.scene._registerObject(this); + } - let direction; - if (reverseClippingPlanes) { - direction = math.negateVec3(sectionPlane.dir, math.vec3()); - } else { - direction = sectionPlane.dir; - } + this.origin = cfg.origin; + this.visible = cfg.visible; + this.culled = cfg.culled; + this.pickable = cfg.pickable; + this.clippable = cfg.clippable; + this.collidable = cfg.collidable; + this.castsShadow = cfg.castsShadow; + this.receivesShadow = cfg.receivesShadow; + this.xrayed = cfg.xrayed; + this.highlighted = cfg.highlighted; + this.selected = cfg.selected; + this.edges = cfg.edges; + this.colorize = cfg.colorize; + this.opacity = cfg.opacity; + this.offset = cfg.offset; - if (camera.yUp) { - // BCF is Z up - location = YToZ(location); - direction = YToZ(direction); - } - math.addVec3(location, realWorldOffset); + // Add children, which inherit state from this Node - location = xyzArrayToObject(location); - direction = xyzArrayToObject(direction); - if (!bcfViewpoint.clipping_planes) { - bcfViewpoint.clipping_planes = []; - } - bcfViewpoint.clipping_planes.push({location, direction}); + if (cfg.children) { + const children = cfg.children; + for (let i = 0, len = children.length; i < len; i++) { + this.addChild(children[i], cfg.inheritStates); } } - // Entity states - - bcfViewpoint.components = { - visibility: { - view_setup_hints: { - spaces_visible: !!options.spacesVisible, - space_boundaries_visible: !!options.spaceBoundariesVisible, - openings_visible: !!options.openingsVisible - } + if (cfg.parentId) { + const parentNode = this.scene.components[cfg.parentId]; + if (!parentNode) { + this.error("Parent not found: '" + cfg.parentId + "'"); + } else if (!parentNode.isNode) { + this.error("Parent is not a Node: '" + cfg.parentId + "'"); + } else { + parentNode.addChild(this); } - }; - - const opacityObjectIds = new Set(scene.opacityObjectIds); - const xrayedObjectIds = new Set(scene.xrayedObjectIds); - const colorizedObjectIds = new Set(scene.colorizedObjectIds); - - const coloringMap = Object.values(scene.objects) - .filter(entity => opacityObjectIds.has(entity.id) || colorizedObjectIds.has(entity.id) || xrayedObjectIds.has(entity.id)) - .reduce((coloringMap, entity) => { - - let color = colorizeToRGB(entity.colorize); - let alpha; - - if (entity.xrayed) { - if (scene.xrayMaterial.fillAlpha === 0.0 && scene.xrayMaterial.edgeAlpha !== 0.0) { - // BCF can't deal with edges. If xRay is implemented only with edges, set an arbitrary opacity - alpha = 0.1; - } else { - alpha = scene.xrayMaterial.fillAlpha; - } - alpha = Math.round(alpha * 255).toString(16).padStart(2, "0"); - color = alpha + color; - } else if (opacityObjectIds.has(entity.id)) { - alpha = Math.round(entity.opacity * 255).toString(16).padStart(2, "0"); - color = alpha + color; - } - - if (!coloringMap[color]) { - coloringMap[color] = []; - } - - const objectId = entity.id; - const originalSystemId = entity.originalSystemId; - const component = { - ifc_guid: originalSystemId, - originating_system: this.originatingSystem - }; - if (originalSystemId !== objectId) { - component.authoring_tool_id = objectId; - } - - coloringMap[color].push(component); + } else if (cfg.parent) { + if (!cfg.parent.isNode) { + this.error("Parent is not a Node"); + } + cfg.parent.addChild(this); + } + } - return coloringMap; + //------------------------------------------------------------------------------------------------------------------ + // Entity members + //------------------------------------------------------------------------------------------------------------------ - }, {}); + /** + * Returns true to indicate that this Component is an Entity. + * @type {Boolean} + */ + get isEntity() { + return true; + } - const coloringArray = Object.entries(coloringMap).map(([color, components]) => { - return {color, components}; - }); + /** + * Returns ````true```` if this Mesh represents a model. + * + * When this returns ````true````, the Mesh will be registered by {@link Mesh#id} in {@link Scene#models} and + * may also have a corresponding {@link MetaModel}. + * + * @type {Boolean} + */ + get isModel() { + return this._isModel; + } - bcfViewpoint.components.coloring = coloringArray; + /** + * Returns ````true```` if this Node represents an object. + * + * When ````true```` the Node will be registered by {@link Node#id} in + * {@link Scene#objects} and may also have a {@link MetaObject} with matching {@link MetaObject#id}. + * + * @type {Boolean} + * @abstract + */ + get isObject() { + return this._isObject; + } - const objectIds = scene.objectIds; - const visibleObjects = scene.visibleObjects; - const visibleObjectIds = scene.visibleObjectIds; - const invisibleObjectIds = objectIds.filter(id => !visibleObjects[id]); - const selectedObjectIds = scene.selectedObjectIds; + /** + * Gets the Node's World-space 3D axis-aligned bounding box. + * + * Represented by a six-element Float64Array containing the min/max extents of the + * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. + * + * @type {Number[]} + */ + get aabb() { + if (this._aabbDirty) { + this._updateAABB(); + } + return this._aabb; + } - if (options.defaultInvisible || visibleObjectIds.length < invisibleObjectIds.length) { - bcfViewpoint.components.visibility.exceptions = this._createBCFComponents(visibleObjectIds); - bcfViewpoint.components.visibility.default_visibility = false; + /** + * Sets the World-space origin for this Node. + * + * @type {Float64Array} + */ + set origin(origin) { + if (origin) { + if (!this._origin) { + this._origin = math.vec3(); + } + this._origin.set(origin); } else { - bcfViewpoint.components.visibility.exceptions = this._createBCFComponents(invisibleObjectIds); - bcfViewpoint.components.visibility.default_visibility = true; + if (this._origin) { + this._origin = null; + } + } + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].origin = origin; } + this.glRedraw(); + } - bcfViewpoint.components.selection = this._createBCFComponents(selectedObjectIds); + /** + * Gets the World-space origin for this Node. + * + * @type {Float64Array} + */ + get origin() { + return this._origin; + } - if (options.snapshot !== false) { - bcfViewpoint.snapshot = { - snapshot_type: "png", - snapshot_data: this.viewer.getSnapshot({format: "png"}) - }; - } + /** + * Sets the World-space origin for this Node. + * + * Deprecated and replaced by {@link Node#origin}. + * + * @deprecated + * @type {Float64Array} + */ + set rtcCenter(rtcCenter) { + this.origin = rtcCenter; + } - return bcfViewpoint; + /** + * Gets the World-space origin for this Node. + * + * Deprecated and replaced by {@link Node#origin}. + * + * @deprecated + * @type {Float64Array} + */ + get rtcCenter() { + return this.origin; } - _createBCFComponents(objectIds) { - const scene = this.viewer.scene; - const components = []; - for (let i = 0, len = objectIds.length; i < len; i++) { - const objectId = objectIds[i]; - const entity = scene.objects[objectId]; - if (entity) { - const component = { - ifc_guid: entity.originalSystemId, - originating_system: this.originatingSystem - }; - if (entity.originalSystemId !== objectId) { - component.authoring_tool_id = objectId; - } - components.push(component); - } - } - return components; + /** + * The number of triangles in this Node. + * + * @type {Number} + */ + get numTriangles() { + return this._numTriangles; } /** - * Sets viewer state to the given BCF viewpoint. + * Sets if this Node and all child Nodes and {@link Mesh}es are visible. * - * Note that xeokit's {@link Camera#look} is the **point-of-interest**, whereas the BCF ````camera_direction```` is a - * direction vector. Therefore, when loading a BCF viewpoint, we set {@link Camera#look} to the absolute position - * obtained by offsetting the BCF ````camera_view_point```` along ````camera_direction````. + * Only rendered both {@link Node#visible} is ````true```` and {@link Node#culled} is ````false````. * - * When loading a viewpoint, we also have the option to find {@link Camera#look} as the closest point of intersection - * (on the surface of any visible and pickable {@link Entity}) with a 3D ray fired from ````camera_view_point```` in - * the direction of ````camera_direction````. + * When {@link Node#isObject} and {@link Node#visible} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#visibleObjects}. * - * @param {*} bcfViewpoint BCF JSON viewpoint object, - * shows default visible entities and restores camera to initial default position. - * @param {*} [options] Options for setting the viewpoint. - * @param {Boolean} [options.rayCast=true] When ````true```` (default), will attempt to set {@link Camera#look} to the closest - * point of surface intersection with a ray fired from the BCF ````camera_view_point```` in the direction of ````camera_direction````. - * @param {Boolean} [options.immediate=true] When ````true```` (default), immediately set camera position. - * @param {Boolean} [options.duration] Flight duration in seconds. Overrides {@link CameraFlightAnimation#duration}. Only applies when ````immediate```` is ````false````. - * @param {Boolean} [options.reset=true] When ````true```` (default), set {@link Entity#xrayed} and {@link Entity#highlighted} ````false```` on all scene objects. - * @param {Boolean} [options.reverseClippingPlanes=false] When ````true````, clipping planes are reversed (https://github.com/buildingSMART/BCF-XML/issues/193) - * @param {Boolean} [options.updateCompositeObjects=false] When ````true````, then when visibility and selection updates refer to composite objects (eg. an IfcBuildingStorey), - * then this method will apply the updates to objects within those composites. + * @type {Boolean} */ - setViewpoint(bcfViewpoint, options = {}) { - if (!bcfViewpoint) { - return; + set visible(visible) { + visible = visible !== false; + this._visible = visible; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].visible = visible; } + if (this._isObject) { + this.scene._objectVisibilityUpdated(this, visible); + } + } - const viewer = this.viewer; - const scene = viewer.scene; - const camera = scene.camera; - const rayCast = (options.rayCast !== false); - const immediate = (options.immediate !== false); - const reset = (options.reset !== false); - const realWorldOffset = scene.realWorldOffset; - const reverseClippingPlanes = (options.reverseClippingPlanes === true); - - scene.clearSectionPlanes(); - - if (bcfViewpoint.clipping_planes) { - bcfViewpoint.clipping_planes.forEach(function (e) { - let pos = xyzObjectToArray(e.location, tempVec3$4); - let dir = xyzObjectToArray(e.direction, tempVec3$4); - - if (reverseClippingPlanes) { - math.negateVec3(dir); - } - math.subVec3(pos, realWorldOffset); + /** + * Gets if this Node is visible. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * When {@link Node#isObject} and {@link Node#visible} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#visibleObjects}. + * + * @type {Boolean} + */ + get visible() { + return this._visible; + } - if (camera.yUp) { - pos = ZToY(pos); - dir = ZToY(dir); - } - new SectionPlane(scene, {pos, dir}); - }); + /** + * Sets if this Node and all child Nodes and {@link Mesh}es are xrayed. + * + * When {@link Node#isObject} and {@link Node#xrayed} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#xrayedObjects}. + * + * @type {Boolean} + */ + set xrayed(xrayed) { + xrayed = !!xrayed; + this._xrayed = xrayed; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].xrayed = xrayed; } - - if (reset) { - scene.setObjectsXRayed(scene.xrayedObjectIds, false); - scene.setObjectsHighlighted(scene.highlightedObjectIds, false); - scene.setObjectsSelected(scene.selectedObjectIds, false); + if (this._isObject) { + this.scene._objectXRayedUpdated(this, xrayed); } + } - if (bcfViewpoint.components) { - - if (bcfViewpoint.components.visibility) { - - if (!bcfViewpoint.components.visibility.default_visibility) { - scene.setObjectsVisible(scene.objectIds, false); - if (bcfViewpoint.components.visibility.exceptions) { - bcfViewpoint.components.visibility.exceptions.forEach((component) => this._withBCFComponent(options, component, entity => entity.visible = true)); - } - } else { - scene.setObjectsVisible(scene.objectIds, true); - if (bcfViewpoint.components.visibility.exceptions) { - bcfViewpoint.components.visibility.exceptions.forEach((component) => this._withBCFComponent(options, component, entity => entity.visible = false)); - } - } - - const view_setup_hints = bcfViewpoint.components.visibility.view_setup_hints; - if (view_setup_hints) { - if (view_setup_hints.spaces_visible === false) { - scene.setObjectsVisible(viewer.metaScene.getObjectIDsByType("IfcSpace"), false); - } - if (view_setup_hints.openings_visible === false) { - scene.setObjectsVisible(viewer.metaScene.getObjectIDsByType("IfcOpening"), false); - } - if (view_setup_hints.space_boundaries_visible !== undefined) ; - } - } - - if (bcfViewpoint.components.selection) { - scene.setObjectsSelected(scene.selectedObjectIds, false); - bcfViewpoint.components.selection.forEach(component => this._withBCFComponent(options, component, entity => entity.selected = true)); - - } - - if (bcfViewpoint.components.coloring) { - bcfViewpoint.components.coloring.forEach(coloring => { - - let color = coloring.color; - let alpha = 0; - let alphaDefined = false; - - if (color.length === 8) { - alpha = parseInt(color.substring(0, 2), 16) / 256; - if (alpha <= 1.0 && alpha >= 0.95) { - alpha = 1.0; - } - color = color.substring(2); - alphaDefined = true; - } - - const colorize = [ - parseInt(color.substring(0, 2), 16) / 256, - parseInt(color.substring(2, 4), 16) / 256, - parseInt(color.substring(4, 6), 16) / 256 - ]; + /** + * Gets if this Node is xrayed. + * + * When {@link Node#isObject} and {@link Node#xrayed} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#xrayedObjects}. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Boolean} + */ + get xrayed() { + return this._xrayed; + } - coloring.components.map(component => - this._withBCFComponent(options, component, entity => { - entity.colorize = colorize; - if (alphaDefined) { - entity.opacity = alpha; - } - })); - }); - } + /** + * Sets if this Node and all child Nodes and {@link Mesh}es are highlighted. + * + * When {@link Node#isObject} and {@link Node#highlighted} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#highlightedObjects}. + * + * @type {Boolean} + */ + set highlighted(highlighted) { + highlighted = !!highlighted; + this._highlighted = highlighted; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].highlighted = highlighted; } - - if (bcfViewpoint.perspective_camera || bcfViewpoint.orthogonal_camera) { - let eye; - let look; - let up; - let projection; - - if (bcfViewpoint.perspective_camera) { - eye = xyzObjectToArray(bcfViewpoint.perspective_camera.camera_view_point, tempVec3$4); - look = xyzObjectToArray(bcfViewpoint.perspective_camera.camera_direction, tempVec3$4); - up = xyzObjectToArray(bcfViewpoint.perspective_camera.camera_up_vector, tempVec3$4); - - camera.perspective.fov = bcfViewpoint.perspective_camera.field_of_view; - - projection = "perspective"; - } else { - eye = xyzObjectToArray(bcfViewpoint.orthogonal_camera.camera_view_point, tempVec3$4); - look = xyzObjectToArray(bcfViewpoint.orthogonal_camera.camera_direction, tempVec3$4); - up = xyzObjectToArray(bcfViewpoint.orthogonal_camera.camera_up_vector, tempVec3$4); - - camera.ortho.scale = bcfViewpoint.orthogonal_camera.view_to_world_scale; - - projection = "ortho"; - } - - math.subVec3(eye, realWorldOffset); - - if (camera.yUp) { - eye = ZToY(eye); - look = ZToY(look); - up = ZToY(up); - } - - if (rayCast) { - const hit = scene.pick({ - pickSurface: true, // <<------ This causes picking to find the intersection point on the entity - origin: eye, - direction: look - }); - look = (hit ? hit.worldPos : math.addVec3(eye, look, tempVec3$4)); - } else { - look = math.addVec3(eye, look, tempVec3$4); - } - - if (immediate) { - camera.eye = eye; - camera.look = look; - camera.up = up; - camera.projection = projection; - } else { - viewer.cameraFlight.flyTo({eye, look, up, duration: options.duration, projection}); - } + if (this._isObject) { + this.scene._objectHighlightedUpdated(this, highlighted); } } - _withBCFComponent(options, component, callback) { - - const viewer = this.viewer; - const scene = viewer.scene; - - if (component.authoring_tool_id && component.originating_system === this.originatingSystem) { - - const id = component.authoring_tool_id; - const entity = scene.objects[id]; - - if (entity) { - callback(entity); - return - } + /** + * Gets if this Node is highlighted. + * + * When {@link Node#isObject} and {@link Node#highlighted} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#highlightedObjects}. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Boolean} + */ + get highlighted() { + return this._highlighted; + } - if (options.updateCompositeObjects) { - const metaObject = viewer.metaScene.metaObjects[id]; - if (metaObject) { - scene.withObjects(viewer.metaScene.getObjectIDsInSubtree(id), callback); - return; - } - } + /** + * Sets if this Node and all child Nodes and {@link Mesh}es are selected. + * + * When {@link Node#isObject} and {@link Node#selected} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#selectedObjects}. + * + * @type {Boolean} + */ + set selected(selected) { + selected = !!selected; + this._selected = selected; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].selected = selected; } + if (this._isObject) { + this.scene._objectSelectedUpdated(this, selected); + } + } - if (component.ifc_guid) { - - const originalSystemId = component.ifc_guid; - const entity = scene.objects[originalSystemId]; - - if (entity) { - callback(entity); - return; - } - - if (options.updateCompositeObjects) { - const metaObject = viewer.metaScene.metaObjects[originalSystemId]; - if (metaObject) { - scene.withObjects(viewer.metaScene.getObjectIDsInSubtree(originalSystemId), callback); - return; - } - } - - Object.keys(scene.models).forEach((modelId) => { - - const id = math.globalizeObjectId(modelId, originalSystemId); - const entity = scene.objects[id]; - - if (entity) { - callback(entity); - return; - } + /** + * Gets if this Node is selected. + * + * When {@link Node#isObject} and {@link Node#selected} are both ````true```` the Node will be + * registered by {@link Node#id} in {@link Scene#selectedObjects}. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Boolean} + */ + get selected() { + return this._selected; + } - if (options.updateCompositeObjects) { - const metaObject = viewer.metaScene.metaObjects[id]; - if (metaObject) { - scene.withObjects(viewer.metaScene.getObjectIDsInSubtree(id), callback); - return; - } - } - }); + /** + * Sets if this Node and all child Nodes and {@link Mesh}es are edge-enhanced. + * + * @type {Boolean} + */ + set edges(edges) { + edges = !!edges; + this._edges = edges; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].edges = edges; } } /** - * Destroys this BCFViewpointsPlugin. + * Gets if this Node's edges are enhanced. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Boolean} */ - destroy() { - super.destroy(); + get edges() { + return this._edges; } -} - -function xyzArrayToObject(arr) { - return {"x": arr[0], "y": arr[1], "z": arr[2]}; -} - -function xyzObjectToArray(xyz, arry) { - arry = new Float64Array(3); - arry[0] = xyz.x; - arry[1] = xyz.y; - arry[2] = xyz.z; - return arry; -} - -function YToZ(vec) { - return new Float64Array([vec[0], -vec[2], vec[1]]); -} - -function ZToY(vec) { - return new Float64Array([vec[0], vec[2], -vec[1]]); -} - -function colorizeToRGB(color) { - let rgb = ""; - rgb += Math.round(color[0] * 255).toString(16).padStart(2, "0"); - rgb += Math.round(color[1] * 255).toString(16).padStart(2, "0"); - rgb += Math.round(color[2] * 255).toString(16).padStart(2, "0"); - return rgb; -} - -var distVec3 = math.vec3(); - -const lengthWire = (x1, y1, x2, y2) => { - var a = x1 - x2; - var b = y1 - y2; - return Math.sqrt(a * a + b * b); -}; - -/** - * @desc Measures the distance between two 3D points. - * - * See {@link DistanceMeasurementsPlugin} for more info. - */ -class DistanceMeasurement extends Component { /** - * @private + * Sets if this Node and all child Nodes and {@link Mesh}es are culled. + * + * @type {Boolean} */ - constructor(plugin, cfg = {}) { - - super(plugin.viewer.scene, cfg); - - /** - * The {@link DistanceMeasurementsPlugin} that owns this DistanceMeasurement. - * @type {DistanceMeasurementsPlugin} - */ - this.plugin = plugin; - - this._container = cfg.container; - if (!this._container) { - throw "config missing: container"; + set culled(culled) { + culled = !!culled; + this._culled = culled; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].culled = culled; } - - this._eventSubs = {}; - - var scene = this.plugin.viewer.scene; - - this._originMarker = new Marker(scene, cfg.origin); - this._targetMarker = new Marker(scene, cfg.target); - - this._originWorld = math.vec3(); - this._targetWorld = math.vec3(); - - this._wp = new Float64Array(24); - this._vp = new Float64Array(24); - this._pp = new Float64Array(24); - this._cp = new Int16Array(8); - - this._xAxisLabelCulled = false; - this._yAxisLabelCulled = false; - this._zAxisLabelCulled = false; - - this._color = cfg.color || this.plugin.defaultColor; - - this._originDot = new Dot(this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined - }); - - this._targetDot = new Dot(this._container, { - fillColor: this._color, - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined - }); - - this._lengthWire = new Wire(this._container, { - color: this._color, - thickness: 2, - zIndex: plugin.zIndex - }); - - this._xAxisWire = new Wire(this._container, { - color: "red", - thickness: 1, - zIndex: plugin.zIndex - }); - - this._yAxisWire = new Wire(this._container, { - color: "green", - thickness: 1, - zIndex: plugin.zIndex - }); - - this._zAxisWire = new Wire(this._container, { - color: "blue", - thickness: 1, - zIndex: plugin.zIndex - }); - - this._lengthLabel = new Label(this._container, { - fillColor: this._color, - prefix: "", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined - }); - - this._xAxisLabel = new Label(this._container, { - fillColor: "red", - prefix: "X", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined - }); - - this._yAxisLabel = new Label(this._container, { - fillColor: "green", - prefix: "Y", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined - }); - - this._zAxisLabel = new Label(this._container, { - fillColor: "blue", - prefix: "Z", - text: "", - zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined - }); - - this._wpDirty = false; - this._vpDirty = false; - this._cpDirty = false; - - this._visible = false; - this._originVisible = false; - this._targetVisible = false; - this._wireVisible = false; - this._axisVisible = false; - - this._originMarker.on("worldPos", (value) => { - this._originWorld.set(value || [0, 0, 0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - - this._targetMarker.on("worldPos", (value) => { - this._targetWorld.set(value || [0, 0, 0]); - this._wpDirty = true; - this._needUpdate(0); // No lag - }); - - this._onViewMatrix = scene.camera.on("viewMatrix", () => { - this._vpDirty = true; - this._needUpdate(0); // No lag - }); - - this._onProjMatrix = scene.camera.on("projMatrix", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this._onCanvasBoundary = scene.canvas.on("boundary", () => { - this._cpDirty = true; - this._needUpdate(0); // No lag - }); - - this._onMetricsUnits = scene.metrics.on("units", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this._onMetricsScale = scene.metrics.on("scale", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this._onMetricsOrigin = scene.metrics.on("origin", () => { - this._cpDirty = true; - this._needUpdate(); - }); - - this.approximate = cfg.approximate; - this.visible = cfg.visible; - this.originVisible = cfg.originVisible; - this.targetVisible = cfg.targetVisible; - this.wireVisible = cfg.wireVisible; - this.axisVisible = cfg.axisVisible; } - _update() { - - if (!this._visible) { - return; - } - - const scene = this.plugin.viewer.scene; - - if (this._wpDirty) { - - this._wp[0] = this._originWorld[0]; - this._wp[1] = this._originWorld[1]; - this._wp[2] = this._originWorld[2]; - this._wp[3] = 1.0; - - this._wp[4] = this._targetWorld[0]; - this._wp[5] = this._originWorld[1]; - this._wp[6] = this._originWorld[2]; - this._wp[7] = 1.0; - - this._wp[8] = this._targetWorld[0]; - this._wp[9] = this._targetWorld[1]; - this._wp[10] = this._originWorld[2]; - this._wp[11] = 1.0; - - this._wp[12] = this._targetWorld[0]; - this._wp[13] = this._targetWorld[1]; - this._wp[14] = this._targetWorld[2]; - this._wp[15] = 1.0; - - this._wpDirty = false; - this._vpDirty = true; - } - - if (this._vpDirty) { - - math.transformPositions4(scene.camera.viewMatrix, this._wp, this._vp); - - this._vp[3] = 1.0; - this._vp[7] = 1.0; - this._vp[11] = 1.0; - this._vp[15] = 1.0; - - this._vpDirty = false; - this._cpDirty = true; - } - - const near = -0.3; - const vpz1 = this._originMarker.viewPos[2]; - const vpz2 = this._targetMarker.viewPos[2]; - - if (vpz1 > near || vpz2 > near) { - - this._xAxisLabel.setVisible(false); - this._yAxisLabel.setVisible(false); - this._zAxisLabel.setVisible(false); - this._lengthLabel.setVisible(false); - - this._xAxisWire.setVisible(false); - this._yAxisWire.setVisible(false); - this._zAxisWire.setVisible(false); - this._lengthWire.setVisible(false); - - this._originDot.setVisible(false); - this._targetDot.setVisible(false); - - return; - } - - if (this._cpDirty) { - - math.transformPositions4(scene.camera.project.matrix, this._vp, this._pp); - - var pp = this._pp; - var cp = this._cp; - - var canvas = scene.canvas.canvas; - var offsets = canvas.getBoundingClientRect(); - const containerOffsets = this._container.getBoundingClientRect(); - var top = offsets.top - containerOffsets.top; - var left = offsets.left - containerOffsets.left; - var aabb = scene.canvas.boundary; - var canvasWidth = aabb[2]; - var canvasHeight = aabb[3]; - var j = 0; - - const metrics = this.plugin.viewer.scene.metrics; - const scale = metrics.scale; - const units = metrics.units; - const unitInfo = metrics.unitsInfo[units]; - const unitAbbrev = unitInfo.abbrev; - - for (var i = 0, len = pp.length; i < len; i += 4) { - cp[j] = left + Math.floor((1 + pp[i + 0] / pp[i + 3]) * canvasWidth / 2); - cp[j + 1] = top + Math.floor((1 - pp[i + 1] / pp[i + 3]) * canvasHeight / 2); - j += 2; - } - - this._originDot.setPos(cp[0], cp[1]); - this._targetDot.setPos(cp[6], cp[7]); - - this._lengthWire.setStartAndEnd(cp[0], cp[1], cp[6], cp[7]); - - this._xAxisWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]); - this._yAxisWire.setStartAndEnd(cp[2], cp[3], cp[4], cp[5]); - this._zAxisWire.setStartAndEnd(cp[4], cp[5], cp[6], cp[7]); - - this._lengthLabel.setPosOnWire(cp[0], cp[1], cp[6], cp[7]); - this._xAxisLabel.setPosOnWire(cp[0], cp[1], cp[2], cp[3]); - this._yAxisLabel.setPosOnWire(cp[2], cp[3], cp[4], cp[5]); - this._zAxisLabel.setPosOnWire(cp[4], cp[5], cp[6], cp[7]); - - const tilde = this._approximate ? " ~ " : " = "; - - this._length = Math.abs(math.lenVec3(math.subVec3(this._targetWorld, this._originWorld, distVec3))); - this._lengthLabel.setText(tilde + (this._length * scale).toFixed(2) + unitAbbrev); - - const xAxisCanvasLength = Math.abs(lengthWire(cp[0], cp[1], cp[2], cp[3])); - const yAxisCanvasLength = Math.abs(lengthWire(cp[2], cp[3], cp[4], cp[5])); - const zAxisCanvasLength = Math.abs(lengthWire(cp[4], cp[5], cp[6], cp[7])); - - const labelMinAxisLength = this.plugin.labelMinAxisLength; - - this._xAxisLabelCulled = (xAxisCanvasLength < labelMinAxisLength); - this._yAxisLabelCulled = (yAxisCanvasLength < labelMinAxisLength); - this._zAxisLabelCulled = (zAxisCanvasLength < labelMinAxisLength); - - if (!this._xAxisLabelCulled) { - this._xAxisLabel.setText(tilde + Math.abs((this._targetWorld[0] - this._originWorld[0]) * scale).toFixed(2) + unitAbbrev); - this._xAxisLabel.setVisible(this.axisVisible); - } else { - this._xAxisLabel.setVisible(false); - } - - if (!this._yAxisLabelCulled) { - this._yAxisLabel.setText(tilde + Math.abs((this._targetWorld[1] - this._originWorld[1]) * scale).toFixed(2) + unitAbbrev); - this._yAxisLabel.setVisible(this.axisVisible); - } else { - this._yAxisLabel.setVisible(false); - } - - if (!this._zAxisLabelCulled) { - this._zAxisLabel.setText(tilde + Math.abs((this._targetWorld[2] - this._originWorld[2]) * scale).toFixed(2) + unitAbbrev); - this._zAxisLabel.setVisible(this.axisVisible); - } else { - this._zAxisLabel.setVisible(false); - } - - this._originDot.setVisible(this._visible && this._originVisible); - this._targetDot.setVisible(this._visible && this._targetVisible); - this._xAxisWire.setVisible(this.axisVisible); - this._yAxisWire.setVisible(this.axisVisible); - this._zAxisWire.setVisible(this.axisVisible); - this._lengthWire.setVisible(this.wireVisible); - this._lengthLabel.setVisible(this.wireVisible); - - this._cpDirty = false; - } + /** + * Gets if this Node is culled. + * + * @type {Boolean} + */ + get culled() { + return this._culled; } /** - * Sets whether this DistanceMeasurement indicates that its measurement is approximate. + * Sets if this Node and all child Nodes and {@link Mesh}es are clippable. * - * This is ````true```` by default. + * Clipping is done by the {@link SectionPlane}s in {@link Scene#clips}. * * @type {Boolean} */ - set approximate(approximate) { - approximate = approximate !== false; - if (this._approximate === approximate) { - return; + set clippable(clippable) { + clippable = clippable !== false; + this._clippable = clippable; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].clippable = clippable; } - this._approximate = approximate; - this._cpDirty = true; - this._needUpdate(0); } /** - * Gets whether this DistanceMeasurement indicates that its measurement is approximate. + * Gets if this Node is clippable. * - * This is ````true```` by default. + * Clipping is done by the {@link SectionPlane}s in {@link Scene#clips}. + * + * Child Nodes and {@link Mesh}es may have different values for this property. * * @type {Boolean} */ - get approximate() { - return this._approximate; + get clippable() { + return this._clippable; } - + /** - * Gets the origin {@link Marker}. + * Sets if this Node and all child Nodes and {@link Mesh}es are included in boundary calculations. * - * @type {Marker} + * @type {Boolean} */ - get origin() { - return this._originMarker; + set collidable(collidable) { + collidable = collidable !== false; + this._collidable = collidable; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].collidable = collidable; + } } /** - * Gets the target {@link Marker}. + * Gets if this Node is included in boundary calculations. * - * @type {Marker} + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Boolean} */ - get target() { - return this._targetMarker; + get collidable() { + return this._collidable; } /** - * Gets the World-space direct point-to-point distance between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target}. + * Sets if this Node and all child Nodes and {@link Mesh}es are pickable. * - * @type {Number} + * Picking is done via calls to {@link Scene#pick}. + * + * @type {Boolean} */ - get length() { - this._update(); - const scale = this.plugin.viewer.scene.metrics.scale; - return this._length * scale; - } - - get color() { - return this._color; - } - - set color(value) { - this._color = value; - this._originDot.setFillColor(value); - this._targetDot.setFillColor(value); - this._lengthWire.setColor(value); - this._lengthLabel.setFillColor(value); + set pickable(pickable) { + pickable = pickable !== false; + this._pickable = pickable; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].pickable = pickable; + } } /** - * Sets whether this DistanceMeasurement is visible or not. + * Gets if to this Node is pickable. + * + * Picking is done via calls to {@link Scene#pick}. + * + * Child Nodes and {@link Mesh}es may have different values for this property. * - * @type Boolean + * @type {Boolean} */ - set visible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultVisible; - this._visible = value; - this._originDot.setVisible(this._visible && this._originVisible); - this._targetDot.setVisible(this._visible && this._targetVisible); - this._lengthWire.setVisible(this._visible && this._wireVisible); - this._lengthLabel.setVisible(this._visible && this._wireVisible); - var axisVisible = this._visible && this._axisVisible; - this._xAxisWire.setVisible(axisVisible); - this._yAxisWire.setVisible(axisVisible); - this._zAxisWire.setVisible(axisVisible); - this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled); - this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled); - this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled); + get pickable() { + return this._pickable; } /** - * Gets whether this DistanceMeasurement is visible or not. + * Sets the RGB colorize color for this Node and all child Nodes and {@link Mesh}es}. + * + * Multiplies by rendered fragment colors. + * + * Each element of the color is in range ````[0..1]````. * - * @type Boolean + * @type {Number[]} */ - get visible() { - return this._visible; + set colorize(rgb) { + let colorize = this._colorize; + if (!colorize) { + colorize = this._colorize = new Float32Array(4); + colorize[3] = 1.0; + } + if (rgb) { + colorize[0] = rgb[0]; + colorize[1] = rgb[1]; + colorize[2] = rgb[2]; + } else { + colorize[0] = 1; + colorize[1] = 1; + colorize[2] = 1; + } + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].colorize = colorize; + } + if (this._isObject) { + const colorized = (!!rgb); + this.scene._objectColorizeUpdated(this, colorized); + } } /** - * Sets if the origin {@link Marker} is visible. + * Gets the RGB colorize color for this Node. * - * @type {Boolean} + * Each element of the color is in range ````[0..1]````. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Number[]} */ - set originVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultOriginVisible; - this._originVisible = value; - this._originDot.setVisible(this._visible && this._originVisible); + get colorize() { + return this._colorize.slice(0, 3); } /** - * Gets if the origin {@link Marker} is visible. + * Sets the opacity factor for this Node and all child Nodes and {@link Mesh}es. * - * @type {Boolean} + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} */ - get originVisible() { - return this._originVisible; + set opacity(opacity) { + let colorize = this._colorize; + if (!colorize) { + colorize = this._colorize = new Float32Array(4); + colorize[0] = 1; + colorize[1] = 1; + colorize[2] = 1; + } + colorize[3] = opacity !== null && opacity !== undefined ? opacity : 1.0; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].opacity = opacity; + } + if (this._isObject) { + const opacityUpdated = (opacity !== null && opacity !== undefined); + this.scene._objectOpacityUpdated(this, opacityUpdated); + } } /** - * Sets if the target {@link Marker} is visible. + * Gets this Node's opacity factor. * - * @type {Boolean} + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Number} */ - set targetVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultTargetVisible; - this._targetVisible = value; - this._targetDot.setVisible(this._visible && this._targetVisible); + get opacity() { + return this._colorize[3]; } /** - * Gets if the target {@link Marker} is visible. + * Sets if this Node and all child Nodes and {@link Mesh}es cast shadows. * * @type {Boolean} */ - get targetVisible() { - return this._targetVisible; + set castsShadow(castsShadow) { + castsShadow = !!castsShadow; + this._castsShadow = castsShadow; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].castsShadow = castsShadow; + } } /** - * Sets if the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} are visible. + * Gets if this Node casts shadows. + * + * Child Nodes and {@link Mesh}es may have different values for this property. * * @type {Boolean} */ - set axisVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; - this._axisVisible = value; - var axisVisible = this._visible && this._axisVisible; - this._xAxisWire.setVisible(axisVisible); - this._yAxisWire.setVisible(axisVisible); - this._zAxisWire.setVisible(axisVisible); - this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled); - this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled); - this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled); + get castsShadow() { + return this._castsShadow; } /** - * Gets if the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} are visible. + * Sets if this Node and all child Nodes and {@link Mesh}es can have shadows cast upon them. * * @type {Boolean} */ - get axisVisible() { - return this._axisVisible; + set receivesShadow(receivesShadow) { + receivesShadow = !!receivesShadow; + this._receivesShadow = receivesShadow; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].receivesShadow = receivesShadow; + } } /** - * Sets if the direct point-to-point wire between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} is visible. + * Whether or not to this Node can have shadows cast upon it. + * + * Child Nodes and {@link Mesh}es may have different values for this property. * * @type {Boolean} */ - set wireVisible(value) { - value = value !== undefined ? Boolean(value) : this.plugin.defaultWireVisible; - this._wireVisible = value; - var wireVisible = this._visible && this._wireVisible; - this._lengthLabel.setVisible(wireVisible); - this._lengthWire.setVisible(wireVisible); + get receivesShadow() { + return this._receivesShadow; } /** - * Gets if the direct point-to-point wire between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} is visible. + * Gets if this Node can have Scalable Ambient Obscurance (SAO) applied to it. + * + * SAO is configured by {@link SAO}. * * @type {Boolean} + * @abstract */ - get wireVisible() { - return this._wireVisible; + get saoEnabled() { + return false; // TODO: Support SAO on Nodes } + /** - * @private + * Sets the 3D World-space offset for this Node and all child Nodes and {@link Mesh}es}. + * + * The offset dynamically translates those components in World-space. + * + * Default value is ````[0, 0, 0]````. + * + * Note that child Nodes and {@link Mesh}es may subsequently be given different values for this property. + * + * @type {Number[]} */ - destroy() { - - const scene = this.plugin.viewer.scene; - const metrics = scene.metrics; - - if (this._onViewMatrix) { - scene.camera.off(this._onViewMatrix); - } - if (this._onProjMatrix) { - scene.camera.off(this._onProjMatrix); - } - if (this._onCanvasBoundary) { - scene.canvas.off(this._onCanvasBoundary); - } - - if (this._onMetricsUnits) { - metrics.off(this._onMetricsUnits); + set offset(offset) { + if (offset) { + this._offset[0] = offset[0]; + this._offset[1] = offset[1]; + this._offset[2] = offset[2]; + } else { + this._offset[0] = 0; + this._offset[1] = 0; + this._offset[2] = 0; } - if (this._onMetricsScale) { - metrics.off(this._onMetricsScale); + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i].offset = this._offset; } - if (this._onMetricsOrigin) { - metrics.off(this._onMetricsOrigin); + if (this._isObject) { + this.scene._objectOffsetUpdated(this, offset); } - - this._originDot.destroy(); - this._targetDot.destroy(); - this._xAxisWire.destroy(); - this._yAxisWire.destroy(); - this._zAxisWire.destroy(); - this._lengthLabel.destroy(); - this._xAxisLabel.destroy(); - this._yAxisLabel.destroy(); - this._zAxisLabel.destroy(); - this._lengthWire.destroy(); - - super.destroy(); } -} - -/** - * Creates {@link DistanceMeasurement}s from mouse and touch input. - * - * Belongs to a {@link DistanceMeasurementsPlugin}. Located at {@link DistanceMeasurementsPlugin#control}. - * - * Once the DistanceMeasurementControl is activated, the first click on any {@link Entity} begins constructing a {@link DistanceMeasurement}, fixing its origin to that Entity. The next click on any Entity will complete the DistanceMeasurement, fixing its target to that second Entity. The DistanceMeasurementControl will then wait for the next click on any Entity, to begin constructing another DistanceMeasurement, and so on, until deactivated. - * - * See {@link DistanceMeasurementsPlugin} for more info. - */ -class DistanceMeasurementsControl extends Component { /** - * @private + * Gets the Node's 3D World-space offset. + * + * Default value is ````[0, 0, 0]````. + * + * Child Nodes and {@link Mesh}es may have different values for this property. + * + * @type {Number[]} */ - constructor(plugin) { - - super(plugin.viewer.scene); - - /** - * The {@link DistanceMeasurementsPlugin} that owns this DistanceMeasurementsControl. - * @type {DistanceMeasurementsPlugin} - */ - this.plugin = plugin; - - this._active = false; - - this._currentDistMeasurement = null; - // Keep initial measurement state values to do not force values but put the default ones. - this._currentDistMeasurementInitState = { - wireVisible: null, - axisVisible: null, - targetVisible: null, - }; + get offset() { + return this._offset; + } - this._onHoverSurface = null; - this._onHoverOff = null; - this._onPickedNothing = null; - this._onInputMouseDown = null; - this._onInputMouseUp = null; - } + //------------------------------------------------------------------------------------------------------------------ + // Node members + //------------------------------------------------------------------------------------------------------------------ - /** Gets if this DistanceMeasurementsControl is currently active, where it is responding to input. - * - * @returns {boolean} + /** + * Returns true to indicate that this Component is a Node. + * @type {Boolean} */ - get active() { - return this._active; + get isNode() { + return true; } - /** - * Activates this DistanceMeasurementsControl, ready to respond to input. - */ - activate() { + _setLocalMatrixDirty() { + this._localMatrixDirty = true; + this._setWorldMatrixDirty(); + } - if (this._active) { - return; + _setWorldMatrixDirty() { + this._worldMatrixDirty = true; + for (let i = 0, len = this._children.length; i < len; i++) { + this._children[i]._setWorldMatrixDirty(); } + } - const cameraControl = this.plugin.viewer.cameraControl; - - let hoveredEntity = null; - const worldPos = math.vec3(); - const hoverCanvasPos = math.vec2(); - - const pickSurfacePrecisionEnabled = this.plugin.viewer.scene.pickSurfacePrecisionEnabled; - - this.startDot = new Dot(this.plugin._container, - { - fillColor: this.plugin.defaultColor, - zIndex: this.plugin.zIndex + 1 - }); - - this._onHoverSurface = cameraControl.on("hoverSurface", e => { - - hoveredEntity = e.entity; - worldPos.set(e.worldPos); - hoverCanvasPos.set(e.canvasPos); - - this.plugin.viewer.scene.canvas.canvas.style.cursor = "pointer"; - - if (this._currentDistMeasurement) { - this._currentDistMeasurement.wireVisible = this._currentDistMeasurementInitState.wireVisible; - this._currentDistMeasurement.axisVisible = this._currentDistMeasurementInitState.axisVisible; - this._currentDistMeasurement.targetVisible = this._currentDistMeasurementInitState.targetVisible; - this._currentDistMeasurement.target.entity = hoveredEntity; - this._currentDistMeasurement.target.worldPos = worldPos; - } else if (this.startDot) { - this.startDot.setVisible(true); - this.startDot.setPos(e.canvasPos[0], e.canvasPos[1]); + _buildWorldMatrix() { + const localMatrix = this.matrix; + if (!this._parentNode) { + for (let i = 0, len = localMatrix.length; i < len; i++) { + this._worldMatrix[i] = localMatrix[i]; } - }); - - let lastX; - let lastY; - const tolerance = 5; - - this._onInputMouseDown = this.plugin.viewer.scene.input.on("mousedown", (coords) => { - lastX = coords[0]; - lastY = coords[1]; - }); - - this._onInputMouseUp = this.plugin.viewer.scene.input.on("mouseup", (coords) => { + } else { + math.mulMat4(this._parentNode.worldMatrix, localMatrix, this._worldMatrix); + } + this._worldMatrixDirty = false; + } - if (coords[0] > lastX + tolerance || coords[0] < lastX - tolerance || coords[1] > lastY + tolerance || coords[1] < lastY - tolerance) { - return; + _setSubtreeAABBsDirty(node) { + node._aabbDirty = true; + if (node._children) { + for (let i = 0, len = node._children.length; i < len; i++) { + this._setSubtreeAABBsDirty(node._children[i]); } + } + } - if (this.startDot) { - this.startDot.destroy(); - this.startDot = null; + _setAABBDirty() { + this._setSubtreeAABBsDirty(this); + if (this.collidable) { + for (let node = this; node; node = node._parentNode) { + node._aabbDirty = true; } + } + } - if (this._currentDistMeasurement) { - if (hoveredEntity) { - if (pickSurfacePrecisionEnabled) { - const pickResult = this.plugin.viewer.scene.pick({ - canvasPos: hoverCanvasPos, - pickSurface: true, - pickSurfacePrecision: true - }); - if (pickResult && pickResult.worldPos) { - this._currentDistMeasurement.target.worldPos = pickResult.worldPos; - } - this._currentDistMeasurement.approximate = false; - } - - this.fire("measurementEnd", this._currentDistMeasurement); - this._currentDistMeasurement = null; - } else { - this._currentDistMeasurement.destroy(); - this.fire("measurementCancel", this._currentDistMeasurement); - this._currentDistMeasurement = null; - } - } else { - if (hoveredEntity) { - if (pickSurfacePrecisionEnabled) { - const pickResult = this.plugin.viewer.scene.pick({ - canvasPos: hoverCanvasPos, - pickSurface: true, - pickSurfacePrecision: true - }); - if (pickResult && pickResult.worldPos) { - worldPos.set(pickResult.worldPos); - } - } - this._currentDistMeasurement = this.plugin.createMeasurement({ - id: math.createUUID(), - origin: { - entity: hoveredEntity, - worldPos: worldPos - }, - target: { - entity: hoveredEntity, - worldPos: worldPos - }, - approximate: true - }); - - this._currentDistMeasurementInitState.axisVisible = this._currentDistMeasurement.axisVisible; - this._currentDistMeasurementInitState.wireVisible = this._currentDistMeasurement.wireVisible; - this._currentDistMeasurementInitState.targetVisible = this._currentDistMeasurement.targetVisible; - - this.fire("measurementStart", this._currentDistMeasurement); + _updateAABB() { + this.scene._aabbDirty = true; + if (!this._aabb) { + this._aabb = math.AABB3(); + } + if (this._buildAABB) { + this._buildAABB(this.worldMatrix, this._aabb); // Mesh or VBOSceneModel + } else { // Node | Node | Model + math.collapseAABB3(this._aabb); + let node; + for (let i = 0, len = this._children.length; i < len; i++) { + node = this._children[i]; + if (!node.collidable) { + continue; } + math.expandAABB3(this._aabb, node.aabb); } - }); + } + this._aabbDirty = false; + } - this._onHoverOff = cameraControl.on("hoverOff", e => { - if (this.startDot) { - this.startDot.setVisible(false); + /** + * Adds a child Node or {@link Mesh}. + * + * The child must be a Node or {@link Mesh} in the same {@link Scene}. + * + * If the child already has a parent, will be removed from that parent first. + * + * Does nothing if already a child. + * + * @param {Node|Mesh|String} child Instance or ID of the child to add. + * @param [inheritStates=false] Indicates if the child should inherit rendering states from this parent as it is added. Rendering state includes {@link Node#visible}, {@link Node#culled}, {@link Node#pickable}, {@link Node#clippable}, {@link Node#castsShadow}, {@link Node#receivesShadow}, {@link Node#selected}, {@link Node#highlighted}, {@link Node#colorize} and {@link Node#opacity}. + * @returns {Node|Mesh} The child. + */ + addChild(child, inheritStates) { + if (utils.isNumeric(child) || utils.isString(child)) { + const nodeId = child; + child = this.scene.component[nodeId]; + if (!child) { + this.warn("Component not found: " + utils.inQuotes(nodeId)); + return; } - hoveredEntity = null; - if (this._currentDistMeasurement) { - this._currentDistMeasurement.wireVisible = false; - this._currentDistMeasurement.targetVisible = false; - this._currentDistMeasurement.axisVisible = false; + if (!child.isNode && !child.isMesh) { + this.error("Not a Node or Mesh: " + nodeId); + return; } - this.plugin.viewer.scene.canvas.canvas.style.cursor = "default"; - }); - - this._onPickedNothing = cameraControl.on("pickedNothing", e => { - if (this._currentDistMeasurement) { - this._currentDistMeasurement.destroy(); - this._currentDistMeasurement = null; + } else { + if (!child.isNode && !child.isMesh) { + this.error("Not a Node or Mesh: " + child.id); + return; } - }); - - //------------------------------------------------------------------------------------------------------------- - - // const canvas = this.scene.canvas.canvas; - // const tapStartCanvasPos = math.vec2(); - // const tapCanvasPos0 = math.vec2(); - // const tapCanvasPos1 = math.vec2(); - // const touch0Vec = math.vec2(); - // const lastCanvasTouchPosList = []; - // let numTouches = 0; - // let waitForTick = false; - // - // this._onTick = scene.on("tick", () => { - // waitForTick = false; - // }); - // - // canvas.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => { - // event.preventDefault(); - // const touches = event.touches; - // const changedTouches = event.changedTouches; - // if (touches.length === 1 && changedTouches.length === 1) { - // getCanvasPosFromEvent(touches[0], tapStartCanvasPos); - // - // if (pickSurfacePrecisionEnabled) { - // const pickResult = this.plugin.viewer.scene.pick({ - // canvasPos: tapStartCanvasPos, - // pickSurface: true, - // // pickSurfacePrecision: true - // }); - // if (pickResult && pickResult.worldPos) { - // // this._currentDistMeasurement.target.worldPos = pickResult.worldPos; - // } - // // this._currentDistMeasurement.approximate = false; - // } - // - // // TODO: Create start of measurement - // } - // while (lastCanvasTouchPosList.length < touches.length) { - // lastCanvasTouchPosList.push(math.vec2()); - // } - // for (let i = 0, len = touches.length; i < len; ++i) { - // getCanvasPosFromEvent(touches[i], lastCanvasTouchPosList[i]); - // } - // numTouches = touches.length; - // }); - // - // canvas.addEventListener("touchmove", this._canvasTouchMoveHandler = (event) => { - // event.stopPropagation(); - // event.preventDefault(); - // if (waitForTick) { // Limit changes detection to one per frame - // return; - // } - // waitForTick = true; - // const touches = event.touches; - // if (event.touches.length !== numTouches) { - // // Two fingers were pressed, then one of them is removed - // return; - // } - // if (numTouches === 1) { - // getCanvasPosFromEvent(touches[0], tapCanvasPos0); - // // TODO: update end of distance measurement - // } - // for (let i = 0; i < numTouches; ++i) { - // getCanvasPosFromEvent(touches[i], lastCanvasTouchPosList[i]); - // } - // }); - - //------------------------------------------------------------------------------------------------------------- - - this._active = true; + if (child._parentNode) { + if (child._parentNode.id === this.id) { + this.warn("Already a child: " + child.id); + return; + } + child._parentNode.removeChild(child); + } + } + child.id; + if (child.scene.id !== this.scene.id) { + this.error("Child not in same Scene: " + child.id); + return; + } + this._children.push(child); + child._parentNode = this; + if (!!inheritStates) { + child.visible = this.visible; + child.culled = this.culled; + child.xrayed = this.xrayed; + child.highlited = this.highlighted; + child.selected = this.selected; + child.edges = this.edges; + child.clippable = this.clippable; + child.pickable = this.pickable; + child.collidable = this.collidable; + child.castsShadow = this.castsShadow; + child.receivesShadow = this.receivesShadow; + child.colorize = this.colorize; + child.opacity = this.opacity; + child.offset = this.offset; + } + child._setWorldMatrixDirty(); + child._setAABBDirty(); + this._numTriangles += child.numTriangles; + return child; } /** - * Deactivates this DistanceMeasurementsControl, making it unresponsive to input. + * Removes the given child Node or {@link Mesh}. * - * Destroys any {@link DistanceMeasurement} under construction. + * @param {Node|Mesh} child Child to remove. */ - deactivate() { - - if (!this._active) { - return; + removeChild(child) { + for (let i = 0, len = this._children.length; i < len; i++) { + if (this._children[i].id === child.id) { + child._parentNode = null; + this._children = this._children.splice(i, 1); + child._setWorldMatrixDirty(); + child._setAABBDirty(); + this._setAABBDirty(); + this._numTriangles -= child.numTriangles; + return; + } } + } - if (this.startDot) { - this.startDot.destroy(); - this.startDot = null; + /** + * Removes all child Nodes and {@link Mesh}es. + */ + removeChildren() { + let child; + for (let i = 0, len = this._children.length; i < len; i++) { + child = this._children[i]; + child._parentNode = null; + child._setWorldMatrixDirty(); + child._setAABBDirty(); + this._numTriangles -= child.numTriangles; } + this._children = []; + this._setAABBDirty(); + } - this.reset(); - - const input = this.plugin.viewer.scene.input; - - input.off(this._onInputMouseDown); - input.off(this._onInputMouseUp); - - const cameraControl = this.plugin.viewer.cameraControl; - - cameraControl.off(this._onHoverSurface); - cameraControl.off(this._onHoverOff); - cameraControl.off(this._onPickedNothing); - - this._currentDistMeasurement = null; + /** + * Number of child Nodes or {@link Mesh}es. + * + * @type {Number} + */ + get numChildren() { + return this._children.length; + } - this._active = false; + /** + * Array of child Nodes or {@link Mesh}es. + * + * @type {Array} + */ + get children() { + return this._children; } /** - * Resets this DistanceMeasurementsControl. + * The parent Node. * - * Destroys any {@link DistanceMeasurement} under construction. + * The parent Node may also be set by passing the Node to the parent's {@link Node#addChild} method. * - * Does nothing if the DistanceMeasurementsControl is not active. + * @type {Node} */ - reset() { - - if (!this._active) { + set parent(node) { + if (utils.isNumeric(node) || utils.isString(node)) { + const nodeId = node; + node = this.scene.components[nodeId]; + if (!node) { + this.warn("Node not found: " + utils.inQuotes(nodeId)); + return; + } + if (!node.isNode) { + this.error("Not a Node: " + node.id); + return; + } + } + if (node.scene.id !== this.scene.id) { + this.error("Node not in same Scene: " + node.id); return; } - - if (this._currentDistMeasurement) { - this._currentDistMeasurement.destroy(); - this._currentDistMeasurement = null; + if (this._parentNode && this._parentNode.id === node.id) { + this.warn("Already a child of Node: " + node.id); + return; } + node.addChild(this); } /** - * @private + * The parent Node. + * + * @type {Node} */ - destroy() { - this.deactivate(); - super.destroy(); + get parent() { + return this._parentNode; } -} - -/** - * {@link Viewer} plugin for measuring point-to-point distances. - * - * [](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_createWithMouse) - * - * * [[Example 1: Model with distance measurements](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_modelWithMeasurements)] - * * [[Example 2: Create distance measurements with mouse](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_createWithMouse)] - * * [[Example 3: Configuring units and scale](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_unitsAndScale)] - * - * ## Overview - * - * * A {@link DistanceMeasurement} represents a point-to-point measurement between two 3D points on one or two {@link Entity}s. - * * As shown on the screen capture above, a DistanceMeasurement has one wire (light blue) that shows the direct point-to-point measurement, - * and three more wires (red, green and blue) that show the distance on each of the World-space X, Y and Z axis. - * * Create DistanceMeasurements programmatically with {@link DistanceMeasurementsPlugin#createMeasurement}. - * * Create DistanceMeasurements interactively using the {@link DistanceMeasurementsControl}, located at {@link DistanceMeasurementsPlugin#control}. - * * Existing DistanceMeasurements are registered by ID in {@link DistanceMeasurementsPlugin#measurements}. - * * Destroy DistanceMeasurements using {@link DistanceMeasurementsPlugin#destroyMeasurement}. - * * Configure global measurement units and scale via {@link Metrics}, located at {@link Scene#metrics}. - * - * ## Example 1: Creating DistanceMeasurements Programmatically - * - * In our first example, we'll use an {@link XKTLoaderPlugin} to load a model, and then use a DistanceMeasurementsPlugin to programmatically create two {@link DistanceMeasurement}s. - * - * Note how each DistanceMeasurement has ````origin```` and ````target```` endpoints, which each indicate a 3D World-space - * position on the surface of an {@link Entity}. The endpoints can be attached to the same Entity, or to different Entitys. - * - * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_modelWithMeasurements)] - * - * ````JavaScript - * import {Viewer, XKTLoaderPlugin, DistanceMeasurementsPlugin} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-2.37, 18.97, -26.12]; - * viewer.scene.camera.look = [10.97, 5.82, -11.22]; - * viewer.scene.camera.up = [0.36, 0.83, 0.40]; - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const distanceMeasurements = new DistanceMeasurementsPlugin(viewer); - * - * const model = xktLoader.load({ - * src: "./models/xkt/duplex/duplex.xkt" - * }); - * - * model.on("loaded", () => { - * - * const myMeasurement1 = distanceMeasurements.createMeasurement({ - * id: "distanceMeasurement1", - * origin: { - * entity: viewer.scene.objects["2O2Fr$t4X7Zf8NOew3FLOH"], - * worldPos: [0.044, 5.998, 17.767] - * }, - * target: { - * entity: viewer.scene.objects["2O2Fr$t4X7Zf8NOew3FLOH"], - * worldPos: [4.738, 3.172, 17.768] - * }, - * visible: true, - * wireVisible: true - * }); - * - * const myMeasurement2 = distanceMeasurements.createMeasurement({ - * id: "distanceMeasurement2", - * origin: { - * entity: viewer.scene.objects["2O2Fr$t4X7Zf8NOew3FNr2"], - * worldPos: [0.457, 2.532, 17.766] - * }, - * target: { - * entity: viewer.scene.objects["1CZILmCaHETO8tf3SgGEXu"], - * worldPos: [0.436, 0.001, 22.135] - * }, - * visible: true, - * wireVisible: true - * }); - * }); - * ```` - * - * ## Example 2: Creating DistanceMeasurements Interactively - * - * In our second example, we'll use an {@link XKTLoaderPlugin} to load a model, then we'll use the DistanceMeasurementPlugin's {@link DistanceMeasurementsControl} to interactively create {@link DistanceMeasurement}s with mouse or touch input. - * - * After we've activated the DistanceMeasurementsControl, the first click on any {@link Entity} begins constructing a DistanceMeasurement, fixing its - * origin to that Entity. The next click on any Entity will complete the DistanceMeasurement, fixing its target to that second Entity. - * - * The DistanceMeasurementControl will then wait for the next click on any Entity, to begin constructing - * another DistanceMeasurement, and so on, until deactivated again. - * - * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_createWithMouse)] - * - * ````JavaScript - * import {Viewer, XKTLoaderPlugin, DistanceMeasurementsPlugin} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-2.37, 18.97, -26.12]; - * viewer.scene.camera.look = [10.97, 5.82, -11.22]; - * viewer.scene.camera.up = [0.36, 0.83, 0.40]; - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const distanceMeasurements = new DistanceMeasurementsPlugin(viewer); - * - * const model = xktLoader.load({ - * src: "./models/xkt/duplex/duplex.xkt" - * }); - * - * distanceMeasurements.control.activate(); // <------------ Activate the DistanceMeasurementsControl - * ```` - * - * ## Example 3: Configuring Measurement Units and Scale - * - * In our third example, we'll use the {@link Scene}'s {@link Metrics} to set the global unit of measurement to ````"meters"````. We'll also specify that a unit within the World-space coordinate system represents ten meters. - * - * The wires belonging to our DistanceMeasurements show their lengths in Real-space coordinates, in the current unit of measurement. They will dynamically update as we set these configurations. - * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_unitsAndScale)] - * - * ````JavaScript - * const metrics = viewer.scene.metrics; - - * metrics.units = "meters"; - * metrics.scale = 10.0; - * ```` - */ -class DistanceMeasurementsPlugin extends Plugin { + /** + * Sets the Node's local translation. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + */ + set position(value) { + this._position.set(value || [0, 0, 0]); + this._setLocalMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + } /** - * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} [cfg] Plugin configuration. - * @param {String} [cfg.id="DistanceMeasurements"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Number} [cfg.labelMinAxisLength=25] The minimum length, in pixels, of an axis wire beyond which its label is shown. - * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````. - * @param {boolean} [cfg.defaultVisible=true] The default value of the DistanceMeasurements `visible` property. - * @param {boolean} [cfg.defaultOriginVisible=true] The default value of the DistanceMeasurements `originVisible` property. - * @param {boolean} [cfg.defaultTargetVisible=true] The default value of the DistanceMeasurements `targetVisible` property. - * @param {boolean} [cfg.defaultWireVisible=true] The default value of the DistanceMeasurements `wireVisible` property. - * @param {boolean} [cfg.defaultAxisVisible=true] The default value of the DistanceMeasurements `axisVisible` property. - * @param {string} [cfg.defaultColor=#00BBFF] The default color of the length dots, wire and label. - * @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels). + * Gets the Node's local translation. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} */ - constructor(viewer, cfg = {}) { + get position() { + return this._position; + } - super("DistanceMeasurements", viewer); + /** + * Sets the Node's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + */ + set rotation(value) { + this._rotation.set(value || [0, 0, 0]); + math.eulerToQuaternion(this._rotation, "XYZ", this._quaternion); + this._setLocalMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + } - this._container = cfg.container || document.body; + /** + * Gets the Node's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + */ + get rotation() { + return this._rotation; + } - this._control = new DistanceMeasurementsControl(this); + /** + * Sets the Node's local rotation quaternion. + * + * Default value is ````[0,0,0,1]````. + * + * @type {Number[]} + */ + set quaternion(value) { + this._quaternion.set(value || [0, 0, 0, 1]); + math.quaternionToEuler(this._quaternion, "XYZ", this._rotation); + this._setLocalMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + } - this._measurements = {}; + /** + * Gets the Node's local rotation quaternion. + * + * Default value is ````[0,0,0,1]````. + * + * @type {Number[]} + */ + get quaternion() { + return this._quaternion; + } - this.labelMinAxisLength = cfg.labelMinAxisLength; + /** + * Sets the Node's local scale. + * + * Default value is ````[1,1,1]````. + * + * @type {Number[]} + */ + set scale(value) { + this._scale.set(value || [1, 1, 1]); + this._setLocalMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + } - this.defaultVisible = cfg.defaultVisible !== false; - this.defaultOriginVisible = cfg.defaultOriginVisible !== false; - this.defaultTargetVisible = cfg.defaultTargetVisible !== false; - this.defaultWireVisible = cfg.defaultWireVisible !== false; - this.defaultAxisVisible = cfg.defaultAxisVisible !== false; - this.defaultColor = cfg.defaultColor !== undefined ? cfg.defaultColor : "#00BBFF"; - this.zIndex = cfg.zIndex; + /** + * Gets the Node's local scale. + * + * Default value is ````[1,1,1]````. + * + * @type {Number[]} + */ + get scale() { + return this._scale; } /** - * @private + * Sets the Node's local modeling transform matrix. + * + * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. + * + * @type {Number[]} */ - send(name, value) { + set matrix(value) { + if (!this._localMatrix) { + this._localMatrix = math.identityMat4(); + } + this._localMatrix.set(value || identityMat); + math.decomposeMat4(this._localMatrix, this._position, this._quaternion, this._scale); + this._localMatrixDirty = false; + this._setWorldMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + } + /** + * Gets the Node's local modeling transform matrix. + * + * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. + * + * @type {Number[]} + */ + get matrix() { + if (this._localMatrixDirty) { + if (!this._localMatrix) { + this._localMatrix = math.identityMat4(); + } + math.composeMat4(this._position, this._quaternion, this._scale, this._localMatrix); + this._localMatrixDirty = false; + } + return this._localMatrix; } /** - * Gets the {@link DistanceMeasurementsControl}, which creates {@link DistanceMeasurement}s from user input. + * Gets the Node's World matrix. * - * @type {DistanceMeasurementsControl} + * @property worldMatrix + * @type {Number[]} */ - get control() { - return this._control; + get worldMatrix() { + if (this._worldMatrixDirty) { + this._buildWorldMatrix(); + } + return this._worldMatrix; } /** - * Gets the existing {@link DistanceMeasurement}s, each mapped to its {@link DistanceMeasurement#id}. + * Rotates the Node about the given local axis by the given increment. * - * @type {{String:DistanceMeasurement}} + * @param {Number[]} axis Local axis about which to rotate. + * @param {Number} angle Angle increment in degrees. */ - get measurements() { - return this._measurements; + rotate(axis, angle) { + angleAxis[0] = axis[0]; + angleAxis[1] = axis[1]; + angleAxis[2] = axis[2]; + angleAxis[3] = angle * math.DEGTORAD; + math.angleAxisToQuaternion(angleAxis, q1); + math.mulQuaternions(this.quaternion, q1, q2); + this.quaternion = q2; + this._setLocalMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + return this; } /** - * Sets the minimum length, in pixels, of an axis wire beyond which its label is shown. + * Rotates the Node about the given World-space axis by the given increment. * - * The axis wire's label is not shown when its length is less than this value. + * @param {Number[]} axis Local axis about which to rotate. + * @param {Number} angle Angle increment in degrees. + */ + rotateOnWorldAxis(axis, angle) { + angleAxis[0] = axis[0]; + angleAxis[1] = axis[1]; + angleAxis[2] = axis[2]; + angleAxis[3] = angle * math.DEGTORAD; + math.angleAxisToQuaternion(angleAxis, q1); + math.mulQuaternions(q1, this.quaternion, q1); + //this.quaternion.premultiply(q1); + return this; + } + + /** + * Rotates the Node about the local X-axis by the given increment. * - * This is ````25```` pixels by default. + * @param {Number} angle Angle increment in degrees. + */ + rotateX(angle) { + return this.rotate(xAxis, angle); + } + + /** + * Rotates the Node about the local Y-axis by the given increment. * - * Must not be less than ````1````. + * @param {Number} angle Angle increment in degrees. + */ + rotateY(angle) { + return this.rotate(yAxis, angle); + } + + /** + * Rotates the Node about the local Z-axis by the given increment. * - * @type {number} + * @param {Number} angle Angle increment in degrees. */ - set labelMinAxisLength(labelMinAxisLength) { - if (labelMinAxisLength < 1) { - this.error("labelMinAxisLength must be >= 1; defaulting to 25"); - labelMinAxisLength = 25; - } - this._labelMinAxisLength = labelMinAxisLength || 25; + rotateZ(angle) { + return this.rotate(zAxis, angle); } /** - * Gets the minimum length, in pixels, of an axis wire beyond which its label is shown. - * @returns {number} + * Translates the Node along local space vector by the given increment. + * + * @param {Number[]} axis Normalized local space 3D vector along which to translate. + * @param {Number} distance Distance to translate along the vector. */ - get labelMinAxisLength() { - return this._labelMinAxisLength; + translate(axis, distance) { + math.vec3ApplyQuaternion(this.quaternion, axis, veca); + math.mulVec3Scalar(veca, distance, vecb); + math.addVec3(this.position, vecb, this.position); + this._setLocalMatrixDirty(); + this._setAABBDirty(); + this.glRedraw(); + return this; } /** - * Creates a {@link DistanceMeasurement}. + * Translates the Node along the local X-axis by the given increment. * - * The DistanceMeasurement is then registered by {@link DistanceMeasurement#id} in {@link DistanceMeasurementsPlugin#measurements}. + * @param {Number} distance Distance to translate along the X-axis. + */ + translateX(distance) { + return this.translate(xAxis, distance); + } + + /** + * Translates the Node along the local Y-axis by the given increment. * - * @param {Object} params {@link DistanceMeasurement} configuration. - * @param {String} params.id Unique ID to assign to {@link DistanceMeasurement#id}. The DistanceMeasurement will be registered by this in {@link DistanceMeasurementsPlugin#measurements} and {@link Scene.components}. Must be unique among all components in the {@link Viewer}. - * @param {Number[]} params.origin.worldPos Origin World-space 3D position. - * @param {Entity} params.origin.entity Origin Entity. - * @param {Number[]} params.target.worldPos Target World-space 3D position. - * @param {Entity} params.target.entity Target Entity. - * @param {Boolean} [params.visible=true] Whether to initially show the {@link DistanceMeasurement}. - * @param {Boolean} [params.originVisible=true] Whether to initially show the {@link DistanceMeasurement} origin. - * @param {Boolean} [params.targetVisible=true] Whether to initially show the {@link DistanceMeasurement} target. - * @param {Boolean} [params.wireVisible=true] Whether to initially show the direct point-to-point wire between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target}. - * @param {Boolean} [params.axisVisible=true] Whether to initially show the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target}. - * @param {string} [params.color] The color of the length dot, wire and label. - * @returns {DistanceMeasurement} The new {@link DistanceMeasurement}. + * @param {Number} distance Distance to translate along the Y-axis. */ - createMeasurement(params = {}) { - if (this.viewer.scene.components[params.id]) { - this.error("Viewer scene component with this ID already exists: " + params.id); - delete params.id; - } - const origin = params.origin; - const target = params.target; - const measurement = new DistanceMeasurement(this, { - id: params.id, - plugin: this, - container: this._container, - origin: { - entity: origin.entity, - worldPos: origin.worldPos - }, - target: { - entity: target.entity, - worldPos: target.worldPos - }, - visible: params.visible, - wireVisible: params.wireVisible, - originVisible: params.originVisible, - targetVisible: params.targetVisible, - color: params.color - }); - this._measurements[measurement.id] = measurement; - measurement.on("destroyed", () => { - delete this._measurements[measurement.id]; - }); - this.fire("measurementCreated", measurement); - return measurement; + translateY(distance) { + return this.translate(yAxis, distance); } /** - * Destroys a {@link DistanceMeasurement}. + * Translates the Node along the local Z-axis by the given increment. * - * @param {String} id ID of DistanceMeasurement to destroy. + * @param {Number} distance Distance to translate along the Z-axis. */ - destroyMeasurement(id) { - const measurement = this._measurements[id]; - if (!measurement) { - this.log("DistanceMeasurement not found: " + id); - return; - } - measurement.destroy(); - this.fire("measurementDestroyed", measurement); + translateZ(distance) { + return this.translate(zAxis, distance); } + //------------------------------------------------------------------------------------------------------------------ + // Component members + //------------------------------------------------------------------------------------------------------------------ + /** - * Destroys all {@link DistanceMeasurement}s. + @private */ - clear() { - const ids = Object.keys(this._measurements); - for (var i = 0, len = ids.length; i < len; i++) { - this.destroyMeasurement(ids[i]); - } + get type() { + return "Node"; } /** - * Destroys this DistanceMeasurementsPlugin. - * - * Destroys all {@link DistanceMeasurement}s first. + * Destroys this Node. */ destroy() { - this.clear(); super.destroy(); + if (this._parentNode) { + this._parentNode.removeChild(this); + } + if (this._isObject) { + this.scene._deregisterObject(this); + if (this._visible) { + this.scene._objectVisibilityUpdated(this, false); + } + if (this._xrayed) { + this.scene._objectXRayedUpdated(this, false); + } + if (this._selected) { + this.scene._objectSelectedUpdated(this, false); + } + if (this._highlighted) { + this.scene._objectHighlightedUpdated(this, false); + } + this.scene._objectColorizeUpdated(this, false); + this.scene._objectOpacityUpdated(this, false); + this.scene._objectOffsetUpdated(this, false); + } + if (this._isModel) { + this.scene._deregisterModel(this); + } + if (this._children.length) { + // Clone the _children before iterating, so our children don't mess us up when calling removeChild(). + const tempChildList = this._children.splice(); + let child; + for (let i = 0, len = tempChildList.length; i < len; i++) { + child = tempChildList[i]; + child.destroy(); + } + } + this._children = []; + this._setAABBDirty(); + this.scene._aabbDirty = true; } + } /** - * {@link Viewer} plugin that makes interaction smoother with large models, by temporarily switching - * the Viewer to faster, lower-quality rendering modes whenever we interact. - * - * [](https://xeokit.github.io/xeokit-sdk/examples/#performance_FastNavPlugin) - * - * FastNavPlugin works by hiding specified Viewer rendering features, and optionally scaling the Viewer's canvas - * resolution, whenever we interact with the Viewer. Then, once we've finished interacting, FastNavPlugin restores those - * rendering features and the original canvas scale, after a configured delay. - * - * Depending on how we configure FastNavPlugin, we essentially switch to a smooth-rendering low-quality view while - * interacting, then return to the normal higher-quality view after we stop, following an optional delay. - * - * Down-scaling the canvas resolution gives particularly good results. For example, scaling by ````0.5```` means that - * we're rendering a quarter of the pixels while interacting, which can make the Viewer noticeably smoother with big models. - * - * The screen capture above shows FastNavPlugin in action. In this example, whenever we move the Camera or resize the Canvas, - * FastNavPlugin switches off enhanced edges and ambient shadows (SAO), and down-scales the canvas, making it slightly - * blurry. When ````0.5```` seconds passes with no interaction, the plugin shows edges and SAO again, and restores the - * original canvas scale. - * - * # Usage - * - * In the example below, we'll create a {@link Viewer}, add a {@link FastNavPlugin}, then use an {@link XKTLoaderPlugin} to load a model. - * - * Whenever we interact with the Viewer, our FastNavPlugin will: + * @desc Configures the normal rendered appearance of {@link Mesh}es using the non-realistic but GPU-efficient Lambertian flat shading model for calculating reflectance. * - * * hide edges, - * * hide ambient shadows (SAO), - * * hide physically-based materials (switching to non-PBR), - * * hide transparent objects, and - * * scale the canvas resolution by 0.5, causing the GPU to render 75% less pixels. - *
+ * * Useful for efficiently rendering non-realistic objects for high-detail CAD. + * * Use {@link PhongMaterial} when you need specular highlights. + * * Use the physically-based {@link MetallicMaterial} or {@link SpecularMaterial} when you need more realism. + * * For LambertMaterial, the illumination calculation is performed at each triangle vertex, and the resulting color is interpolated across the face of the triangle. For {@link PhongMaterial}, {@link MetallicMaterial} and + * {@link SpecularMaterial}, vertex normals are interpolated across the surface of the triangle, and the illumination calculation is performed at each texel. * - * We'll also configure a 0.5 second delay before we transition back to high-quality each time we stop ineracting, so that we're - * not continually flipping between low and high quality as we interact. Since we're only rendering ambient shadows when not interacting, we'll also treat ourselves - * to expensive, high-quality SAO settings, that we wouldn't normally configure for an interactive SAO effect. + * ## Usage * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#performance_FastNavPlugin)] + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_LambertMaterial)] * - * ````javascript - * import {Viewer, XKTLoaderPlugin, FastNavPlugin} from "xeokit-sdk.es.js"; + * In the example below we'll create a {@link Mesh} with a shape defined by a {@link buildTorusGeometry} and normal rendering appearance configured with a LambertMaterial. * - * // Create a Viewer with PBR and SAO enabled + * ```` javascript + * import {Viewer, Mesh, buildTorusGeometry, ReadableGeometry, LambertMaterial} from "xeokit-sdk.es.js"; * * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true, - * pbr: true, // Enable physically-based rendering for Viewer - * sao: true // Enable ambient shadows for Viewer - * }); - * - * viewer.scene.camera.eye = [-66.26, 105.84, -281.92]; - * viewer.scene.camera.look = [42.45, 49.62, -43.59]; - * viewer.scene.camera.up = [0.05, 0.95, 0.15]; - * - * // Higher-quality SAO settings - * - * viewer.scene.sao.enabled = true; - * viewer.scene.sao.numSamples = 60; - * viewer.scene.sao.kernelRadius = 170; + * canvasId: "myCanvas" + * }); * - * // Install a FastNavPlugin + * viewer.scene.camera.eye = [0, 0, 5]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; * - * new FastNavPlugin(viewer, { - * hideEdges: true, // Don't show edges while we interact (default is true) - * hideSAO: true, // Don't show ambient shadows while we interact (default is true) - * hideColorTexture: true, // No color textures while we interact (default is true) - * hidePBR: true, // No physically-based rendering while we interact (default is true) - * hideTransparentObjects: true, // Hide transparent objects while we interact (default is false) - * scaleCanvasResolution: true, // Scale canvas resolution while we interact (default is false) - * scaleCanvasResolutionFactor: 0.5, // Factor by which we scale canvas resolution when we interact (default is 0.6) - * delayBeforeRestore: true, // When we stop interacting, delay before restoring normal render (default is true) - * delayBeforeRestoreSeconds: 0.5 // The delay duration, in seconds (default is 0.5) - * }); + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ + * center: [0, 0, 0], + * radius: 1.5, + * tube: 0.5, + * radialSegments: 12, + * tubeSegments: 8, + * arc: Math.PI * 2.0 + * }), + * material: new LambertMaterial(viewer.scene, { + * ambient: [0.3, 0.3, 0.3], + * color: [0.5, 0.5, 0.0], + * alpha: 1.0, // Default + * lineWidth: 1, + * pointSize: 1, + * backfaces: false, + * frontFace: "ccw" + * }) + * }); + * ```` * - * // Load a BIM model from XKT + * ## LambertMaterial Properties * - * const xktLoader = new XKTLoaderPlugin(viewer); + * The following table summarizes LambertMaterial properties: * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/HolterTower.xkt", - * sao: true, // Enable ambient shadows for this model - * pbr: true // Enable physically-based rendering for this model - * }); - * ```` + * | Property | Type | Range | Default Value | Space | Description | + * |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:| + * | {@link LambertMaterial#ambient} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the ambient light reflected by the material. | + * | {@link LambertMaterial#color} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the diffuse light reflected by the material. | + * | {@link LambertMaterial#emissive} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the light emitted by the material. | + * | {@link LambertMaterial#alpha} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). | + * | {@link LambertMaterial#lineWidth} | Number | [0..100] | 1 | | Line width in pixels. | + * | {@link LambertMaterial#pointSize} | Number | [0..100] | 1 | | Point size in pixels. | + * | {@link LambertMaterial#backfaces} | Boolean | | false | | Whether to render {@link Geometry} backfaces. | + * | {@link LambertMaterial#frontface} | String | "ccw", "cw" | "ccw" | | The winding order for {@link Geometry} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. | * - * @class FastNavPlugin */ -class FastNavPlugin extends Plugin { +class LambertMaterial extends Material { /** - * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg FastNavPlugin configuration. - * @param {String} [cfg.id="FastNav"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Boolean} [cfg.hideColorTexture=true] Whether to temporarily hide color textures whenever we interact with the Viewer. - * @param {Boolean} [cfg.hidePBR=true] Whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. - * @param {Boolean} [cfg.hideSAO=true] Whether to temporarily hide scalable ambient occlusion (SAO) whenever we interact with the Viewer. - * @param {Boolean} [cfg.hideEdges=true] Whether to temporarily hide edges whenever we interact with the Viewer. - * @param {Boolean} [cfg.hideTransparentObjects=false] Whether to temporarily hide transparent objects whenever we interact with the Viewer. - * @param {Number} [cfg.scaleCanvasResolution=false] Whether to temporarily down-scale the canvas resolution whenever we interact with the Viewer. - * @param {Number} [cfg.scaleCanvasResolutionFactor=0.6] The factor by which we downscale the canvas resolution whenever we interact with the Viewer. - * @param {Boolean} [cfg.delayBeforeRestore=true] Whether to temporarily have a delay before restoring normal rendering after we stop interacting with the Viewer. - * @param {Number} [cfg.delayBeforeRestoreSeconds=0.5] Delay in seconds before restoring normal rendering after we stop interacting with the Viewer. + @private */ - constructor(viewer, cfg = {}) { - - super("FastNav", viewer); - - this._hideColorTexture = cfg.hideColorTexture !== false; - this._hidePBR = cfg.hidePBR !== false; - this._hideSAO = cfg.hideSAO !== false; - this._hideEdges = cfg.hideEdges !== false; - this._hideTransparentObjects = !!cfg.hideTransparentObjects; - this._scaleCanvasResolution = !!cfg.scaleCanvasResolution; - this._scaleCanvasResolutionFactor = cfg.scaleCanvasResolutionFactor || 0.6; - this._delayBeforeRestore = (cfg.delayBeforeRestore !== false); - this._delayBeforeRestoreSeconds = cfg.delayBeforeRestoreSeconds || 0.5; - - let timer = this._delayBeforeRestoreSeconds * 1000; - let fastMode = false; - - const switchToLowQuality = () => { - timer = (this._delayBeforeRestoreSeconds * 1000); - if (!fastMode) { - viewer.scene._renderer.setColorTextureEnabled(!this._hideColorTexture); - viewer.scene._renderer.setPBREnabled(!this._hidePBR); - viewer.scene._renderer.setSAOEnabled(!this._hideSAO); - viewer.scene._renderer.setTransparentEnabled(!this._hideTransparentObjects); - viewer.scene._renderer.setEdgesEnabled(!this._hideEdges); - if (this._scaleCanvasResolution) { - viewer.scene.canvas.resolutionScale = this._scaleCanvasResolutionFactor; - } else { - viewer.scene.canvas.resolutionScale = 1; - } - fastMode = true; - } - }; - - const switchToHighQuality = () => { - viewer.scene.canvas.resolutionScale = 1; - viewer.scene._renderer.setEdgesEnabled(true); - viewer.scene._renderer.setColorTextureEnabled(true); - viewer.scene._renderer.setPBREnabled(true); - viewer.scene._renderer.setSAOEnabled(true); - viewer.scene._renderer.setTransparentEnabled(true); - fastMode = false; - }; - - this._onCanvasBoundary = viewer.scene.canvas.on("boundary", switchToLowQuality); - this._onCameraMatrix = viewer.scene.camera.on("matrix", switchToLowQuality); - - this._onSceneTick = viewer.scene.on("tick", (tickEvent) => { - if (!fastMode) { - return; - } - timer -= tickEvent.deltaTime; - if ((!this._delayBeforeRestore) || timer <= 0) { - switchToHighQuality(); - } - }); - - let down = false; + get type() { + return "LambertMaterial"; + } - this._onSceneMouseDown = viewer.scene.input.on("mousedown", () => { - down = true; - }); + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] The LambertMaterial configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {String:Object} [cfg.meta=null] Metadata to attach to this LambertMaterial. + * @param {Number[]} [cfg.ambient=[1.0, 1.0, 1.0 ]] LambertMaterial ambient color. + * @param {Number[]} [cfg.color=[ 1.0, 1.0, 1.0 ]] LambertMaterial diffuse color. + * @param {Number[]} [cfg.emissive=[ 0.0, 0.0, 0.0 ]] LambertMaterial emissive color. + * @param {Number} [cfg.alpha=1]Scalar in range 0-1 that controls alpha, where 0 is completely transparent and 1 is completely opaque. + * @param {Number} [cfg.reflectivity=1]Scalar in range 0-1 that controls how much {@link ReflectionMap} is reflected. + * @param {Number} [cfg.lineWidth=1] Scalar that controls the width of {@link Geometry} lines. + * @param {Number} [cfg.pointSize=1] Scalar that controls the size of points for {@link Geometry} with {@link Geometry#primitive} set to "points". + * @param {Boolean} [cfg.backfaces=false] Whether to render {@link Geometry} backfaces. + * @param {Boolean} [cfg.frontface="ccw"] The winding order for {@link Geometry} front faces - "cw" for clockwise, or "ccw" for counter-clockwise. + */ + constructor(owner, cfg = {}) { - this._onSceneMouseUp = viewer.scene.input.on("mouseup", () => { - down = false; - }); + super(owner, cfg); - this._onSceneMouseMove = viewer.scene.input.on("mousemove", () => { - if (!down) { - return; - } - switchToLowQuality(); + this._state = new RenderState({ + type: "LambertMaterial", + ambient: math.vec3([1.0, 1.0, 1.0]), + color: math.vec3([1.0, 1.0, 1.0]), + emissive: math.vec3([0.0, 0.0, 0.0]), + alpha: null, + alphaMode: 0, // 2 ("blend") when transparent, so renderer knows when to add to transparency bin + lineWidth: null, + pointSize: null, + backfaces: null, + frontface: null, // Boolean for speed; true == "ccw", false == "cw" + hash: "/lam;" }); - } - /** - * Gets whether to temporarily hide color textures whenever we interact with the Viewer. - * - * Default is ````true````. - * - * @return {Boolean} ````true```` if hiding color textures. - */ - get hideColorTexture() { - return this._hideColorTexture; + this.ambient = cfg.ambient; + this.color = cfg.color; + this.emissive = cfg.emissive; + this.alpha = cfg.alpha; + this.lineWidth = cfg.lineWidth; + this.pointSize = cfg.pointSize; + this.backfaces = cfg.backfaces; + this.frontface = cfg.frontface; } /** - * Sets whether to temporarily hide color textures whenever we interact with the Viewer. - * - * Default is ````true````. - * - * @param {Boolean} hideColorTexture ````true```` to hide color textures. - */ - set hideColorTexture(hideColorTexture) { - this._hideColorTexture = hideColorTexture; - } - - /** - * Gets whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. + * Sets the LambertMaterial's ambient color. * - * Default is ````true````. + * Default value is ````[0.3, 0.3, 0.3]````. * - * @return {Boolean} ````true```` if hiding PBR. + * @type {Number[]} */ - get hidePBR() { - return this._hidePBR; + set ambient(value) { + let ambient = this._state.ambient; + if (!ambient) { + ambient = this._state.ambient = new Float32Array(3); + } else if (value && ambient[0] === value[0] && ambient[1] === value[1] && ambient[2] === value[2]) { + return; + } + if (value) { + ambient[0] = value[0]; + ambient[1] = value[1]; + ambient[2] = value[2]; + } else { + ambient[0] = .2; + ambient[1] = .2; + ambient[2] = .2; + } + this.glRedraw(); } /** - * Sets whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. + * Gets the LambertMaterial's ambient color. * - * Default is ````true````. + * Default value is ````[0.3, 0.3, 0.3]````. * - * @param {Boolean} hidePBR ````true```` to hide PBR. + * @type {Number[]} */ - set hidePBR(hidePBR) { - this._hidePBR = hidePBR; + get ambient() { + return this._state.ambient; } /** - * Gets whether to temporarily hide scalable ambient shadows (SAO) whenever we interact with the Viewer. + * Sets the LambertMaterial's diffuse color. * - * Default is ````true````. + * Default value is ````[1.0, 1.0, 1.0]````. * - * @return {Boolean} ````true```` if hiding SAO. + * @type {Number[]} */ - get hideSAO() { - return this._hideSAO; + set color(value) { + let color = this._state.color; + if (!color) { + color = this._state.color = new Float32Array(3); + } else if (value && color[0] === value[0] && color[1] === value[1] && color[2] === value[2]) { + return; + } + if (value) { + color[0] = value[0]; + color[1] = value[1]; + color[2] = value[2]; + } else { + color[0] = 1; + color[1] = 1; + color[2] = 1; + } + this.glRedraw(); } /** - * Sets whether to temporarily hide scalable ambient shadows (SAO) whenever we interact with the Viewer. + * Gets the LambertMaterial's diffuse color. * - * Default is ````true````. + * Default value is ````[1.0, 1.0, 1.0]````. * - * @param {Boolean} hideSAO ````true```` to hide SAO. + * @type {Number[]} */ - set hideSAO(hideSAO) { - this._hideSAO = hideSAO; + get color() { + return this._state.color; } /** - * Gets whether to temporarily hide edges whenever we interact with the Viewer. + * Sets the LambertMaterial's emissive color. * - * Default is ````true````. + * Default value is ````[0.0, 0.0, 0.0]````. * - * @return {Boolean} ````true```` if hiding edges. + * @type {Number[]} */ - get hideEdges() { - return this._hideEdges; + set emissive(value) { + let emissive = this._state.emissive; + if (!emissive) { + emissive = this._state.emissive = new Float32Array(3); + } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) { + return; + } + if (value) { + emissive[0] = value[0]; + emissive[1] = value[1]; + emissive[2] = value[2]; + } else { + emissive[0] = 0; + emissive[1] = 0; + emissive[2] = 0; + } + this.glRedraw(); } /** - * Sets whether to temporarily hide edges whenever we interact with the Viewer. + * Gets the LambertMaterial's emissive color. * - * Default is ````true````. + * Default value is ````[0.0, 0.0, 0.0]````. * - * @param {Boolean} hideEdges ````true```` to hide edges. + * @type {Number[]} */ - set hideEdges(hideEdges) { - this._hideEdges = hideEdges; + get emissive() { + return this._state.emissive; } /** - * Gets whether to temporarily hide transparent objects whenever we interact with the Viewer. + * Sets factor in the range ````[0..1]```` indicating how transparent the LambertMaterial is. * - * Does not hide X-rayed, selected, highlighted objects. + * A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. * - * Default is ````false````. + * Default value is ````1.0```` * - * @return {Boolean} ````true```` if hiding transparent objects. + * @type {Number} */ - get hideTransparentObjects() { - return this._hideTransparentObjects + set alpha(value) { + value = (value !== undefined && value !== null) ? value : 1.0; + if (this._state.alpha === value) { + return; + } + this._state.alpha = value; + this._state.alphaMode = value < 1.0 ? 2 /* blend */ : 0; + /* opaque */ + this.glRedraw(); } /** - * Sets whether to temporarily hide transparent objects whenever we interact with the Viewer. + * Gets factor in the range ````[0..1]```` indicating how transparent the LambertMaterial is. * - * Does not hide X-rayed, selected, highlighted objects. + * A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. * - * Default is ````false````. + * Default value is ````1.0```` * - * @param {Boolean} hideTransparentObjects ````true```` to hide transparent objects. + * @type {Number} */ - set hideTransparentObjects(hideTransparentObjects) { - this._hideTransparentObjects = (hideTransparentObjects !== false); + get alpha() { + return this._state.alpha; } /** - * Gets whether to temporarily scale the canvas resolution whenever we interact with the Viewer. + * Sets the LambertMaterial's line width. * - * Default is ````false````. + * This is not supported by WebGL implementations based on DirectX [2019]. * - * The scaling factor is configured via {@link FastNavPlugin#scaleCanvasResolutionFactor}. + * Default value is ````1.0````. * - * @return {Boolean} ````true```` if scaling the canvas resolution. + * @type {Number} */ - get scaleCanvasResolution() { - return this._scaleCanvasResolution; + set lineWidth(value) { + this._state.lineWidth = value || 1.0; + this.glRedraw(); } /** - * Sets whether to temporarily scale the canvas resolution whenever we interact with the Viewer. + * Gets the LambertMaterial's line width. * - * Default is ````false````. + * This is not supported by WebGL implementations based on DirectX [2019]. * - * The scaling factor is configured via {@link FastNavPlugin#scaleCanvasResolutionFactor}. + * Default value is ````1.0````. * - * @param {Boolean} scaleCanvasResolution ````true```` to scale the canvas resolution. + * @type {Number} */ - set scaleCanvasResolution(scaleCanvasResolution) { - this._scaleCanvasResolution = scaleCanvasResolution; + get lineWidth() { + return this._state.lineWidth; } /** - * Gets the factor by which we temporarily scale the canvas resolution when we interact with the viewer. - * - * Default is ````0.6````. + * Sets the LambertMaterial's point size. * - * Enable canvas resolution scaling by setting {@link FastNavPlugin#scaleCanvasResolution} ````true````. + * Default value is ````1.0````. * - * @return {Number} Factor by which we scale the canvas resolution. + * @type {Number} */ - get scaleCanvasResolutionFactor() { - return this._scaleCanvasResolutionFactor; + set pointSize(value) { + this._state.pointSize = value || 1.0; + this.glRedraw(); } /** - * Sets the factor by which we temporarily scale the canvas resolution when we interact with the viewer. - * - * Accepted range is ````[0.0 .. 1.0]````. - * - * Default is ````0.6````. + * Gets the LambertMaterial's point size. * - * Enable canvas resolution scaling by setting {@link FastNavPlugin#scaleCanvasResolution} ````true````. + * Default value is ````1.0````. * - * @param {Number} scaleCanvasResolutionFactor Factor by which we scale the canvas resolution. + * @type {Number} */ - set scaleCanvasResolutionFactor(scaleCanvasResolutionFactor) { - this._scaleCanvasResolutionFactor = scaleCanvasResolutionFactor || 0.6; + get pointSize() { + return this._state.pointSize; } /** - * Gets whether to have a delay before restoring normal rendering after we stop interacting with the Viewer. - * - * The delay duration is configured via {@link FastNavPlugin#delayBeforeRestoreSeconds}. - * - * Default is ````true````. + * Sets whether backfaces are visible on attached {@link Mesh}es. * - * @return {Boolean} Whether to have a delay. + * @type {Boolean} */ - get delayBeforeRestore() { - return this._delayBeforeRestore; + set backfaces(value) { + value = !!value; + if (this._state.backfaces === value) { + return; + } + this._state.backfaces = value; + this.glRedraw(); } /** - * Sets whether to have a delay before restoring normal rendering after we stop interacting with the Viewer. - * - * The delay duration is configured via {@link FastNavPlugin#delayBeforeRestoreSeconds}. - * - * Default is ````true````. + * Gets whether backfaces are visible on attached {@link Mesh}es. * - * @param {Boolean} delayBeforeRestore Whether to have a delay. + * @type {Boolean} */ - set delayBeforeRestore(delayBeforeRestore) { - this._delayBeforeRestore = delayBeforeRestore; + get backfaces() { + return this._state.backfaces; } /** - * Gets the delay before restoring normal rendering after we stop interacting with the Viewer. - * - * The delay is enabled when {@link FastNavPlugin#delayBeforeRestore} is ````true````. + * Sets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. * - * Default is ````0.5```` seconds. + * Default value is ````"ccw"````. * - * @return {Number} Delay in seconds. + * @type {String} */ - get delayBeforeRestoreSeconds() { - return this._delayBeforeRestoreSeconds; + set frontface(value) { + value = value !== "cw"; + if (this._state.frontface === value) { + return; + } + this._state.frontface = value; + this.glRedraw(); } /** - * Sets the delay before restoring normal rendering after we stop interacting with the Viewer. - * - * The delay is enabled when {@link FastNavPlugin#delayBeforeRestore} is ````true````. + * Gets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. * - * Default is ````0.5```` seconds. + * Default value is ````"ccw"````. * - * @param {Number} delayBeforeRestoreSeconds Delay in seconds. + * @type {String} */ - set delayBeforeRestoreSeconds(delayBeforeRestoreSeconds) { - this._delayBeforeRestoreSeconds = delayBeforeRestoreSeconds !== null && delayBeforeRestoreSeconds !== undefined ? delayBeforeRestoreSeconds : 0.5; + get frontface() { + return this._state.frontface ? "ccw" : "cw"; } - /** - * @private - */ - send(name, value) { + _getState() { + return this._state; } /** - * Destroys this plugin. + * Destroys this LambertMaterial. */ destroy() { - this.viewer.scene.camera.off(this._onCameraMatrix); - this.viewer.scene.canvas.off(this._onCanvasBoundary); - this.viewer.scene.input.off(this._onSceneMouseDown); - this.viewer.scene.input.off(this._onSceneMouseUp); - this.viewer.scene.input.off(this._onSceneMouseMove); - this.viewer.scene.off(this._onSceneTick); super.destroy(); + this._state.destroy(); } } +const modes = {"opaque": 0, "mask": 1, "blend": 2}; +const modeNames = ["opaque", "mask", "blend"]; + /** - * Default data access strategy for {@link GLTFLoaderPlugin}. + * @desc Configures the normal rendered appearance of {@link Mesh}es using the physically-accurate *metallic-roughness* shading model. * - * This just loads assets using XMLHttpRequest. - */ -class GLTFDefaultDataSource { - - constructor() { + * * Useful for conductive materials, such as metal, but also appropriate for insulators. + * * {@link SpecularMaterial} is best for insulators, such as wood, ceramics and plastic. + * * {@link PhongMaterial} is appropriate for non-realistic objects. + * * {@link LambertMaterial} is appropriate for high-detail models that need to render as efficiently as possible. + * + * ## Usage + * + * In the example below we'll create a {@link Mesh} with {@link MetallicMaterial} and {@link ReadableGeometry} loaded from OBJ. + * + * Note that in this example we're providing separate {@link Texture} for the {@link MetallicMaterial#metallic} and {@link MetallicMaterial#roughness} + * channels, which allows us a little creative flexibility. Then, in the next example further down, we'll combine those channels + * within the same {@link Texture} for efficiency. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_MetallicMaterial)] + * + * ````javascript + * import {Viewer, Mesh, loadOBJGeometry, ReadableGeometry, MetallicMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [0.57, 1.37, 1.14]; + * viewer.scene.camera.look = [0.04, 0.58, 0.00]; + * viewer.scene.camera.up = [-0.22, 0.84, -0.48]; + * + * loadOBJGeometry(viewer.scene, { + * src: "models/obj/fireHydrant/FireHydrantMesh.obj" + * }) + * .then(function (geometry) { + * + * // Success + * + * new Mesh(viewer.scene, { + * + * geometry: new ReadableGeometry(viewer.scene, geometry), + * + * material: new MetallicMaterial(viewer.scene, { + * + * baseColor: [1, 1, 1], + * metallic: 1.0, + * roughness: 1.0, + * + * baseColorMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", + * encoding: "sRGB" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" + * }), + * roughnessMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Roughness.png" + * }), + * metallicMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Metallic.png" + * }), + * occlusionMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" + * }), + * + * specularF0: 0.7 + * }) + * }); + * }, function () { + * // Error + * }); + * ```` + * + * ## Background Theory + * + * For an introduction to physically-based rendering (PBR) concepts, try these articles: + * + * * Joe Wilson's [Basic Theory of Physically-Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/) + * * Jeff Russel's [Physically-based Rendering, and you can too!](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/) + * * Sebastien Legarde's [Adapting a physically-based shading model](http://seblagarde.wordpress.com/tag/physically-based-rendering/) + * + * ## MetallicMaterial Properties + * + * The following table summarizes MetallicMaterial properties: + * + * | Property | Type | Range | Default Value | Space | Description | + * |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:| + * | {@link MetallicMaterial#baseColor} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the base color of the material. | + * | {@link MetallicMaterial#metallic} | Number | [0, 1] | 1 | linear | The metallic-ness the material (1 for metals, 0 for non-metals). | + * | {@link MetallicMaterial#roughness} | Number | [0, 1] | 1 | linear | The roughness of the material surface. | + * | {@link MetallicMaterial#specularF0} | Number | [0, 1] | 1 | linear | The specular Fresnel of the material surface. | + * | {@link MetallicMaterial#emissive} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the emissive color of the material. | + * | {@link MetallicMaterial#alpha} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). | + * | {@link MetallicMaterial#baseColorMap} | {@link Texture} | | null | sRGB | Texture RGB components multiplying by {@link MetallicMaterial#baseColor}. If the fourth component (A) is present, it multiplies by {@link MetallicMaterial#alpha}. | + * | {@link MetallicMaterial#metallicMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#metallic}. | + * | {@link MetallicMaterial#roughnessMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#roughness}. | + * | {@link MetallicMaterial#metallicRoughnessMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#metallic} and second component multiplying by {@link MetallicMaterial#roughness}. | + * | {@link MetallicMaterial#emissiveMap} | {@link Texture} | | null | linear | Texture with RGB components multiplying by {@link MetallicMaterial#emissive}. | + * | {@link MetallicMaterial#alphaMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#alpha}. | + * | {@link MetallicMaterial#occlusionMap} | {@link Texture} | | null | linear | Ambient occlusion texture multiplying by surface's reflected diffuse and specular light. | + * | {@link MetallicMaterial#normalMap} | {@link Texture} | | null | linear | Tangent-space normal map. | + * | {@link MetallicMaterial#alphaMode} | String | "opaque", "blend", "mask" | "blend" | | Alpha blend mode. | + * | {@link MetallicMaterial#alphaCutoff} | Number | [0..1] | 0.5 | | Alpha cutoff value. | + * | {@link MetallicMaterial#backfaces} | Boolean | | false | | Whether to render {@link ReadableGeometry} backfaces. | + * | {@link MetallicMaterial#frontface} | String | "ccw", "cw" | "ccw" | | The winding order for {@link ReadableGeometry} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. | + * + * + * ## Combining Channels Within the Same Textures + * + * In the previous example we provided separate {@link Texture} for the {@link MetallicMaterial#metallic} and + * {@link MetallicMaterial#roughness} channels, but we can combine those channels into the same {@link Texture} to + * reduce download time, memory footprint and rendering time (and also for glTF compatibility). + * + * Here's the {@link Mesh} again, with our MetallicMaterial with those channels combined in the {@link MetallicMaterial#metallicRoughnessMap} + * {@link Texture}, where the *R* component multiplies by {@link MetallicMaterial#metallic} and *G* multiplies + * by {@link MetallicMaterial#roughness}. + * + * ````javascript + * new Mesh(viewer.scene, { + * + * geometry: geometry, + * + * material: new MetallicMaterial(viewer.scene, { + * + * baseColor: [1, 1, 1], + * metallic: 1.0, + * roughness: 1.0, + * + * baseColorMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", + * encoding: "sRGB" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" + * }), + * metallicRoughnessMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" + * }), + * metallicRoughnessMap : new Texture(viewer.scene, { // <<----------- Added + * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" // R component multiplies by metallic + * }), // G component multiplies by roughness + * occlusionMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" + * }), + * + * specularF0: 0.7 + * }) + * ```` + * + * Although not shown in this example, we can also texture {@link MetallicMaterial#alpha} with the *A* component of + * {@link MetallicMaterial#baseColorMap}'s {@link Texture}, if required. + * + * ## Alpha Blending + * + * Let's make our {@link Mesh} transparent. + * + * We'll update the {@link MetallicMaterial#alpha} and {@link MetallicMaterial#alphaMode}, causing it to blend 50% + * with the background: + * + * ````javascript + * hydrant.material.alpha = 0.5; + * hydrant.material.alphaMode = "blend"; + * ```` + * + * ## Alpha Masking + * + * Let's apply an alpha mask to our {@link Mesh}. + * + * We'll configure an {@link MetallicMaterial#alphaMap} to multiply by {@link MetallicMaterial#alpha}, + * with {@link MetallicMaterial#alphaMode} and {@link MetallicMaterial#alphaCutoff} to treat it as an alpha mask: + * + * ````javascript + * new Mesh(viewer.scene, { + * + * geometry: geometry, + * + * material: new MetallicMaterial(viewer.scene, { + * + * baseColor: [1, 1, 1], + * metallic: 1.0, + * roughness: 1.0, + * alpha: 1.0, + * alphaMode : "mask", // <<---------------- Added + * alphaCutoff : 0.2, // <<---------------- Added + * + * alphaMap : new Texture(viewer.scene{ // <<---------------- Added + * src: "textures/alphaMap.jpg" + * }), + * baseColorMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", + * encoding: "sRGB" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" + * }), + * metallicRoughnessMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" + * }), + * metallicRoughnessMap : new Texture(viewer.scene, { // <<----------- Added + * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" // R component multiplies by metallic + * }), // G component multiplies by roughness + * occlusionMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" + * }), + * + * specularF0: 0.7 + * }) + * ```` + */ +class MetallicMaterial extends Material { + + /** + @private + */ + get type() { + return "MetallicMaterial"; } /** - * Gets metamodel JSON. - * - * @param {String|Number} metaModelSrc Identifies the metamodel JSON asset. - * @param {Function} ok Fired on successful loading of the metamodel JSON asset. - * @param {Function} error Fired on error while loading the metamodel JSON asset. + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this MetallicMaterial as well. + * @param {*} [cfg] The MetallicMaterial configuration. + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} [cfg.baseColor=[1,1,1]] RGB diffuse color of this MetallicMaterial. Multiplies by the RGB components of {@link MetallicMaterial#baseColorMap}. + * @param {Number} [cfg.metallic=1.0] Factor in the range ````[0..1]```` indicating how metallic this MetallicMaterial is. ````1```` is metal, ````0```` is non-metal. Multiplies by the *R* component of {@link MetallicMaterial#metallicMap} and the *A* component of {@link MetallicMaterial#metallicRoughnessMap}. + * @param {Number} [cfg.roughness=1.0] Factor in the range ````[0..1]```` indicating the roughness of this MetallicMaterial. ````0```` is fully smooth, ````1```` is fully rough. Multiplies by the *R* component of {@link MetallicMaterial#roughnessMap}. + * @param {Number} [cfg.specularF0=0.0] Factor in the range ````[0..1]```` indicating specular Fresnel. + * @param {Number[]} [cfg.emissive=[0,0,0]] RGB emissive color of this MetallicMaterial. Multiplies by the RGB components of {@link MetallicMaterial#emissiveMap}. + * @param {Number} [cfg.alpha=1.0] Factor in the range ````[0..1]```` indicating the alpha of this MetallicMaterial. Multiplies by the *R* component of {@link MetallicMaterial#alphaMap} and the *A* component, if present, of {@link MetallicMaterial#baseColorMap}. The value of {@link MetallicMaterial#alphaMode} indicates how alpha is interpreted when rendering. + * @param {Texture} [cfg.baseColorMap=undefined] RGBA {@link Texture} containing the diffuse color of this MetallicMaterial, with optional *A* component for alpha. The RGB components multiply by the {@link MetallicMaterial#baseColor} property, while the *A* component, if present, multiplies by the {@link MetallicMaterial#alpha} property. + * @param {Texture} [cfg.alphaMap=undefined] RGB {@link Texture} containing this MetallicMaterial's alpha in its *R* component. The *R* component multiplies by the {@link MetallicMaterial#alpha} property. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {Texture} [cfg.metallicMap=undefined] RGB {@link Texture} containing this MetallicMaterial's metallic factor in its *R* component. The *R* component multiplies by the {@link MetallicMaterial#metallic} property. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {Texture} [cfg.roughnessMap=undefined] RGB {@link Texture} containing this MetallicMaterial's roughness factor in its *R* component. The *R* component multiplies by the {@link MetallicMaterial#roughness} property. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {Texture} [cfg.metallicRoughnessMap=undefined] RGB {@link Texture} containing this MetallicMaterial's metalness in its *R* component and roughness in its *G* component. Its *R* component multiplies by the {@link MetallicMaterial#metallic} property, while its *G* component multiplies by the {@link MetallicMaterial#roughness} property. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {Texture} [cfg.emissiveMap=undefined] RGB {@link Texture} containing the emissive color of this MetallicMaterial. Multiplies by the {@link MetallicMaterial#emissive} property. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {Texture} [cfg.occlusionMap=undefined] RGB ambient occlusion {@link Texture}. Within shaders, multiplies by the specular and diffuse light reflected by surfaces. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {Texture} [cfg.normalMap=undefined] RGB tangent-space normal {@link Texture}. Must be within the same {@link Scene} as this MetallicMaterial. + * @param {String} [cfg.alphaMode="opaque"] The alpha blend mode, which specifies how alpha is to be interpreted. Accepted values are "opaque", "blend" and "mask". See the {@link MetallicMaterial#alphaMode} property for more info. + * @param {Number} [cfg.alphaCutoff=0.5] The alpha cutoff value. See the {@link MetallicMaterial#alphaCutoff} property for more info. + * @param {Boolean} [cfg.backfaces=false] Whether to render {@link ReadableGeometry} backfaces. + * @param {Boolean} [cfg.frontface="ccw"] The winding order for {@link ReadableGeometry} front faces - ````"cw"```` for clockwise, or ````"ccw"```` for counter-clockwise. + * @param {Number} [cfg.lineWidth=1] Scalar that controls the width of lines for {@link ReadableGeometry} with {@link ReadableGeometry#primitive} set to "lines". + * @param {Number} [cfg.pointSize=1] Scalar that controls the size of points for {@link ReadableGeometry} with {@link ReadableGeometry#primitive} set to "points". */ - getMetaModel(metaModelSrc, ok, error) { - utils.loadJSON(metaModelSrc, - (json) => { - ok(json); - }, - function (errMsg) { - error(errMsg); - }); + constructor(owner, cfg = {}) { + + super(owner, cfg); + + this._state = new RenderState({ + type: "MetallicMaterial", + baseColor: math.vec4([1.0, 1.0, 1.0]), + emissive: math.vec4([0.0, 0.0, 0.0]), + metallic: null, + roughness: null, + specularF0: null, + alpha: null, + alphaMode: null, // "opaque" + alphaCutoff: null, + lineWidth: null, + pointSize: null, + backfaces: null, + frontface: null, // Boolean for speed; true == "ccw", false == "cw" + hash: null + }); + + this.baseColor = cfg.baseColor; + this.metallic = cfg.metallic; + this.roughness = cfg.roughness; + this.specularF0 = cfg.specularF0; + this.emissive = cfg.emissive; + this.alpha = cfg.alpha; + + if (cfg.baseColorMap) { + this._baseColorMap = this._checkComponent("Texture", cfg.baseColorMap); + } + if (cfg.metallicMap) { + this._metallicMap = this._checkComponent("Texture", cfg.metallicMap); + + } + if (cfg.roughnessMap) { + this._roughnessMap = this._checkComponent("Texture", cfg.roughnessMap); + } + if (cfg.metallicRoughnessMap) { + this._metallicRoughnessMap = this._checkComponent("Texture", cfg.metallicRoughnessMap); + } + if (cfg.emissiveMap) { + this._emissiveMap = this._checkComponent("Texture", cfg.emissiveMap); + } + if (cfg.occlusionMap) { + this._occlusionMap = this._checkComponent("Texture", cfg.occlusionMap); + } + if (cfg.alphaMap) { + this._alphaMap = this._checkComponent("Texture", cfg.alphaMap); + } + if (cfg.normalMap) { + this._normalMap = this._checkComponent("Texture", cfg.normalMap); + } + + this.alphaMode = cfg.alphaMode; + this.alphaCutoff = cfg.alphaCutoff; + this.backfaces = cfg.backfaces; + this.frontface = cfg.frontface; + this.lineWidth = cfg.lineWidth; + this.pointSize = cfg.pointSize; + + this._makeHash(); + } + + _makeHash() { + const state = this._state; + const hash = ["/met"]; + if (this._baseColorMap) { + hash.push("/bm"); + if (this._baseColorMap._state.hasMatrix) { + hash.push("/mat"); + } + hash.push("/" + this._baseColorMap._state.encoding); + } + if (this._metallicMap) { + hash.push("/mm"); + if (this._metallicMap._state.hasMatrix) { + hash.push("/mat"); + } + } + if (this._roughnessMap) { + hash.push("/rm"); + if (this._roughnessMap._state.hasMatrix) { + hash.push("/mat"); + } + } + if (this._metallicRoughnessMap) { + hash.push("/mrm"); + if (this._metallicRoughnessMap._state.hasMatrix) { + hash.push("/mat"); + } + } + if (this._emissiveMap) { + hash.push("/em"); + if (this._emissiveMap._state.hasMatrix) { + hash.push("/mat"); + } + } + if (this._occlusionMap) { + hash.push("/ocm"); + if (this._occlusionMap._state.hasMatrix) { + hash.push("/mat"); + } + } + if (this._alphaMap) { + hash.push("/am"); + if (this._alphaMap._state.hasMatrix) { + hash.push("/mat"); + } + } + if (this._normalMap) { + hash.push("/nm"); + if (this._normalMap._state.hasMatrix) { + hash.push("/mat"); + } + } + hash.push(";"); + state.hash = hash.join(""); } + /** - * Gets glTF JSON. + * Sets the RGB diffuse color. * - * @param {String|Number} glTFSrc Identifies the glTF JSON asset. - * @param {Function} ok Fired on successful loading of the glTF JSON asset. - * @param {Function} error Fired on error while loading the glTF JSON asset. + * Multiplies by the RGB components of {@link MetallicMaterial#baseColorMap}. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * @type {Number[]} */ - getGLTF(glTFSrc, ok, error) { - utils.loadArraybuffer(glTFSrc, - (gltf) => { - ok(gltf); - }, - function (errMsg) { - error(errMsg); - }); + set baseColor(value) { + let baseColor = this._state.baseColor; + if (!baseColor) { + baseColor = this._state.baseColor = new Float32Array(3); + } else if (value && baseColor[0] === value[0] && baseColor[1] === value[1] && baseColor[2] === value[2]) { + return; + } + if (value) { + baseColor[0] = value[0]; + baseColor[1] = value[1]; + baseColor[2] = value[2]; + } else { + baseColor[0] = 1; + baseColor[1] = 1; + baseColor[2] = 1; + } + this.glRedraw(); } /** - * Gets binary glTF file. + * Gets the RGB diffuse color. * - * @param {String|Number} glbSrc Identifies the .glb asset. - * @param {Function} ok Fired on successful loading of the .glb asset. - * @param {Function} error Fired on error while loading the .glb asset. + * Multiplies by the RGB components of {@link MetallicMaterial#baseColorMap}. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * @type {Number[]} */ - getGLB(glbSrc, ok, error) { - utils.loadArraybuffer(glbSrc, - (arraybuffer) => { - ok(arraybuffer); - }, - function (errMsg) { - error(errMsg); - }); + get baseColor() { + return this._state.baseColor; } + /** - * Gets glTF binary attachment. + * Gets the RGB {@link Texture} containing the diffuse color of this MetallicMaterial, with optional *A* component for alpha. * - * Note that this method requires the source of the glTF JSON asset. This is because the binary attachment - * source could be relative to the glTF source, IE. it may not be a global ID. + * The RGB components multiply by {@link MetallicMaterial#baseColor}, while the *A* component, if present, multiplies by {@link MetallicMaterial#alpha}. * - * @param {String|Number} glTFSrc Identifies the glTF JSON asset. - * @param {String|Number} binarySrc Identifies the glTF binary asset. - * @param {Function} ok Fired on successful loading of the glTF binary asset. - * @param {Function} error Fired on error while loading the glTF binary asset. + * @type {Texture} */ - getArrayBuffer(glTFSrc, binarySrc, ok, error) { - loadArraybuffer(glTFSrc, binarySrc, - (arrayBuffer) => { - ok(arrayBuffer); - }, - function (errMsg) { - error(errMsg); - }); + get baseColorMap() { + return this._baseColorMap; } -} -function loadArraybuffer(glTFSrc, binarySrc, ok, err) { - // Check for data: URI - var defaultCallback = () => { - }; - ok = ok || defaultCallback; - err = err || defaultCallback; - const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; - const dataUriRegexResult = binarySrc.match(dataUriRegex); - if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest - const isBase64 = !!dataUriRegexResult[2]; - var data = dataUriRegexResult[3]; - data = window.decodeURIComponent(data); - if (isBase64) { - data = window.atob(data); - } - try { - const buffer = new ArrayBuffer(data.length); - const view = new Uint8Array(buffer); - for (var i = 0; i < data.length; i++) { - view[i] = data.charCodeAt(i); - } - window.setTimeout(function () { - ok(buffer); - }, 0); - } catch (error) { - window.setTimeout(function () { - err(error); - }, 0); + /** + * Sets the metallic factor. + * + * This is in the range ````[0..1]```` and indicates how metallic this MetallicMaterial is. + * + * ````1```` is metal, ````0```` is non-metal. + * + * Multiplies by the *R* component of {@link MetallicMaterial#metallicMap} and the *A* component of {@link MetallicMaterial#metallicRoughnessMap}. + * + * Default value is ````1.0````. + * + * @type {Number} + */ + set metallic(value) { + value = (value !== undefined && value !== null) ? value : 1.0; + if (this._state.metallic === value) { + return; } - } else { - const basePath = getBasePath$1(glTFSrc); - const url = basePath + binarySrc; - const request = new XMLHttpRequest(); - request.open('GET', url, true); - request.responseType = 'arraybuffer'; - request.onreadystatechange = function () { - if (request.readyState === 4) { - if (request.status === 200) { - ok(request.response); - } else { - err('loadArrayBuffer error : ' + request.response); - } - } - }; - request.send(null); + this._state.metallic = value; + this.glRedraw(); } -} - -function getBasePath$1(src) { - var i = src.lastIndexOf("/"); - return (i !== 0) ? src.substring(0, i + 1) : ""; -} - -/** - * @private - * @implements Pickable - */ -class VBOSceneModelMesh { - - constructor(model, id, color, opacity, layer = null, portionId = 0) { - - /** - * The VBOSceneModel that contains this PerformanceModelMesh. - * - * A PerformanceModelMesh always belongs to exactly one VBOSceneModel. - * - * @property model - * @type {VBOSceneModel} - * @final - */ - this.model = model; - - /** - * The VBOSceneModelNode that contains this PerformanceModelMesh. - * - * A PerformanceModelMesh always belongs to exactly one VBOSceneModelNode. - * - * @property object - * @type {VBOSceneModelNode} - * @final - */ - this.object = null; - - /** - * The VBOSceneModelNode that contains this PerformanceModelMesh. - * - * A PerformanceModelMesh always belongs to exactly one VBOSceneModelNode. - * - * @property object - * @type {VBOSceneModelNode} - * @final - */ - this.parent = null; - - /** - * ID of this PerformanceModelMesh, unique within the xeokit.Scene. - * - * @property id - * @type {String} - * @final - */ - this.id = id; - - /** - * - * @type {Number} - * @private - */ - this.pickId = this.model.scene._renderer.getPickID(this); - - /** - * World-space 3D axis-aligned bounding box (AABB). - * - * Represented by a six-element Float64Array containing the min/max extents of the - * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. - * - * @property aabb - * @final - * @type {Float64Array} - */ - this.aabb = math.AABB3(); - - this._layer = layer; - this._portionId = portionId; - - this._color = [color[0], color[1], color[2], opacity]; // [0..255] - this._colorize = [color[0], color[1], color[2], opacity]; // [0..255] - this._colorizing = false; - - this._transparent = (opacity < 255); - - this.numTriangles = 0; - /** - * 3D origin of the VBOSceneModelMesh's vertex positions, if they are in relative-to-center (RTC) coordinates. - * - * When this is defined, then the positions are RTC, which means that they are relative to this position. - * - * @property origin - * @type {Float64Array} - */ - this.origin = null; + /** + * Gets the metallic factor. + * + * @type {Number} + */ + get metallic() { + return this._state.metallic; } /** - * @private + * Gets the RGB {@link Texture} containing this MetallicMaterial's metallic factor in its *R* component. + * + * The *R* component multiplies by {@link MetallicMaterial#metallic}. + * + * @type {Texture} */ - _finalize(entityFlags) { - this._layer.initFlags(this._portionId, entityFlags, this._transparent); + get metallicMap() { + return this._attached.metallicMap; } /** - * @private + * Sets the roughness factor. + * + * This factor is in the range ````[0..1]````, where ````0```` is fully smooth,````1```` is fully rough. + * + * Multiplies by the *R* component of {@link MetallicMaterial#roughnessMap}. + * + * Default value is ````1.0````. + * + * @type {Number} */ - _finalize2() { - if (this._layer.flushInitFlags) { - this._layer.flushInitFlags(); + set roughness(value) { + value = (value !== undefined && value !== null) ? value : 1.0; + if (this._state.roughness === value) { + return; } + this._state.roughness = value; + this.glRedraw(); } /** - * @private + * Gets the roughness factor. + * + * @type {Number} */ - _setVisible(entityFlags) { - this._layer.setVisible(this._portionId, entityFlags, this._transparent); + get roughness() { + return this._state.roughness; } /** - * @private + * Gets the RGB {@link Texture} containing this MetallicMaterial's roughness factor in its *R* component. + * + * The *R* component multiplies by {@link MetallicMaterial#roughness}. + * + * @type {Texture} */ - _setColor(color) { - this._color[0] = color[0]; - this._color[1] = color[1]; - this._color[2] = color[2]; - if (!this._colorizing) { - this._layer.setColor(this._portionId, this._color, false); - } + get roughnessMap() { + return this._attached.roughnessMap; } - /** @private */ - _setColorize(colorize) { - const setOpacity = false; - if (colorize) { - this._colorize[0] = colorize[0]; - this._colorize[1] = colorize[1]; - this._colorize[2] = colorize[2]; - this._layer.setColor(this._portionId, this._colorize, setOpacity); - this._colorizing = true; - } else { - this._layer.setColor(this._portionId, this._color, setOpacity); - this._colorizing = false; - } + /** + * Gets the RGB {@link Texture} containing this MetallicMaterial's metalness in its *R* component and roughness in its *G* component. + * + * Its *B* component multiplies by the {@link MetallicMaterial#metallic} property, while its *G* component multiplies by the {@link MetallicMaterial#roughness} property. + * + * @type {Texture} + */ + get metallicRoughnessMap() { + return this._attached.metallicRoughnessMap; } - /** @private */ - _setOpacity(opacity, entityFlags) { - const newTransparent = (opacity < 255); - const lastTransparent = this._transparent; - const changingTransparency = (lastTransparent !== newTransparent); - this._color[3] = opacity; - this._colorize[3] = opacity; - this._transparent = newTransparent; - if (this._colorizing) { - this._layer.setColor(this._portionId, this._colorize); - } else { - this._layer.setColor(this._portionId, this._color); - } - if (changingTransparency) { - this._layer.setTransparent(this._portionId, entityFlags, newTransparent); + /** + * Sets the factor in the range [0..1] indicating specular Fresnel value. + * + * Default value is ````0.0````. + * + * @type {Number} + */ + set specularF0(value) { + value = (value !== undefined && value !== null) ? value : 0.0; + if (this._state.specularF0 === value) { + return; } + this._state.specularF0 = value; + this.glRedraw(); } /** - * @private + * Gets the factor in the range [0..1] indicating specular Fresnel value. + * + * @type {Number} */ - _setOffset(offset) { - this._layer.setOffset(this._portionId, offset); + get specularF0() { + return this._state.specularF0; } /** - * @private + * Sets the RGB emissive color. + * + * Multiplies by {@link MetallicMaterial#emissiveMap}. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @type {Number[]} */ - _setHighlighted(entityFlags) { - this._layer.setHighlighted(this._portionId, entityFlags, this._transparent); + set emissive(value) { + let emissive = this._state.emissive; + if (!emissive) { + emissive = this._state.emissive = new Float32Array(3); + } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) { + return; + } + if (value) { + emissive[0] = value[0]; + emissive[1] = value[1]; + emissive[2] = value[2]; + } else { + emissive[0] = 0; + emissive[1] = 0; + emissive[2] = 0; + } + this.glRedraw(); } /** - * @private + * Gets the RGB emissive color. + * + * @type {Number[]} */ - _setXRayed(entityFlags) { - this._layer.setXRayed(this._portionId, entityFlags, this._transparent); + get emissive() { + return this._state.emissive; } /** - * @private + * Gets the RGB emissive map. + * + * Multiplies by {@link MetallicMaterial#emissive}. + * + * @type {Texture} */ - _setSelected(entityFlags) { - this._layer.setSelected(this._portionId, entityFlags, this._transparent); + get emissiveMap() { + return this._attached.emissiveMap; } /** - * @private + * Gets the RGB ambient occlusion map. + * + * Multiplies by the specular and diffuse light reflected by surfaces. + * + * @type {Texture} */ - _setEdges(entityFlags) { - this._layer.setEdges(this._portionId, entityFlags, this._transparent); + get occlusionMap() { + return this._attached.occlusionMap; } /** - * @private + * Sets factor in the range ````[0..1]```` that indicates the alpha value. + * + * Multiplies by the *R* component of {@link MetallicMaterial#alphaMap} and the *A* component, if present, of {@link MetallicMaterial#baseColorMap}. + * + * The value of {@link MetallicMaterial#alphaMode} indicates how alpha is interpreted when rendering. + * + * Default value is ````1.0````. + * + * @type {Number} */ - _setClippable(entityFlags) { - this._layer.setClippable(this._portionId, entityFlags, this._transparent); + set alpha(value) { + value = (value !== undefined && value !== null) ? value : 1.0; + if (this._state.alpha === value) { + return; + } + this._state.alpha = value; + this.glRedraw(); } /** - * @private + * Gets factor in the range ````[0..1]```` that indicates the alpha value. + * + * @type {Number} */ - _setCollidable(entityFlags) { - this._layer.setCollidable(this._portionId, entityFlags); + get alpha() { + return this._state.alpha; } /** - * @private + * Gets the RGB {@link Texture} containing this MetallicMaterial's alpha in its *R* component. + * + * The *R* component multiplies by the {@link MetallicMaterial#alpha} property. + * + * @type {Texture} */ - _setPickable(flags) { - this._layer.setPickable(this._portionId, flags, this._transparent); + get alphaMap() { + return this._attached.alphaMap; } /** - * @private + * Gets the RGB tangent-space normal map {@link Texture}. + * + * @type {Texture} */ - _setCulled(flags) { - this._layer.setCulled(this._portionId, flags, this._transparent); + get normalMap() { + return this._attached.normalMap; } - /** @private */ - canPickTriangle() { - return false; + /** + * Sets the alpha rendering mode. + * + * This specifies how alpha is interpreted. Alpha is the combined result of the {@link MetallicMaterial#alpha} and {@link MetallicMaterial#alphaMap} properties. + * + * Accepted values are: + * + * * "opaque" - The alpha value is ignored and the rendered output is fully opaque (default). + * * "mask" - The rendered output is either fully opaque or fully transparent depending on the alpha and {@link MetallicMaterial#alphaCutoff}. + * * "blend" - The alpha value is used to composite the source and destination areas. The rendered output is combined with the background using the normal painting operation (i.e. the Porter and Duff over operator). + * + * @type {String} + */ + set alphaMode(alphaMode) { + alphaMode = alphaMode || "opaque"; + let value = modes[alphaMode]; + if (value === undefined) { + this.error("Unsupported value for 'alphaMode': " + alphaMode + " defaulting to 'opaque'"); + value = "opaque"; + } + if (this._state.alphaMode === value) { + return; + } + this._state.alphaMode = value; + this.glRedraw(); } - /** @private */ - drawPickTriangles(renderFlags, frameCtx) { - // NOP + /** + * Gets the alpha rendering mode. + * + * @type {String} + */ + get alphaMode() { + return modeNames[this._state.alphaMode]; } - /** @private */ - pickTriangleSurface(pickResult) { - // NOP + /** + * Sets the alpha cutoff value. + * + * Specifies the cutoff threshold when {@link MetallicMaterial#alphaMode} equals "mask". If the alpha is greater than or equal to this value then it is rendered as fully opaque, otherwise, it is rendered as fully transparent. A value greater than 1.0 will render the entire + * material as fully transparent. This value is ignored for other modes. + * + * Alpha is the combined result of the {@link MetallicMaterial#alpha} and {@link MetallicMaterial#alphaMap} properties. + * + * Default value is ````0.5````. + * + * @type {Number} + */ + set alphaCutoff(alphaCutoff) { + if (alphaCutoff === null || alphaCutoff === undefined) { + alphaCutoff = 0.5; + } + if (this._state.alphaCutoff === alphaCutoff) { + return; + } + this._state.alphaCutoff = alphaCutoff; } - /** @private */ - precisionRayPickSurface(worldRayOrigin, worldRayDir, worldSurfacePos, worldSurfaceNormal) { - return this._layer.precisionRayPickSurface ? this._layer.precisionRayPickSurface(this._portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldSurfaceNormal) : false; + /** + * Gets the alpha cutoff value. + * + * @type {Number} + */ + get alphaCutoff() { + return this._state.alphaCutoff; } - /** @private */ - canPickWorldPos() { - return true; + /** + * Sets whether backfaces are visible on attached {@link Mesh}es. + * + * The backfaces will belong to {@link ReadableGeometry} compoents that are also attached to the {@link Mesh}es. + * + * Default is ````false````. + * + * @type {Boolean} + */ + set backfaces(value) { + value = !!value; + if (this._state.backfaces === value) { + return; + } + this._state.backfaces = value; + this.glRedraw(); } - /** @private */ - drawPickDepths(frameCtx) { - this.model.drawPickDepths(frameCtx); + /** + * Gets whether backfaces are visible on attached {@link Mesh}es. + * + * @type {Boolean} + */ + get backfaces() { + return this._state.backfaces; } - /** @private */ - drawPickNormals(frameCtx) { - this.model.drawPickNormals(frameCtx); + /** + * Sets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. + * + * Default value is ````"ccw"````. + * + * @type {String} + */ + set frontface(value) { + value = value !== "cw"; + if (this._state.frontface === value) { + return; + } + this._state.frontface = value; + this.glRedraw(); } /** - * @private - * @returns {VBOSceneModelNode} + * Gets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. +* + * @type {String} */ - delegatePickedEntity() { - return this.parent; + get frontface() { + return this._state.frontface ? "ccw" : "cw"; } /** - * @private + * Sets the MetallicMaterial's line width. + * + * This is not supported by WebGL implementations based on DirectX [2019]. + * + * Default value is ````1.0````. + * + * @type {Number} */ - _destroy() { - this.model.scene._renderer.putPickID(this.pickId); + set lineWidth(value) { + this._state.lineWidth = value || 1.0; + this.glRedraw(); } -} - -/** - * Provides scratch memory for methods like TrianglesBatchingLayer setFlags() and setColors(), - * so they don't need to allocate temporary arrays that need garbage collection. - * - * @private - */ -class ScratchMemory { - constructor() { - this._uint8Arrays = {}; - this._float32Arrays = {}; + /** + * Gets the MetallicMaterial's line width. + * + * @type {Number} + */ + get lineWidth() { + return this._state.lineWidth; } - _clear() { - this._uint8Arrays = {}; - this._float32Arrays = {}; + /** + * Sets the MetallicMaterial's point size. + * + * Default value is ````1.0````. + * + * @type {Number} + */ + set pointSize(value) { + this._state.pointSize = value || 1.0; + this.glRedraw(); } - getUInt8Array(len) { - let uint8Array = this._uint8Arrays[len]; - if (!uint8Array) { - uint8Array = new Uint8Array(len); - this._uint8Arrays[len] = uint8Array; - } - return uint8Array; + /** + * Gets the MetallicMaterial's point size. + * + * @type {Number} + */ + get pointSize() { + return this._state.pointSize; } - getFloat32Array(len) { - let float32Array = this._float32Arrays[len]; - if (!float32Array) { - float32Array = new Float32Array(len); - this._float32Arrays[len] = float32Array; - } - return float32Array; + /** + * Destroys this MetallicMaterial. + */ + destroy() { + super.destroy(); + this._state.destroy(); } } -const batchingLayerScratchMemory = new ScratchMemory(); - -let countUsers = 0; +const alphaModes = {"opaque": 0, "mask": 1, "blend": 2}; +const alphaModeNames = ["opaque", "mask", "blend"]; /** - * @private - */ -function getScratchMemory() { - countUsers++; - return batchingLayerScratchMemory; -} - -/** - * @private - */ -function putScratchMemory() { - if (countUsers === 0) { - return; - } - countUsers--; - if (countUsers === 0) { - batchingLayerScratchMemory._clear(); - } -} - -/** - * @private + * @desc Configures the normal rendered appearance of {@link Mesh}es using the physically-accurate *specular-glossiness* shading model. + * + * * Useful for insulators, such as wood, ceramics and plastic. + * * {@link MetallicMaterial} is best for conductive materials, such as metal. + * * {@link PhongMaterial} is appropriate for non-realistic objects. + * * {@link LambertMaterial} is appropriate for high-detail models that need to render as efficiently as possible. + * + * ## Usage + * + * In the example below we'll create a {@link Mesh} with a {@link buildTorusGeometry} and a SpecularMaterial. + * + * Note that in this example we're providing separate {@link Texture} for the {@link SpecularMaterial#specular} and {@link SpecularMaterial#glossiness} + * channels, which allows us a little creative flexibility. Then, in the next example further down, we'll combine those channels + * within the same {@link Texture} for efficiency. + * + * ````javascript + * import {Viewer, Mesh, buildTorusGeometry, SpecularMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ canvasId: "myCanvas" }); + * + * const myMesh = new Mesh(viewer.scene,{ + * + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry()), + * + * material: new SpecularMaterial(viewer.scene,{ + * + * // Channels with default values, just to show them + * + * diffuse: [1.0, 1.0, 1.0], + * specular: [1.0, 1.0, 1.0], + * glossiness: 1.0, + * emissive: [0.0, 0.0, 0.0] + * alpha: 1.0, + * + * // Textures to multiply some of the channels + * + * diffuseMap: new Texture(viewer.scene, { // RGB components multiply by diffuse + * src: "textures/diffuse.jpg" + * }), + * specularMap: new Texture(viewer.scene, { // RGB component multiplies by specular + * src: "textures/specular.jpg" + * }), + * glossinessMap: new Texture(viewer.scene, { // R component multiplies by glossiness + * src: "textures/glossiness.jpg" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "textures/normalMap.jpg" + * }) + * }) + * }); + * ```` + * + * ## Combining Channels Within the Same Textures + * + * In the previous example we provided separate {@link Texture} for the {@link SpecularMaterial#specular} and + * {@link SpecularMaterial#glossiness} channels, but we can combine those channels into the same {@link Texture} to reduce + * download time, memory footprint and rendering time (and also for glTF compatibility). + * + * Here's our SpecularMaterial again with those channels combined in the {@link SpecularMaterial#specularGlossinessMap} + * {@link Texture}, where the *RGB* component multiplies by {@link SpecularMaterial#specular} and *A* multiplies by {@link SpecularMaterial#glossiness}. + * + * ````javascript + * const myMesh = new Mesh(viewer.scene,{ + * + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry()), + * + * material: new SpecularMaterial(viewer.scene,{ + * + * // Channels with default values, just to show them + * + * diffuse: [1.0, 1.0, 1.0], + * specular: [1.0, 1.0, 1.0], + * glossiness: 1.0, + * emissive: [0.0, 0.0, 0.0] + * alpha: 1.0, + * + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse.jpg" + * }), + * specularGlossinessMap: new Texture(viewer.scene, { // RGB multiplies by specular, A by glossiness + * src: "textures/specularGlossiness.jpg" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "textures/normalMap.jpg" + * }) + * }) + * }); + * ```` + * + * Although not shown in this example, we can also texture {@link SpecularMaterial#alpha} with + * the *A* component of {@link SpecularMaterial#diffuseMap}'s {@link Texture}, if required. + * + * ## Alpha Blending + * + * Let's make our {@link Mesh} transparent. We'll redefine {@link SpecularMaterial#alpha} + * and {@link SpecularMaterial#alphaMode}, causing it to blend 50% with the background: + * + * ````javascript + * const myMesh = new Mesh(viewer.scene,{ + * + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry()), + * + * material: new SpecularMaterial(viewer.scene,{ + * + * // Channels with default values, just to show them + * + * diffuse: [1.0, 1.0, 1.0], + * specular: [1.0, 1.0, 1.0], + * glossiness: 1.0, + * emissive: [0.0, 0.0, 0.0] + * alpha: 0.5, // <<----------- Changed + * alphaMode: "blend", // <<----------- Added + * + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse.jpg" + * }), + * specularGlossinessMap: new Texture(viewer.scene, { // RGB multiplies by specular, A by glossiness + * src: "textures/specularGlossiness.jpg" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "textures/normalMap.jpg" + * }) + * }) + * }); + * ```` + * + * ## Alpha Masking + * + * Now let's make holes in our {@link Mesh}. We'll give its SpecularMaterial an {@link SpecularMaterial#alphaMap} + * and configure {@link SpecularMaterial#alpha}, {@link SpecularMaterial#alphaMode}, + * and {@link SpecularMaterial#alphaCutoff} to treat it as an alpha mask: + * + * ````javascript + * const myMesh = new Mesh(viewer.scene,{ + * + * geometry: buildTorusGeometry(viewer.scene, ReadableGeometry, {}), + * + * material: new SpecularMaterial(viewer.scene, { + * + * // Channels with default values, just to show them + * + * diffuse: [1.0, 1.0, 1.0], + * specular: [1.0, 1.0, 1.0], + * glossiness: 1.0, + * emissive: [0.0, 0.0, 0.0] + * alpha: 1.0, // <<----------- Changed + * alphaMode: "mask", // <<----------- Changed + * alphaCutoff: 0.2, // <<----------- Added + * + * alphaMap: new Texture(viewer.scene, { // <<---------- Added + * src: "textures/diffuse/crossGridColorMap.jpg" + * }), + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse.jpg" + * }), + * specularGlossinessMap: new Texture(viewer.scene, { // RGB multiplies by specular, A by glossiness + * src: "textures/specularGlossiness.jpg" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "textures/normalMap.jpg" + * }) + * }) + * }); + * ```` + * + * ## Background Theory + * + * For an introduction to physically-based rendering (PBR) concepts, try these articles: + * + * * Joe Wilson's [Basic Theory of Physically-Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/) + * * Jeff Russel's [Physically-based Rendering, and you can too!](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/) + * * Sebastien Legarde's [Adapting a physically-based shading model](http://seblagarde.wordpress.com/tag/physically-based-rendering/) + * + * ## SpecularMaterial Properties + * + * The following table summarizes SpecularMaterial properties: + * + * | Property | Type | Range | Default Value | Space | Description | + * |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:| + * | {@link SpecularMaterial#diffuse} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the diffuse color of the material. | + * | {@link SpecularMaterial#specular} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the specular color of the material. | + * | {@link SpecularMaterial#glossiness} | Number | [0, 1] | 1 | linear | The glossiness the material. | + * | {@link SpecularMaterial#specularF0} | Number | [0, 1] | 1 | linear | The specularF0 of the material surface. | + * | {@link SpecularMaterial#emissive} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the emissive color of the material. | + * | {@link SpecularMaterial#alpha} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). | + * | {@link SpecularMaterial#diffuseMap} | {@link Texture} | | null | sRGB | Texture RGB components multiplying by {@link SpecularMaterial#diffuse}. If the fourth component (A) is present, it multiplies by {@link SpecularMaterial#alpha}. | + * | {@link SpecularMaterial#specularMap} | {@link Texture} | | null | sRGB | Texture RGB components multiplying by {@link SpecularMaterial#specular}. If the fourth component (A) is present, it multiplies by {@link SpecularMaterial#alpha}. | + * | {@link SpecularMaterial#glossinessMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link SpecularMaterial#glossiness}. | + * | {@link SpecularMaterial#specularGlossinessMap} | {@link Texture} | | null | linear | Texture with first three components multiplying by {@link SpecularMaterial#specular} and fourth component multiplying by {@link SpecularMaterial#glossiness}. | + * | {@link SpecularMaterial#emissiveMap} | {@link Texture} | | null | linear | Texture with RGB components multiplying by {@link SpecularMaterial#emissive}. | + * | {@link SpecularMaterial#alphaMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link SpecularMaterial#alpha}. | + * | {@link SpecularMaterial#occlusionMap} | {@link Texture} | | null | linear | Ambient occlusion texture multiplying by surface's reflected diffuse and specular light. | + * | {@link SpecularMaterial#normalMap} | {@link Texture} | | null | linear | Tangent-space normal map. | + * | {@link SpecularMaterial#alphaMode} | String | "opaque", "blend", "mask" | "blend" | | Alpha blend mode. | + * | {@link SpecularMaterial#alphaCutoff} | Number | [0..1] | 0.5 | | Alpha cutoff value. | + * | {@link SpecularMaterial#backfaces} | Boolean | | false | | Whether to render {@link Geometry} backfaces. | + * | {@link SpecularMaterial#frontface} | String | "ccw", "cw" | "ccw" | | The winding order for {@link Geometry} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. | + * */ -const RENDER_PASSES = { - - // Skipped - suppress rendering - - NOT_RENDERED: 0, - - // Normal rendering - mutually exclusive modes - - COLOR_OPAQUE: 1, - COLOR_TRANSPARENT: 2, +class SpecularMaterial extends Material { - // Emphasis silhouette rendering - mutually exclusive modes + /** + @private + */ + get type() { + return "SpecularMaterial"; + } - SILHOUETTE_HIGHLIGHTED: 3, - SILHOUETTE_SELECTED: 4, - SILHOUETTE_XRAYED: 5, + /** + * + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] The SpecularMaterial configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} [cfg.diffuse=[1,1,1]] RGB diffuse color of this SpecularMaterial. Multiplies by the RGB components of {@link SpecularMaterial#diffuseMap}. + * @param {Texture} [cfg.diffuseMap=undefined] RGBA {@link Texture} containing the diffuse color of this SpecularMaterial, with optional *A* component for alpha. The RGB components multiply by {@link SpecularMaterial#diffuse}, while the *A* component, if present, multiplies by {@link SpecularMaterial#alpha}. + * @param {Number} [cfg.specular=[1,1,1]] RGB specular color of this SpecularMaterial. Multiplies by the {@link SpecularMaterial#specularMap} and the *RGB* components of {@link SpecularMaterial#specularGlossinessMap}. + * @param {Texture} [cfg.specularMap=undefined] RGB texture containing the specular color of this SpecularMaterial. Multiplies by the {@link SpecularMaterial#specular} property. Must be within the same {@link Scene} as this SpecularMaterial. + * @param {Number} [cfg.glossiness=1.0] Factor in the range [0..1] indicating how glossy this SpecularMaterial is. 0 is no glossiness, 1 is full glossiness. Multiplies by the *R* component of {@link SpecularMaterial#glossinessMap} and the *A* component of {@link SpecularMaterial#specularGlossinessMap}. + * @param {Texture} [cfg.specularGlossinessMap=undefined] RGBA {@link Texture} containing this SpecularMaterial's specular color in its *RGB* component and glossiness in its *A* component. Its *RGB* components multiply by {@link SpecularMaterial#specular}, while its *A* component multiplies by {@link SpecularMaterial#glossiness}. Must be within the same {@link Scene} as this SpecularMaterial. + * @param {Number} [cfg.specularF0=0.0] Factor in the range 0..1 indicating how reflective this SpecularMaterial is. + * @param {Number[]} [cfg.emissive=[0,0,0]] RGB emissive color of this SpecularMaterial. Multiplies by the RGB components of {@link SpecularMaterial#emissiveMap}. + * @param {Texture} [cfg.emissiveMap=undefined] RGB {@link Texture} containing the emissive color of this SpecularMaterial. Multiplies by the {@link SpecularMaterial#emissive} property. Must be within the same {@link Scene} as this SpecularMaterial. + * @param {Texture} [cfg.occlusionMap=undefined] RGB ambient occlusion {@link Texture}. Within shaders, multiplies by the specular and diffuse light reflected by surfaces. Must be within the same {@link Scene} as this SpecularMaterial. + * @param {Texture} [cfg.normalMap=undefined] {Texture} RGB tangent-space normal {@link Texture}. Must be within the same {@link Scene} as this SpecularMaterial. + * @param {Number} [cfg.alpha=1.0] Factor in the range 0..1 indicating how transparent this SpecularMaterial is. A value of 0.0 indicates fully transparent, 1.0 is fully opaque. Multiplies by the *R* component of {@link SpecularMaterial#alphaMap} and the *A* component, if present, of {@link SpecularMaterial#diffuseMap}. + * @param {Texture} [cfg.alphaMap=undefined] RGB {@link Texture} containing this SpecularMaterial's alpha in its *R* component. The *R* component multiplies by the {@link SpecularMaterial#alpha} property. Must be within the same {@link Scene} as this SpecularMaterial. + * @param {String} [cfg.alphaMode="opaque"] The alpha blend mode - accepted values are "opaque", "blend" and "mask". See the {@link SpecularMaterial#alphaMode} property for more info. + * @param {Number} [cfg.alphaCutoff=0.5] The alpha cutoff value. See the {@link SpecularMaterial#alphaCutoff} property for more info. + * @param {Boolean} [cfg.backfaces=false] Whether to render {@link Geometry} backfaces. + * @param {Boolean} [cfg.frontface="ccw"] The winding order for {@link Geometry} front faces - "cw" for clockwise, or "ccw" for counter-clockwise. + * @param {Number} [cfg.lineWidth=1] Scalar that controls the width of {@link Geometry lines. + * @param {Number} [cfg.pointSize=1] Scalar that controls the size of {@link Geometry} points. + */ + constructor(owner, cfg = {}) { - // Edges rendering - mutually exclusive modes + super(owner, cfg); - EDGES_COLOR_OPAQUE: 6, - EDGES_COLOR_TRANSPARENT: 7, - EDGES_HIGHLIGHTED: 8, - EDGES_SELECTED: 9, - EDGES_XRAYED: 10, + this._state = new RenderState({ + type: "SpecularMaterial", + diffuse: math.vec3([1.0, 1.0, 1.0]), + emissive: math.vec3([0.0, 0.0, 0.0]), + specular: math.vec3([1.0, 1.0, 1.0]), + glossiness: null, + specularF0: null, + alpha: null, + alphaMode: null, + alphaCutoff: null, + lineWidth: null, + pointSize: null, + backfaces: null, + frontface: null, // Boolean for speed; true == "ccw", false == "cw" + hash: null + }); - // Picking + this.diffuse = cfg.diffuse; + this.specular = cfg.specular; + this.glossiness = cfg.glossiness; + this.specularF0 = cfg.specularF0; + this.emissive = cfg.emissive; + this.alpha = cfg.alpha; - PICK: 11 -}; + if (cfg.diffuseMap) { + this._diffuseMap = this._checkComponent("Texture", cfg.diffuseMap); + } + if (cfg.emissiveMap) { + this._emissiveMap = this._checkComponent("Texture", cfg.emissiveMap); + } + if (cfg.specularMap) { + this._specularMap = this._checkComponent("Texture", cfg.specularMap); + } + if (cfg.glossinessMap) { + this._glossinessMap = this._checkComponent("Texture", cfg.glossinessMap); + } + if (cfg.specularGlossinessMap) { + this._specularGlossinessMap = this._checkComponent("Texture", cfg.specularGlossinessMap); + } + if (cfg.occlusionMap) { + this._occlusionMap = this._checkComponent("Texture", cfg.occlusionMap); + } + if (cfg.alphaMap) { + this._alphaMap = this._checkComponent("Texture", cfg.alphaMap); + } + if (cfg.normalMap) { + this._normalMap = this._checkComponent("Texture", cfg.normalMap); + } -const tempVec4$7 = math.vec4(); -const tempVec3a$W = math.vec3(); + this.alphaMode = cfg.alphaMode; + this.alphaCutoff = cfg.alphaCutoff; + this.backfaces = cfg.backfaces; + this.frontface = cfg.frontface; -/** - * @private - */ -class TrianglesBatchingColorRenderer { + this.lineWidth = cfg.lineWidth; + this.pointSize = cfg.pointSize; - constructor(scene, withSAO) { - this._scene = scene; - this._withSAO = withSAO; - this._hash = this._getHash(); - this._allocate(); + this._makeHash(); } - getValid() { - return this._hash === this._getHash(); - }; + _makeHash() { + const state = this._state; + const hash = ["/spe"]; + if (this._diffuseMap) { + hash.push("/dm"); + if (this._diffuseMap.hasMatrix) { + hash.push("/mat"); + } + hash.push("/" + this._diffuseMap.encoding); + } + if (this._emissiveMap) { + hash.push("/em"); + if (this._emissiveMap.hasMatrix) { + hash.push("/mat"); + } + } + if (this._glossinessMap) { + hash.push("/gm"); + if (this._glossinessMap.hasMatrix) { + hash.push("/mat"); + } + } + if (this._specularMap) { + hash.push("/sm"); + if (this._specularMap.hasMatrix) { + hash.push("/mat"); + } + } + if (this._specularGlossinessMap) { + hash.push("/sgm"); + if (this._specularGlossinessMap.hasMatrix) { + hash.push("/mat"); + } + } + if (this._occlusionMap) { + hash.push("/ocm"); + if (this._occlusionMap.hasMatrix) { + hash.push("/mat"); + } + } + if (this._normalMap) { + hash.push("/nm"); + if (this._normalMap.hasMatrix) { + hash.push("/mat"); + } + } + if (this._alphaMap) { + hash.push("/opm"); + if (this._alphaMap.hasMatrix) { + hash.push("/mat"); + } + } + hash.push(";"); + state.hash = hash.join(""); + } - _getHash() { - const scene = this._scene; - return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); + /** + * Sets the RGB diffuse color of this SpecularMaterial. + * + * Multiplies by the *RGB* components of {@link SpecularMaterial#diffuseMap}. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * @type {Number[]} + */ + set diffuse(value) { + let diffuse = this._state.diffuse; + if (!diffuse) { + diffuse = this._state.diffuse = new Float32Array(3); + } else if (value && diffuse[0] === value[0] && diffuse[1] === value[1] && diffuse[2] === value[2]) { + return; + } + if (value) { + diffuse[0] = value[0]; + diffuse[1] = value[1]; + diffuse[2] = value[2]; + } else { + diffuse[0] = 1; + diffuse[1] = 1; + diffuse[2] = 1; + } + this.glRedraw(); } - drawLayer(frameCtx, batchingLayer, renderPass) { + /** + * Gets the RGB diffuse color of this SpecularMaterial. + * + * @type {Number[]} + */ + get diffuse() { + return this._state.diffuse; + } - const scene = this._scene; - const camera = scene.camera; - const model = batchingLayer.model; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; + /** + * Gets the RGB {@link Texture} containing the diffuse color of this SpecularMaterial, with optional *A* component for alpha. + * + * The *RGB* components multipliues by the {@link SpecularMaterial#diffuse} property, while the *A* component, if present, multiplies by the {@link SpecularMaterial#alpha} property. + * + * @type {Texture} + */ + get diffuseMap() { + return this._diffuseMap; + } - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } + /** + * Sets the RGB specular color of this SpecularMaterial. + * + * Multiplies by {@link SpecularMaterial#specularMap} and the *A* component of {@link SpecularMaterial#specularGlossinessMap}. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * + * @type {Number[]} + */ + set specular(value) { + let specular = this._state.specular; + if (!specular) { + specular = this._state.specular = new Float32Array(3); + } else if (value && specular[0] === value[0] && specular[1] === value[1] && specular[2] === value[2]) { + return; } - - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + if (value) { + specular[0] = value[0]; + specular[1] = value[1]; + specular[2] = value[2]; + } else { + specular[0] = 1; + specular[1] = 1; + specular[2] = 1; } + this.glRedraw(); + } - gl.uniform1i(this._uRenderPass, renderPass); + /** + * Gets the RGB specular color of this SpecularMaterial. + * + * @type {Number[]} + */ + get specular() { + return this._state.specular; + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + /** + * Gets the RGB texture containing the specular color of this SpecularMaterial. + * + * Multiplies by {@link SpecularMaterial#specular}. + * + * @type {Texture} + */ + get specularMap() { + return this._specularMap; + } - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + /** + * Gets the RGBA texture containing this SpecularMaterial's specular color in its *RGB* components and glossiness in its *A* component. + * + * The *RGB* components multiplies {@link SpecularMaterial#specular}, while the *A* component multiplies by {@link SpecularMaterial#glossiness}. + * + * @type {Texture} + */ + get specularGlossinessMap() { + return this._specularGlossinessMap; + } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$W); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } + /** + * Sets the Factor in the range [0..1] indicating how glossy this SpecularMaterial is. + * + * ````0```` is no glossiness, ````1```` is full glossiness. + * + * Multiplies by the *R* component of {@link SpecularMaterial#glossinessMap} and the *A* component of {@link SpecularMaterial#specularGlossinessMap}. + * + * Default value is ````1.0````. + * + * @type {Number} + */ + set glossiness(value) { + value = (value !== undefined && value !== null) ? value : 1.0; + if (this._state.glossiness === value) { + return; } + this._state.glossiness = value; + this.glRedraw(); + } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + /** + * Gets the Factor in the range ````[0..1]```` indicating how glossy this SpecularMaterial is. - this._aPosition.bindArrayBuffer(state.positionsBuf); + * @type {Number} + */ + get glossiness() { + return this._state.glossiness; + } - if (this._aNormal) { - this._aNormal.bindArrayBuffer(state.normalsBuf); - } + /** + * Gets the RGB texture containing this SpecularMaterial's glossiness in its *R* component. + * + * The *R* component multiplies by {@link SpecularMaterial#glossiness}. + ** @type {Texture} + */ + get glossinessMap() { + return this._glossinessMap; + } - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); + /** + * Sets the factor in the range ````[0..1]```` indicating amount of specular Fresnel. + * + * Default value is ````0.0````. + * + * @type {Number} + */ + set specularF0(value) { + value = (value !== undefined && value !== null) ? value : 0.0; + if (this._state.specularF0 === value) { + return; } + this._state.specularF0 = value; + this.glRedraw(); + } - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } + /** + * Gets the factor in the range ````[0..1]```` indicating amount of specular Fresnel. + * + * @type {Number} + */ + get specularF0() { + return this._state.specularF0; + } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + /** + * Sets the RGB emissive color of this SpecularMaterial. + * + * Multiplies by {@link SpecularMaterial#emissiveMap}. - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @type {Number[]} + */ + set emissive(value) { + let emissive = this._state.emissive; + if (!emissive) { + emissive = this._state.emissive = new Float32Array(3); + } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) { + return; } - - state.indicesBuf.bind(); - - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - - frameCtx.drawElements++; + if (value) { + emissive[0] = value[0]; + emissive[1] = value[1]; + emissive[2] = value[2]; + } else { + emissive[0] = 0; + emissive[1] = 0; + emissive[2] = 0; + } + this.glRedraw(); } - _allocate() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; + /** + * Gets the RGB emissive color of this SpecularMaterial. + * + * @type {Number[]} + */ + get emissive() { + return this._state.emissive; + } - this._program = new Program(gl, this._buildShader()); + /** + * Gets the RGB texture containing the emissive color of this SpecularMaterial. + * + * Multiplies by {@link SpecularMaterial#emissive}. + * + * @type {Texture} + */ + get emissiveMap() { + return this._emissiveMap; + } - if (this._program.errors) { - this.errors = this._program.errors; + /** + * Sets the factor in the range [0..1] indicating how transparent this SpecularMaterial is. + * + * A value of ````0.0```` is fully transparent, while ````1.0```` is fully opaque. + * + * Multiplies by the *R* component of {@link SpecularMaterial#alphaMap} and the *A* component, if present, of {@link SpecularMaterial#diffuseMap}. + * + * Default value is ````1.0````. + * + * @type {Number} + */ + set alpha(value) { + value = (value !== undefined && value !== null) ? value : 1.0; + if (this._state.alpha === value) { return; } + this._state.alpha = value; + this.glRedraw(); + } - const program = this._program; + /** + * Gets the factor in the range [0..1] indicating how transparent this SpecularMaterial is. + * + * @type {Number} + */ + get alpha() { + return this._state.alpha; + } - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); + /** + * Gets the RGB {@link Texture} with alpha in its *R* component. + * + * The *R* component multiplies by the {@link SpecularMaterial#alpha} property. + * + * @type {Texture} + */ + get alphaMap() { + return this._alphaMap; + } - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; + /** + * Gets the RGB tangent-space normal {@link Texture} attached to this SpecularMaterial. + * + * @type {Texture} + */ + get normalMap() { + return this._normalMap; + } - const lights = lightsState.lights; - let light; + /** + * Gets the RGB ambient occlusion {@link Texture} attached to this SpecularMaterial. + * + * Multiplies by the specular and diffuse light reflected by surfaces. + * + * @type {Texture} + */ + get occlusionMap() { + return this._occlusionMap; + } - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - } + /** + * Sets the alpha rendering mode. + * + * This governs how alpha is treated. Alpha is the combined result of the {@link SpecularMaterial#alpha} and {@link SpecularMaterial#alphaMap} properties. + * + * Accepted values are: + * + * * "opaque" - The alpha value is ignored and the rendered output is fully opaque (default). + * * "mask" - The rendered output is either fully opaque or fully transparent depending on the alpha value and the specified alpha cutoff value. + * * "blend" - The alpha value is used to composite the source and destination areas. The rendered output is combined with the background using the normal painting operation (i.e. the Porter and Duff over operator) + * + * @type {String} + */ + set alphaMode(alphaMode) { + alphaMode = alphaMode || "opaque"; + let value = alphaModes[alphaMode]; + if (value === undefined) { + this.error("Unsupported value for 'alphaMode': " + alphaMode + " defaulting to 'opaque'"); + value = "opaque"; } - - this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); + if (this._state.alphaMode === value) { + return; } + this._state.alphaMode = value; + this.glRedraw(); + } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aNormal = program.getAttribute("normal"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + get alphaMode() { + return alphaModeNames[this._state.alphaMode]; + } - if (this._withSAO) { - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); + /** + * Sets the alpha cutoff value. + * + * Specifies the cutoff threshold when {@link SpecularMaterial#alphaMode} equals "mask". If the alpha is greater than or equal to this value then it is rendered as fully opaque, otherwise, it is rendered as fully transparent. A value greater than 1.0 will render the entire material as fully transparent. This value is ignored for other modes. + * + * Alpha is the combined result of the {@link SpecularMaterial#alpha} and {@link SpecularMaterial#alphaMap} properties. + * + * Default value is ````0.5````. + * + * @type {Number} + */ + set alphaCutoff(alphaCutoff) { + if (alphaCutoff === null || alphaCutoff === undefined) { + alphaCutoff = 0.5; } - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + if (this._state.alphaCutoff === alphaCutoff) { + return; } + this._state.alphaCutoff = alphaCutoff; } - _bindProgram(frameCtx) { - - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const lights = scene._lightsState.lights; - const project = scene.camera.project; - - program.bind(); + /** + * Gets the alpha cutoff value. - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + * @type {Number} + */ + get alphaCutoff() { + return this._state.alphaCutoff; + } - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + /** + * Sets whether backfaces are visible on attached {@link Mesh}es. + * + * The backfaces will belong to {@link ReadableGeometry} compoents that are also attached to the {@link Mesh}es. + * + * Default is ````false````. + * + * @type {Boolean} + */ + set backfaces(value) { + value = !!value; + if (this._state.backfaces === value) { + return; } + this._state.backfaces = value; + this.glRedraw(); + } - for (let i = 0, len = lights.length; i < len; i++) { - - const light = lights[i]; + /** + * Gets whether backfaces are visible on attached {@link Mesh}es. + * + * @type {Boolean} + */ + get backfaces() { + return this._state.backfaces; + } - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); - } - } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } + /** + * Sets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. + * + * Default value is ````"ccw"````. + * + * @type {String} + */ + set frontface(value) { + value = value !== "cw"; + if (this._state.frontface === value) { + return; } + this._state.frontface = value; + this.glRedraw(); + } - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$7[0] = viewportWidth; - tempVec4$7[1] = viewportHeight; - tempVec4$7[2] = sao.blendCutoff; - tempVec4$7[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$7); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); - } - } + /** + * Gets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. + * + * @type {String} + */ + get frontface() { + return this._state.frontface ? "ccw" : "cw"; + } - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + /** + * Sets the SpecularMaterial's line width. + * + * This is not supported by WebGL implementations based on DirectX [2019]. + * + * Default value is ````1.0````. + * + * @type {Number} + */ + set lineWidth(value) { + this._state.lineWidth = value || 1.0; + this.glRedraw(); } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + /** + * Gets the SpecularMaterial's line width. + * + * @type {Number} + */ + get lineWidth() { + return this._state.lineWidth; } - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - let light; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching draw vertex shader"); + /** + * Sets the SpecularMaterial's point size. + * + * Default value is ````1.0````. + * + * @type {Number} + */ + set pointSize(value) { + this._state.pointSize = value || 1; + this.glRedraw(); + } - src.push("uniform int renderPass;"); + /** + * Sets the SpecularMaterial's point size. + * + * @type {Number} + */ + get pointSize() { + return this._state.pointSize; + } - src.push("in vec3 position;"); - src.push("in vec3 normal;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + /** + * Destroys this SpecularMaterial. + */ + destroy() { + super.destroy(); + this._state.destroy(); + } +} - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } +/** + * @private + */ +function convertConstant(gl, constantVal, encoding = null) { - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); + let extension; + const p = constantVal; - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); + if (p === UnsignedByteType) return gl.UNSIGNED_BYTE; + if (p === UnsignedShort4444Type) return gl.UNSIGNED_SHORT_4_4_4_4; + if (p === UnsignedShort5551Type) return gl.UNSIGNED_SHORT_5_5_5_1; - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } + if (p === ByteType) return gl.BYTE; + if (p === ShortType) return gl.SHORT; + if (p === UnsignedShortType) return gl.UNSIGNED_SHORT; + if (p === IntType) return gl.INT; + if (p === UnsignedIntType) return gl.UNSIGNED_INT; + if (p === FloatType) return gl.FLOAT; - src.push("uniform vec4 lightAmbient;"); + if (p === HalfFloatType) { + return gl.HALF_FLOAT; + } - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); - } - } - - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } - src.push("out vec4 vColor;"); - - src.push("void main(void) {"); - - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE - - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - - src.push("} else {"); + if (p === AlphaFormat) return gl.ALPHA; + if (p === RGBAFormat) return gl.RGBA; + if (p === LuminanceFormat) return gl.LUMINANCE; + if (p === LuminanceAlphaFormat) return gl.LUMINANCE_ALPHA; + if (p === DepthFormat) return gl.DEPTH_COMPONENT; + if (p === DepthStencilFormat) return gl.DEPTH_STENCIL; + if (p === RedFormat) return gl.RED; - src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push("worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + if (p === RGBFormat) { + return gl.RGBA; + } - src.push("vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); + // WebGL2 formats. - src.push("vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); + if (p === RedIntegerFormat) return gl.RED_INTEGER; + if (p === RGFormat) return gl.RG; + if (p === RGIntegerFormat) return gl.RG_INTEGER; + if (p === RGBAIntegerFormat) return gl.RGBA_INTEGER; - src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); - src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + // S3TC - src.push("float lambertian = 1.0;"); - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; + if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) { + if (encoding === sRGBEncoding) { + const extension = getExtension(gl, 'WEBGL_compressed_texture_s3tc_srgb'); + if (extension !== null) { + if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; + if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; + if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; + if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; + } else { + return null; } - if (light.type === "dir") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); - } else { - src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } + } else { + extension = getExtension(gl, 'WEBGL_compressed_texture_s3tc'); + if (extension !== null) { + if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; + if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; + if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; + if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; } else { - continue; + return null; } - src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); - src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); } + } - src.push("vec3 rgb = (vec3(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0));"); - src.push("vColor = vec4((lightAmbient.rgb * lightAmbient.a * rgb) + (reflectedColor * rgb), float(color.a) / 255.0);"); + // PVRTC - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) { + const extension = getExtension(gl, 'WEBGL_compressed_texture_pvrtc'); + if (extension !== null) { + if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + } else { + return null; } - src.push("gl_Position = clipPos;"); - src.push("}"); - - src.push("}"); - return src; } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching draw fragment shader"); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); + // ETC1 - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + if (p === RGB_ETC1_Format) { + const extension = getExtension(gl, 'WEBGL_compressed_texture_etc1'); + if (extension !== null) { + return extension.COMPRESSED_RGB_ETC1_WEBGL; + } else { + return null; } + } - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + // ETC2 - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } + if (p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format) { + const extension = getExtension(gl, 'WEBGL_compressed_texture_etc'); + if (extension !== null) { + if (p === RGB_ETC2_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; + if (p === RGBA_ETC2_EAC_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; + } else { + return null; } - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); + } - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - src.push("}"); - } + // ASTC - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + if (p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || + p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || + p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || + p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || + p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) { + const extension = getExtension(gl, 'WEBGL_compressed_texture_astc'); + if (extension !== null) { + if (p === RGBA_ASTC_4x4_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; + if (p === RGBA_ASTC_5x4_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; + if (p === RGBA_ASTC_5x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; + if (p === RGBA_ASTC_6x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; + if (p === RGBA_ASTC_6x6_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; + if (p === RGBA_ASTC_8x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; + if (p === RGBA_ASTC_8x6_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; + if (p === RGBA_ASTC_8x8_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; + if (p === RGBA_ASTC_10x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; + if (p === RGBA_ASTC_10x6_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; + if (p === RGBA_ASTC_10x8_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; + if (p === RGBA_ASTC_10x10_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; + if (p === RGBA_ASTC_12x10_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; + if (p === RGBA_ASTC_12x12_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; + } else { + return null; } + } - if (this._withSAO) { - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" outColor = vec4(vColor.rgb * ambient, 1.0);"); + // BPTC + + if (p === RGBA_BPTC_Format) { + const extension = getExtension(gl, 'EXT_texture_compression_bptc'); + if (extension !== null) { + if (p === RGBA_BPTC_Format) { + return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + } } else { - src.push(" outColor = vColor;"); + return null; } - - src.push("}"); - return src; } - webglContextRestored() { - this._program = null; - } + // - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + if (p === UnsignedInt248Type) { + return gl.UNSIGNED_INT_24_8; + } + if (p === RepeatWrapping) { + return gl.REPEAT; + } + if (p === ClampToEdgeWrapping) { + return gl.CLAMP_TO_EDGE; + } + if (p === NearestMipMapNearestFilter) { + return gl.NEAREST_MIPMAP_LINEAR; + } + if (p === NearestMipMapLinearFilter) { + return gl.NEAREST_MIPMAP_LINEAR; + } + if (p === LinearMipMapNearestFilter) { + return gl.LINEAR_MIPMAP_NEAREST; + } + if (p === LinearMipMapLinearFilter) { + return gl.LINEAR_MIPMAP_LINEAR; } + if (p === NearestFilter) { + return gl.NEAREST; + } + if (p === LinearFilter) { + return gl.LINEAR; + } + + return null; } -const tempVec4$6 = math.vec4(); -const tempVec3a$V = math.vec3(); +const color$2 = new Uint8Array([0, 0, 0, 1]); /** + * @desc A low-level component that represents a 2D WebGL texture. + * * @private */ -class TrianglesBatchingFlatColorRenderer { +class Texture2D { - constructor(scene, withSAO) { - this._scene = scene; - this._withSAO = withSAO; - this._hash = this._getHash(); - this._allocate(); - } + constructor({gl, target, format, type, wrapS, wrapT, wrapR, encoding, preloadColor, premultiplyAlpha, flipY}) { - getValid() { - return this._hash === this._getHash(); - }; + this.gl = gl; - _getHash() { - const scene = this._scene; - return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); - } + this.target = target || gl.TEXTURE_2D; + this.format = format || RGBAFormat; + this.type = type || UnsignedByteType; + this.internalFormat = null; + this.premultiplyAlpha = !!premultiplyAlpha; + this.flipY = !!flipY; + this.unpackAlignment = 4; + this.wrapS = wrapS || RepeatWrapping; + this.wrapT = wrapT || RepeatWrapping; + this.wrapR = wrapR || RepeatWrapping; + this.encoding = encoding || sRGBEncoding; + this.texture = gl.createTexture(); - drawLayer(frameCtx, batchingLayer, renderPass) { + if (preloadColor) { + this.setPreloadColor(preloadColor); // Prevents "there is no texture bound to the unit 0" error + } - const scene = this._scene; - const camera = scene.camera; - const model = batchingLayer.model; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; + this.allocated = true; + } - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } + setPreloadColor(value) { + if (!value) { + color$2[0] = 0; + color$2[1] = 0; + color$2[2] = 0; + color$2[3] = 255; + } else { + color$2[0] = Math.floor(value[0] * 255); + color$2[1] = Math.floor(value[1] * 255); + color$2[2] = Math.floor(value[2] * 255); + color$2[3] = Math.floor((value[3] !== undefined ? value[3] : 1) * 255); } - - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + const gl = this.gl; + gl.bindTexture(this.target, this.texture); + if (this.target === gl.TEXTURE_CUBE_MAP) { + const faces = [ + gl.TEXTURE_CUBE_MAP_POSITIVE_X, + gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ]; + for (let i = 0, len = faces.length; i < len; i++) { + gl.texImage2D(faces[i], 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, color$2); + } + } else { + gl.texImage2D(this.target, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, color$2); } + gl.bindTexture(this.target, null); + } - gl.uniform1i(this._uRenderPass, renderPass); + setTarget(target) { + this.target = target || this.gl.TEXTURE_2D; + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + setImage(image, props = {}) { - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + const gl = this.gl; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$V); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } + if (props.format !== undefined) { + this.format = props.format; } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - - this._aPosition.bindArrayBuffer(state.positionsBuf); - - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); + if (props.internalFormat !== undefined) { + this.internalFormat = props.internalFormat; } - - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); + if (props.encoding !== undefined) { + this.encoding = props.encoding; } - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + if (props.type !== undefined) { + this.type = props.type; } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); + if (props.flipY !== undefined) { + this.flipY = props.flipY; } - - state.indicesBuf.bind(); - - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - } - - _allocate() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; - - this._program = new Program(gl, this._buildShader()); - - if (this._program.errors) { - this.errors = this._program.errors; - return; + if (props.premultiplyAlpha !== undefined) { + this.premultiplyAlpha = props.premultiplyAlpha; } - - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; - - const lights = lightsState.lights; - let light; - - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - } + if (props.unpackAlignment !== undefined) { + this.unpackAlignment = props.unpackAlignment; } - - this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); + if (props.minFilter !== undefined) { + this.minFilter = props.minFilter; } - - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - - if (this._withSAO) { - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); + if (props.magFilter !== undefined) { + this.magFilter = props.magFilter; } - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + if (props.wrapS !== undefined) { + this.wrapS = props.wrapS; + } + if (props.wrapT !== undefined) { + this.wrapT = props.wrapT; + } + if (props.wrapR !== undefined) { + this.wrapR = props.wrapR; } - } - - _bindProgram(frameCtx) { - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const lights = scene._lightsState.lights; - const project = scene.camera.project; + let generateMipMap = false; - program.bind(); + gl.bindTexture(this.target, this.texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flipY); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, this.unpackAlignment); + gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + const minFilter = convertConstant(gl, this.minFilter); + gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, minFilter); - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + if (minFilter === gl.NEAREST_MIPMAP_NEAREST + || minFilter === gl.LINEAR_MIPMAP_NEAREST + || minFilter === gl.NEAREST_MIPMAP_LINEAR + || minFilter === gl.LINEAR_MIPMAP_LINEAR) { + generateMipMap = true; } - for (let i = 0, len = lights.length; i < len; i++) { + const magFilter = convertConstant(gl, this.magFilter); + if (magFilter) { + gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, magFilter); + } - const light = lights[i]; + const wrapS = convertConstant(gl, this.wrapS); + if (wrapS) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS); + } - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); - } - } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } + const wrapT = convertConstant(gl, this.wrapT); + if (wrapT) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT); } - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$6[0] = viewportWidth; - tempVec4$6[1] = viewportHeight; - tempVec4$6[2] = sao.blendCutoff; - tempVec4$6[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$6); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + const glFormat = convertConstant(gl, this.format, this.encoding); + const glType = convertConstant(gl, this.type); + const glInternalFormat = getInternalFormat(gl, this.internalFormat, glFormat, glType, this.encoding, false); + + if (this.target === gl.TEXTURE_CUBE_MAP) { + if (utils.isArray(image)) { + const images = image; + const faces = [ + gl.TEXTURE_CUBE_MAP_POSITIVE_X, + gl.TEXTURE_CUBE_MAP_NEGATIVE_X, + gl.TEXTURE_CUBE_MAP_POSITIVE_Y, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, + gl.TEXTURE_CUBE_MAP_POSITIVE_Z, + gl.TEXTURE_CUBE_MAP_NEGATIVE_Z + ]; + for (let i = 0, len = faces.length; i < len; i++) { + gl.texImage2D(faces[i], 0, glInternalFormat, glFormat, glType, images[i]); + } } + } else { + gl.texImage2D(gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image); } - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + if (generateMipMap) { + gl.generateMipmap(this.target); } - } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + gl.bindTexture(this.target, null); } - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching flat-shading draw vertex shader"); + setCompressedData({mipmaps, props = {}}) { - src.push("uniform int renderPass;"); + const gl = this.gl; + const levels = mipmaps.length; - src.push("in vec3 position;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + // Cache props - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); + if (props.format !== undefined) { + this.format = props.format; } - - src.push("uniform mat4 worldMatrix;"); - - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); + if (props.internalFormat !== undefined) { + this.internalFormat = props.internalFormat; } - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); + if (props.encoding !== undefined) { + this.encoding = props.encoding; } - src.push("out vec4 vViewPosition;"); - src.push("out vec4 vColor;"); - - src.push("void main(void) {"); - - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE - - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - - src.push("} else {"); - - src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push("worldPosition.xyz = worldPosition.xyz + offset;"); + if (props.type !== undefined) { + this.type = props.type; } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vViewPosition = viewPosition;"); - src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); - - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + if (props.flipY !== undefined) { + this.flipY = props.flipY; } - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + if (props.premultiplyAlpha !== undefined) { + this.premultiplyAlpha = props.premultiplyAlpha; + } + if (props.unpackAlignment !== undefined) { + this.unpackAlignment = props.unpackAlignment; + } + if (props.minFilter !== undefined) { + this.minFilter = props.minFilter; + } + if (props.magFilter !== undefined) { + this.magFilter = props.magFilter; + } + if (props.wrapS !== undefined) { + this.wrapS = props.wrapS; + } + if (props.wrapT !== undefined) { + this.wrapT = props.wrapT; + } + if (props.wrapR !== undefined) { + this.wrapR = props.wrapR; } - src.push("gl_Position = clipPos;"); - src.push("}"); - - src.push("}"); - return src; - } - _buildFragmentShader() { - const scene = this._scene; - const lightsState = scene._lightsState; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching flat-shading draw fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); + gl.activeTexture(gl.TEXTURE0 + 0); + gl.bindTexture(this.target, this.texture); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } + let supportsMips = mipmaps.length > 1; - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flipY); + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); + gl.pixelStorei(gl.UNPACK_ALIGNMENT, this.unpackAlignment); + gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + const wrapS = convertConstant(gl, this.wrapS); + if (wrapS) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS); + } - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); + const wrapT = convertConstant(gl, this.wrapT); + if (wrapT) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT); } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); + if (this.type === gl.TEXTURE_3D || this.type === gl.TEXTURE_2D_ARRAY) { + const wrapR = convertConstant(gl, this.wrapR); + if (wrapR) { + gl.texParameteri(this.target, gl.TEXTURE_WRAP_R, wrapR); } + gl.texParameteri(this.type, gl.TEXTURE_WRAP_R, wrapR); } - src.push("uniform mat4 viewMatrix;"); + if (supportsMips) { + gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, filterFallback(gl, this.minFilter)); + gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, filterFallback(gl, this.magFilter)); - src.push("uniform vec4 lightAmbient;"); - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); - } + } else { + gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, convertConstant(gl, this.minFilter)); + gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, convertConstant(gl, this.magFilter)); } - src.push("in vec4 vViewPosition;"); - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); + const glFormat = convertConstant(gl, this.format, this.encoding); + const glType = convertConstant(gl, this.type); + const glInternalFormat = getInternalFormat(gl, this.internalFormat, glFormat, glType, this.encoding, false); - src.push("void main(void) {"); + gl.texStorage2D(gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + for (let i = 0, len = mipmaps.length; i < len; i++) { + + const mipmap = mipmaps[i]; + + if (this.format !== RGBAFormat) { + if (glFormat !== null) { + gl.compressedTexSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); + } else { + console.warn('Attempt to load unsupported compressed texture format in .setCompressedData()'); + } + } else { + gl.texSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); } - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - src.push("}"); } - src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); - src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + // if (generateMipMap) { + // // gl.generateMipmap(this.target); // Only for roughness textures? + // } - src.push("float lambertian = 1.0;"); + gl.bindTexture(this.target, null); + } - src.push("vec3 xTangent = dFdx( vViewPosition.xyz );"); - src.push("vec3 yTangent = dFdy( vViewPosition.xyz );"); - src.push("vec3 viewNormal = normalize( cross( xTangent, yTangent ) );"); + setProps(props) { + const gl = this.gl; + gl.bindTexture(this.target, this.texture); + this._uploadProps(props); + gl.bindTexture(this.target, null); + } - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - if (light.type === "dir") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); - } else { - src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + _uploadProps(props) { + const gl = this.gl; + if (props.format !== undefined) { + this.format = props.format; + } + if (props.internalFormat !== undefined) { + this.internalFormat = props.internalFormat; + } + if (props.encoding !== undefined) { + this.encoding = props.encoding; + } + if (props.type !== undefined) { + this.type = props.type; + } + if (props.minFilter !== undefined) { + const minFilter = convertConstant(gl, props.minFilter); + if (minFilter) { + this.minFilter = props.minFilter; + gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, minFilter); + if (minFilter === gl.NEAREST_MIPMAP_NEAREST || minFilter === gl.LINEAR_MIPMAP_NEAREST || minFilter === gl.NEAREST_MIPMAP_LINEAR || minFilter === gl.LINEAR_MIPMAP_LINEAR) { + gl.generateMipmap(this.target); } - } else { - continue; } - - src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); - src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); } - - src.push("vec4 fragColor = vec4((lightAmbient.rgb * lightAmbient.a * vColor.rgb) + (reflectedColor * vColor.rgb), vColor.a);"); - - if (this._withSAO) { - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" outColor = vec4(fragColor.rgb * ambient, 1.0);"); - } else { - src.push(" outColor = fragColor;"); + if (props.magFilter !== undefined) { + const magFilter = convertConstant(gl, props.magFilter); + if (magFilter) { + this.magFilter = props.magFilter; + gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, magFilter); + } } - - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + if (props.wrapS !== undefined) { + const wrapS = convertConstant(gl, props.wrapS); + if (wrapS) { + this.wrapS = props.wrapS; + gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS); + } + } + if (props.wrapT !== undefined) { + const wrapT = convertConstant(gl, props.wrapT); + if (wrapT) { + this.wrapT = props.wrapT; + gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT); + } } + } - src.push("}"); - return src; + bind(unit) { + if (!this.allocated) { + return; + } + if (this.texture) { + const gl = this.gl; + gl.activeTexture(gl["TEXTURE" + unit]); + gl.bindTexture(this.target, this.texture); + return true; + } + return false; } - webglContextRestored() { - this._program = null; + unbind(unit) { + if (!this.allocated) { + return; + } + if (this.texture) { + const gl = this.gl; + gl.activeTexture(gl["TEXTURE" + unit]); + gl.bindTexture(this.target, null); + } } destroy() { - if (this._program) { - this._program.destroy(); + if (!this.allocated) { + return; + } + if (this.texture) { + this.gl.deleteTexture(this.texture); + this.texture = null; } - this._program = null; } } -const defaultColor$4 = new Float32Array([1, 1, 1]); -const tempVec3a$U = math.vec3(); - -/** - * @private - */ -class TrianglesBatchingSilhouetteRenderer { +function getInternalFormat(gl, internalFormatName, glFormat, glType, encoding, isVideoTexture = false) { + if (internalFormatName !== null) { + if (gl[internalFormatName] !== undefined) { + return gl[internalFormatName]; + } + console.warn('Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\''); + } + let internalFormat = glFormat; + if (glFormat === gl.RED) { + if (glType === gl.FLOAT) internalFormat = gl.R32F; + if (glType === gl.HALF_FLOAT) internalFormat = gl.R16F; + if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.R8; + } + if (glFormat === gl.RG) { + if (glType === gl.FLOAT) internalFormat = gl.RG32F; + if (glType === gl.HALF_FLOAT) internalFormat = gl.RG16F; + if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.RG8; + } + if (glFormat === gl.RGBA) { + if (glType === gl.FLOAT) internalFormat = gl.RGBA32F; + if (glType === gl.HALF_FLOAT) internalFormat = gl.RGBA16F; + if (glType === gl.UNSIGNED_BYTE) internalFormat = (encoding === sRGBEncoding && isVideoTexture === false) ? gl.SRGB8_ALPHA8 : gl.RGBA8; + if (glType === gl.UNSIGNED_SHORT_4_4_4_4) internalFormat = gl.RGBA4; + if (glType === gl.UNSIGNED_SHORT_5_5_5_1) internalFormat = gl.RGB5_A1; + } + if (internalFormat === gl.R16F || internalFormat === gl.R32F || + internalFormat === gl.RG16F || internalFormat === gl.RG32F || + internalFormat === gl.RGBA16F || internalFormat === gl.RGBA32F) { + getExtension(gl, 'EXT_color_buffer_float'); + } + return internalFormat; +} - constructor(scene, primitiveType) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); +function filterFallback(gl, f) { + if (f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter) { + return gl.NEAREST; } + return gl.LINEAR; - getValid() { - return this._hash === this._getHash(); - }; +} - _getHash() { - return this._scene._sectionPlanesState.getHash(); +function ensureImageSizePowerOfTwo$1(image) { + if (!isPowerOfTwo$1(image.width) || !isPowerOfTwo$1(image.height)) { + const canvas = document.createElement("canvas"); + canvas.width = nextHighestPowerOfTwo$1(image.width); + canvas.height = nextHighestPowerOfTwo$1(image.height); + const ctx = canvas.getContext("2d"); + ctx.drawImage(image, + 0, 0, image.width, image.height, + 0, 0, canvas.width, canvas.height); + image = canvas; } + return image; +} - drawLayer(frameCtx, batchingLayer, renderPass) { - - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; +function isPowerOfTwo$1(x) { + return (x & (x - 1)) === 0; +} - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } - } +function nextHighestPowerOfTwo$1(x) { + --x; + for (let i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; +} - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); - } +/** + * @desc A 2D texture map. + * + * * Textures are attached to {@link Material}s, which are attached to {@link Mesh}es. + * * To create a Texture from an image file, set {@link Texture#src} to the image file path. + * * To create a Texture from an HTMLImageElement, set the Texture's {@link Texture#image} to the HTMLImageElement. + * + * ## Usage + * + * In this example we have a Mesh with a {@link PhongMaterial} which applies diffuse {@link Texture}, and a {@link buildTorusGeometry} which builds a {@link ReadableGeometry}. + * + * Note that xeokit will ignore {@link PhongMaterial#diffuse} and {@link PhongMaterial#specular}, since we override those + * with {@link PhongMaterial#diffuseMap} and {@link PhongMaterial#specularMap}. The {@link Texture} pixel colors directly + * provide the diffuse and specular components for each fragment across the {@link ReadableGeometry} surface. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_Texture)] + * + * ```` javascript + * import {Viewer, Mesh, buildTorusGeometry, + * ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [0, 0, 5]; + * viewer.camera.look = [0, 0, 0]; + * viewer.camera.up = [0, 1, 0]; + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ + * center: [0, 0, 0], + * radius: 1.5, + * tube: 0.5, + * radialSegments: 32, + * tubeSegments: 24, + * arc: Math.PI * 2.0 + * }), + * material: new PhongMaterial(viewer.scene, { + * ambient: [0.9, 0.3, 0.9], + * shininess: 30, + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }) + * }) + * }); + *```` + */ +class Texture extends Component { - gl.uniform1i(this._uRenderPass, renderPass); + /** + @private + */ + get type() { + return "Texture"; + } - if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { - const material = scene.xrayMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this Texture as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for this Texture, unique among all components in the parent scene, generated automatically when omitted. + * @param {String} [cfg.src=null] Path to image file to load into this Texture. See the {@link Texture#src} property for more info. + * @param {HTMLImageElement} [cfg.image=null] HTML Image object to load into this Texture. See the {@link Texture#image} property for more info. + * @param {Number} [cfg.minFilter=LinearMipmapLinearFilter] How the texture is sampled when a texel covers less than one pixel. + * Supported values are {@link LinearMipmapLinearFilter}, {@link LinearMipMapNearestFilter}, {@link NearestMipMapNearestFilter}, {@link NearestMipMapLinearFilter} and {@link LinearMipMapLinearFilter}. + * @param {Number} [cfg.magFilter=LinearFilter] How the texture is sampled when a texel covers more than one pixel. Supported values are {@link LinearFilter} and {@link NearestFilter}. + * @param {Number} [cfg.wrapS=RepeatWrapping] Wrap parameter for texture coordinate *S*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. + * @param {Number} [cfg.wrapT=RepeatWrapping] Wrap parameter for texture coordinate *T*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}.. + * @param {Boolean} [cfg.flipY=false] Flips this Texture's source data along its vertical axis when ````true````. + * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. + * @param {Number[]} [cfg.translate=[0,0]] 2D translation vector that will be added to texture's *S* and *T* coordinates. + * @param {Number[]} [cfg.scale=[1,1]] 2D scaling vector that will be applied to texture's *S* and *T* coordinates. + * @param {Number} [cfg.rotate=0] Rotation, in degrees, that will be applied to texture's *S* and *T* coordinates. + */ + constructor(owner, cfg = {}) { - } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + super(owner, cfg); - } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { - const material = scene.selectedMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + this._state = new RenderState({ + texture: new Texture2D({gl: this.scene.canvas.gl}), + matrix: math.identityMat4(), + hasMatrix: (cfg.translate && (cfg.translate[0] !== 0 || cfg.translate[1] !== 0)) || (!!cfg.rotate) || (cfg.scale && (cfg.scale[0] !== 0 || cfg.scale[1] !== 0)), + minFilter: this._checkMinFilter(cfg.minFilter), + magFilter: this._checkMagFilter(cfg.magFilter), + wrapS: this._checkWrapS(cfg.wrapS), + wrapT: this._checkWrapT(cfg.wrapT), + flipY: this._checkFlipY(cfg.flipY), + encoding: this._checkEncoding(cfg.encoding) + }); - } else { - gl.uniform4fv(this._uColor, defaultColor$4); - } + // Data source - const viewMat = (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix; - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMat); + this._src = null; + this._image = null; - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + // Transformation - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$U); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + this._translate = math.vec2([0, 0]); + this._scale = math.vec2([1, 1]); + this._rotate = math.vec2([0, 0]); - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + this._matrixDirty = false; - this._aPosition.bindArrayBuffer(state.positionsBuf); + // Transform - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + this.translate = cfg.translate; + this.scale = cfg.scale; + this.rotate = cfg.rotate; - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } + // Data source - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + if (cfg.src) { + this.src = cfg.src; // Image file + } else if (cfg.image) { + this.image = cfg.image; // Image object } - state.indicesBuf.bind(); - - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + stats.memory.textures++; } - _allocate() { - - const scene = this._scene; - const gl = scene.canvas.gl; - - this._program = new Program(gl, this._buildShader()); - - if (this._program.errors) { - this.errors = this._program.errors; - return; + _checkMinFilter(value) { + value = value || LinearMipMapLinearFilter; + if (value !== LinearFilter && + value !== LinearMipMapNearestFilter && + value !== LinearMipMapLinearFilter && + value !== NearestMipMapLinearFilter && + value !== NearestMipMapNearestFilter) { + this.error("Unsupported value for 'minFilter' - supported values are LinearFilter, LinearMipMapNearestFilter, NearestMipMapNearestFilter, " + + "NearestMipMapLinearFilter and LinearMipMapLinearFilter. Defaulting to LinearMipMapLinearFilter."); + value = LinearMipMapLinearFilter; } + return value; + } - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uColor = program.getLocation("color"); - this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); + _checkMagFilter(value) { + value = value || LinearFilter; + if (value !== LinearFilter && value !== NearestFilter) { + this.error("Unsupported value for 'magFilter' - supported values are LinearFilter and NearestFilter. Defaulting to LinearFilter."); + value = LinearFilter; } + return value; + } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + _checkWrapS(value) { + value = value || RepeatWrapping; + if (value !== ClampToEdgeWrapping && value !== MirroredRepeatWrapping && value !== RepeatWrapping) { + this.error("Unsupported value for 'wrapS' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping."); + value = RepeatWrapping; } + return value; } - _bindProgram() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; - - this._program.bind(); - - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + _checkWrapT(value) { + value = value || RepeatWrapping; + if (value !== ClampToEdgeWrapping && value !== MirroredRepeatWrapping && value !== RepeatWrapping) { + this.error("Unsupported value for 'wrapT' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping."); + value = RepeatWrapping; } + return value; } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + _checkFlipY(value) { + return !!value; } - _buildVertexShader() { - - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching silhouette vertex shader"); - - src.push("uniform int renderPass;"); - - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform vec4 color;"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); + _checkEncoding(value) { + value = value || LinearEncoding; + if (value !== LinearEncoding && value !== sRGBEncoding) { + this.error("Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); + value = LinearEncoding; } + return value; + } - src.push("void main(void) {"); - - // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | SILHOUETTE_XRAYED - // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - - src.push(`if (int(flags.y) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + _webglContextRestored() { + this._state.texture = new Texture2D({gl: this.scene.canvas.gl}); + if (this._image) { + this.image = this._image; + } else if (this._src) { + this.src = this._src; } - src.push("gl_Position = clipPos;"); - src.push("}"); - src.push("}"); - return src; } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - let i; - let len; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching silhouette fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); + _update() { + const state = this._state; + if (this._matrixDirty) { + let matrix; + let t; + if (this._translate[0] !== 0 || this._translate[1] !== 0) { + matrix = math.translationMat4v([this._translate[0], this._translate[1], 0], this._state.matrix); } - } - src.push("uniform vec4 color;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + if (this._scale[0] !== 1 || this._scale[1] !== 1) { + t = math.scalingMat4v([this._scale[0], this._scale[1], 1]); + matrix = matrix ? math.mulMat4(matrix, t) : t; } - src.push(" if (dist > 0.0) { discard; }"); - src.push("}"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + if (this._rotate !== 0) { + t = math.rotationMat4v(this._rotate * 0.0174532925, [0, 0, 1]); + matrix = matrix ? math.mulMat4(matrix, t) : t; + } + if (matrix) { + state.matrix = matrix; + } + this._matrixDirty = false; } - src.push("outColor = color;"); - src.push("}"); - return src; + this.glRedraw(); } - webglContextRestored() { - this._program = null; - } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + /** + * Sets an HTML DOM Image object to source this Texture from. + * + * Sets {@link Texture#src} null. + * + * @type {HTMLImageElement} + */ + set image(value) { + this._image = ensureImageSizePowerOfTwo$1(value); + this._image.crossOrigin = "Anonymous"; + this._state.texture.setImage(this._image, this._state); + this._src = null; + this.glRedraw(); } -} - -const tempVec3a$T = math.vec3(); -const defaultColor$3 = new Float32Array([0,0,0,1]); -/** - * @private - */ -class TrianglesBatchingEdgesRenderer { + /** + * Gets HTML DOM Image object this Texture is sourced from, if any. + * + * Returns null if not set. + * + * @type {HTMLImageElement} + */ + get image() { + return this._image; + } - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); + /** + * Sets path to an image file to source this Texture from. + * + * Sets {@link Texture#image} null. + * + * @type {String} + */ + set src(src) { + this.scene.loading++; + this.scene.canvas.spinner.processes++; + const self = this; + let image = new Image(); + image.onload = function () { + image = ensureImageSizePowerOfTwo$1(image); + self._state.texture.setImage(image, self._state); + self.scene.loading--; + self.glRedraw(); + self.scene.canvas.spinner.processes--; + }; + image.src = src; + this._src = src; + this._image = null; } - getValid() { - return this._hash === this._getHash(); - }; + /** + * Gets path to the image file this Texture from, if any. + * + * Returns null if not set. + * + * @type {String} + */ + get src() { + return this._src; + } - _getHash() { - return this._scene._sectionPlanesState.getHash(); + /** + * Sets the 2D translation vector added to this Texture's *S* and *T* UV coordinates. + * + * Default value is ````[0, 0]````. + * + * @type {Number[]} + */ + set translate(value) { + this._translate.set(value || [0, 0]); + this._matrixDirty = true; + this._needUpdate(); } - drawLayer(frameCtx, batchingLayer, renderPass) { + /** + * Gets the 2D translation vector added to this Texture's *S* and *T* UV coordinates. + * + * Default value is ````[0, 0]````. + * + * @type {Number[]} + */ + get translate() { + return this._translate; + } - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; + /** + * Sets the 2D scaling vector that will be applied to this Texture's *S* and *T* UV coordinates. + * + * Default value is ````[1, 1]````. + * + * @type {Number[]} + */ + set scale(value) { + this._scale.set(value || [1, 1]); + this._matrixDirty = true; + this._needUpdate(); + } - if (!this._program) { - this._allocate(batchingLayer); - if (this.errors) { - return; - } - } + /** + * Gets the 2D scaling vector that will be applied to this Texture's *S* and *T* UV coordinates. + * + * Default value is ````[1, 1]````. + * + * @type {Number[]} + */ + get scale() { + return this._scale; + } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + /** + * Sets the rotation angles, in degrees, that will be applied to this Texture's *S* and *T* UV coordinates. + * + * Default value is ````0````. + * + * @type {Number} + */ + set rotate(value) { + value = value || 0; + if (this._rotate === value) { + return; } + this._rotate = value; + this._matrixDirty = true; + this._needUpdate(); + } - gl.uniform1i(this._uRenderPass, renderPass); - - if (renderPass === RENDER_PASSES.EDGES_XRAYED) { - const material = scene.xrayMaterial._state; - const edgeColor = material.edgeColor; - const edgeAlpha = material.edgeAlpha; - gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); + /** + * Gets the rotation angles, in degrees, that will be applied to this Texture's *S* and *T* UV coordinates. + * + * Default value is ````0````. + * + * @type {Number} + */ + get rotate() { + return this._rotate; + } - } else if (renderPass === RENDER_PASSES.EDGES_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const edgeColor = material.edgeColor; - const edgeAlpha = material.edgeAlpha; - gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); + /** + * Gets how this Texture is sampled when a texel covers less than one pixel. + * + * Options are: + * + * * NearestFilter - Uses the value of the texture element that is nearest + * (in Manhattan distance) to the center of the pixel being textured. + * + * * LinearFilter - Uses the weighted average of the four texture elements that are + * closest to the center of the pixel being textured. + * + * * NearestMipMapNearestFilter - Chooses the mipmap that most closely matches the + * size of the pixel being textured and uses the "nearest" criterion (the texture + * element nearest to the center of the pixel) to produce a texture value. + * + * * LinearMipMapNearestFilter - Chooses the mipmap that most closely matches the size of + * the pixel being textured and uses the "linear" criterion (a weighted average of the + * four texture elements that are closest to the center of the pixel) to produce a + * texture value. + * + * * NearestMipMapLinearFilter - Chooses the two mipmaps that most closely + * match the size of the pixel being textured and uses the "nearest" criterion + * (the texture element nearest to the center of the pixel) to produce a texture + * value from each mipmap. The final texture value is a weighted average of those two + * values. + * + * * LinearMipMapLinearFilter - (default) - Chooses the two mipmaps that most closely match the size + * of the pixel being textured and uses the "linear" criterion (a weighted average + * of the four texture elements that are closest to the center of the pixel) to + * produce a texture value from each mipmap. The final texture value is a weighted + * average of those two values. + * + * Default value is LinearMipMapLinearFilter. + * + * @type {Number} + */ + get minFilter() { + return this._state.minFilter; + } - } else if (renderPass === RENDER_PASSES.EDGES_SELECTED) { - const material = scene.selectedMaterial._state; - const edgeColor = material.edgeColor; - const edgeAlpha = material.edgeAlpha; - gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); + /** + * Gets how this Texture is sampled when a texel covers more than one pixel. + * + * * NearestFilter - Uses the value of the texture element that is nearest + * (in Manhattan distance) to the center of the pixel being textured. + * * LinearFilter - (default) - Uses the weighted average of the four texture elements that are + * closest to the center of the pixel being textured. + * + * Default value is LinearMipMapLinearFilter. + * + * @type {Number} + */ + get magFilter() { + return this._state.magFilter; + } - } else { - gl.uniform4fv(this._uColor, defaultColor$3); - } + /** + * Gets the wrap parameter for this Texture's *S* coordinate. + * + * Values can be: + * + * * ClampToEdgeWrapping - causes *S* coordinates to be clamped to the size of the texture. + * * MirroredRepeatWrapping - causes the *S* coordinate to be set to the fractional part of the texture coordinate + * if the integer part of *S* is even; if the integer part of *S* is odd, then the *S* texture coordinate is + * set to *1 - frac ⁡ S* , where *frac ⁡ S* represents the fractional part of *S*. + * * RepeatWrapping - (default) - causes the integer part of the *S* coordinate to be ignored; xeokit uses only the + * fractional part, thereby creating a repeating pattern. + * + * Default value is RepeatWrapping. + * + * @type {Number} + */ + get wrapS() { + return this._state.wrapS; + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + /** + * Gets the wrap parameter for this Texture's *T* coordinate. + * + * Values can be: + * + * * ClampToEdgeWrapping - causes *S* coordinates to be clamped to the size of the texture. + * * MirroredRepeatWrapping - causes the *S* coordinate to be set to the fractional part of the texture coordinate + * if the integer part of *S* is even; if the integer part of *S* is odd, then the *S* texture coordinate is + * set to *1 - frac ⁡ S* , where *frac ⁡ S* represents the fractional part of *S*. + * * RepeatWrapping - (default) - causes the integer part of the *S* coordinate to be ignored; xeokit uses only the + * fractional part, thereby creating a repeating pattern. + * + * Default value is RepeatWrapping. + * + * @type {Number} + */ + get wrapT() { + return this._state.wrapT; + } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$T); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + /** + * Gets if this Texture's source data is flipped along its vertical axis. + * + * @type {Number} + */ + get flipY() { + return this._state.flipY; + } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + /** + * Gets the Texture's encoding format. + * + * @type {Number} + */ + get encoding() { + return this._state.encoding; + } - this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + /** + * Destroys this Texture + */ + destroy() { + super.destroy(); + if (this._state.texture) { + this._state.texture.destroy(); } - state.edgeIndicesBuf.bind(); - - gl.drawElements(gl.LINES, state.edgeIndicesBuf.numItems, state.edgeIndicesBuf.itemType, 0); + this._state.destroy(); + stats.memory.textures--; } +} - _allocate() { - - const scene = this._scene; - const gl = scene.canvas.gl; - - this._program = new Program(gl, this._buildShader()); +/** + * @desc Configures Fresnel effects for {@link PhongMaterial}s. + * + * Fresnels are attached to {@link PhongMaterial}s, which are attached to {@link Mesh}es. + * + * ## Usage + * + * In the example below we'll create a {@link Mesh} with a {@link PhongMaterial} that applies a Fresnel to its alpha channel to give a glasss-like effect. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_Fresnel)] + * + * ````javascript + * import {Viewer, Mesh, buildTorusGeometry, + * ReadableGeometry, PhongMaterial, Texture, Fresnel} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [0, 0, 5]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ + * center: [0, 0, 0], + * radius: 1.5, + * tube: 0.5, + * radialSegments: 32, + * tubeSegments: 24, + * arc: Math.PI * 2.0 + * }), + * material: new PhongMaterial(viewer.scene, { + * alpha: 0.9, + * alphaMode: "blend", + * ambient: [0.0, 0.0, 0.0], + * shininess: 30, + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }), + * alphaFresnel: new Fresnel(viewer.scene, { +v edgeBias: 0.2, + * centerBias: 0.8, + * edgeColor: [1.0, 1.0, 1.0], + * centerColor: [0.0, 0.0, 0.0], + * power: 2 + * }) + * }) + * }); + * ```` + */ +class Fresnel extends Component { - if (this._program.errors) { - this.errors = this._program.errors; - return; - } + /** + * JavaScript class name for this Component. + * + * @type {String} + */ + get type() { + return "Fresnel"; + } - const program = this._program; + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this Fresnel as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent scene, generated automatically when omitted. + * @param {Number[]} [cfg.edgeColor=[ 0.0, 0.0, 0.0 ]] Color used on edges. + * @param {Number[]} [cfg.centerColor=[ 1.0, 1.0, 1.0 ]] Color used on center. + * @param {Number} [cfg.edgeBias=0] Bias at the edge. + * @param {Number} [cfg.centerBias=1] Bias at the center. + * @param {Number} [cfg.power=0] The power. + */ + constructor(owner, cfg = {}) { - this._uRenderPass = program.getLocation("renderPass"); - this._uColor = program.getLocation("color"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; + super(owner, cfg); - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + this._state = new RenderState({ + edgeColor: math.vec3([0, 0, 0]), + centerColor: math.vec3([1, 1, 1]), + edgeBias: 0, + centerBias: 1, + power: 1 + }); - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + this.edgeColor = cfg.edgeColor; + this.centerColor = cfg.centerColor; + this.edgeBias = cfg.edgeBias; + this.centerBias = cfg.centerBias; + this.power = cfg.power; + } - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } + /** + * Sets the Fresnel's edge color. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @type {Number[]} + */ + set edgeColor(value) { + this._state.edgeColor.set(value || [0.0, 0.0, 0.0]); + this.glRedraw(); } - _bindProgram() { + /** + * Gets the Fresnel's edge color. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @type {Number[]} + */ + get edgeColor() { + return this._state.edgeColor; + } - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const project = scene.camera.project; + /** + * Sets the Fresnel's center color. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * + * @type {Number[]} + */ + set centerColor(value) { + this._state.centerColor.set(value || [1.0, 1.0, 1.0]); + this.glRedraw(); + } - program.bind(); + /** + * Gets the Fresnel's center color. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * + * @type {Number[]} + */ + get centerColor() { + return this._state.centerColor; + } - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + /** + * Sets the Fresnel's edge bias. + * + * Default value is ````0````. + * + * @type {Number} + */ + set edgeBias(value) { + this._state.edgeBias = value || 0; + this.glRedraw(); + } - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + /** + * Gets the Fresnel's edge bias. + * + * Default value is ````0````. + * + * @type {Number} + */ + get edgeBias() { + return this._state.edgeBias; } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + /** + * Sets the Fresnel's center bias. + * + * Default value is ````1````. + * + * @type {Number} + */ + set centerBias(value) { + this._state.centerBias = (value !== undefined && value !== null) ? value : 1; + this.glRedraw(); } - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; + /** + * Gets the Fresnel's center bias. + * + * Default value is ````1````. + * + * @type {Number} + */ + get centerBias() { + return this._state.centerBias; + } - src.push("#version 300 es"); - src.push("// Batched geometry edges drawing vertex shader"); + /** + * Sets the Fresnel's power. + * + * Default value is ````1````. + * + * @type {Number} + */ + set power(value) { + this._state.power = (value !== undefined && value !== null) ? value : 1; + this.glRedraw(); + } - src.push("uniform int renderPass;"); - src.push("uniform vec4 color;"); + /** + * Gets the Fresnel's power. + * + * Default value is ````1````. + * + * @type {Number} + */ + get power() { + return this._state.power; + } - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + /** + * Destroys this Fresnel. + */ + destroy() { + super.destroy(); + this._state.destroy(); + } +} - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } - - src.push("out vec4 vColor;"); - src.push("void main(void) {"); - - // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - // renderPass = EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - - src.push(`if (int(flags.z) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - - src.push("} else {"); - - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - src.push("vColor = vec4(color.r, color.g, color.b, color.a);"); - src.push("}"); - src.push("}"); - return src; - } - - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry edges drawing fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push("}"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push("outColor = vColor;"); - src.push("}"); - return src; - } - - webglContextRestored() { - this._program = null; - } - - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; - } -} - -const tempVec3a$S = math.vec3(); +const memoryStats = stats.memory; +const tempAABB$1 = math.AABB3(); /** - * @private + * @desc A {@link Geometry} that keeps its geometry data solely in GPU memory, without retaining it in browser memory. + * + * VBOGeometry uses less memory than {@link ReadableGeometry}, which keeps its geometry data in both browser and GPU memory. + * + * ## Usage + * + * Creating a {@link Mesh} with a VBOGeometry that defines a single triangle, plus a {@link PhongMaterial} with diffuse {@link Texture}: + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_VBOGeometry)] + * + * ````javascript + * import {Viewer, Mesh, VBOGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * new Mesh(viewer.scene, { + * geometry: new VBOGeometry(viewer.scene, { + * primitive: "triangles", + * positions: [0.0, 3, 0.0, -3, -3, 0.0, 3, -3, 0.0], + * normals: [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0], + * uv: [0.0, 0.0, 0.5, 1.0, 1.0, 0.0], + * indices: [0, 1, 2] + * }), + * material: new PhongMaterial(viewer.scene, { + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }), + * backfaces: true + * }) + * }); + * ```` */ -class TrianglesBatchingEdgesColorRenderer { +class VBOGeometry extends Geometry { - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); + /** + @private + */ + get type() { + return "VBOGeometry"; } - getValid() { - return this._hash === this._getHash(); - }; - - _getHash() { - return this._scene._sectionPlanesState.getHash(); + /** + * @private + * @returns {Boolean} + */ + get isVBOGeometry() { + return true; } - drawLayer(frameCtx, batchingLayer, renderPass) { + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {String} [cfg.primitive="triangles"] The primitive type. Accepted values are 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'. + * @param {Number[]} [cfg.positions] Positions array. + * @param {Number[]} [cfg.normals] Vertex normal vectors array. + * @param {Number[]} [cfg.uv] UVs array. + * @param {Number[]} [cfg.colors] Vertex colors. + * @param {Number[]} [cfg.indices] Indices array. + * @param {Number} [cfg.edgeThreshold=10] When autogenerating edges for supporting {@link Drawable#edges}, this indicates the threshold angle (in degrees) between the face normals of adjacent triangles below which the edge is discarded. + */ + constructor(owner, cfg = {}) { - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; + super(owner, cfg); - if (!this._program) { - this._allocate(batchingLayer); - if (this.errors) { - return; - } - } + this._state = new RenderState({ // Arrays for emphasis effects are got from xeokit.GeometryLite friend methods + compressGeometry: true, + primitive: null, // WebGL enum + primitiveName: null, // String + positionsDecodeMatrix: null, // Set when compressGeometry == true + uvDecodeMatrix: null, // Set when compressGeometry == true + positionsBuf: null, + normalsBuf: null, + colorsbuf: null, + uvBuf: null, + indicesBuf: null, + hash: "" + }); - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); - } + this._numTriangles = 0; - gl.uniform1i(this._uRenderPass, renderPass); + this._edgeThreshold = cfg.edgeThreshold || 10.0; + this._aabb = null; + this._obb = math.OBB3(); - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + const state = this._state; + const gl = this.scene.canvas.gl; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$S); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } + cfg.primitive = cfg.primitive || "triangles"; + switch (cfg.primitive) { + case "points": + state.primitive = gl.POINTS; + state.primitiveName = cfg.primitive; + break; + case "lines": + state.primitive = gl.LINES; + state.primitiveName = cfg.primitive; + break; + case "line-loop": + state.primitive = gl.LINE_LOOP; + state.primitiveName = cfg.primitive; + break; + case "line-strip": + state.primitive = gl.LINE_STRIP; + state.primitiveName = cfg.primitive; + break; + case "triangles": + state.primitive = gl.TRIANGLES; + state.primitiveName = cfg.primitive; + break; + case "triangle-strip": + state.primitive = gl.TRIANGLE_STRIP; + state.primitiveName = cfg.primitive; + break; + case "triangle-fan": + state.primitive = gl.TRIANGLE_FAN; + state.primitiveName = cfg.primitive; + break; + default: + this.error("Unsupported value for 'primitive': '" + cfg.primitive + + "' - supported values are 'points', 'lines', 'line-loop', 'line-strip', 'triangles', " + + "'triangle-strip' and 'triangle-fan'. Defaulting to 'triangles'."); + state.primitive = gl.TRIANGLES; + state.primitiveName = cfg.primitive; } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - - this._aPosition.bindArrayBuffer(state.positionsBuf); - this._aColor.bindArrayBuffer(state.colorsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); + if (!cfg.positions) { + this.error("Config expected: positions"); + return; // TODO: Recover? } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + + if (!cfg.indices) { + this.error("Config expected: indices"); + return; // TODO: Recover? } - state.edgeIndicesBuf.bind(); - gl.drawElements(gl.LINES, state.edgeIndicesBuf.numItems, state.edgeIndicesBuf.itemType, 0); - } + var positions; - _allocate() { + { + const positionsDecodeMatrix = cfg.positionsDecodeMatrix; - const scene = this._scene; - const gl = scene.canvas.gl; + if (positionsDecodeMatrix) ; else { - this._program = new Program(gl, this._buildShader()); + // Uncompressed positions - if (this._program.errors) { - this.errors = this._program.errors; - return; + const bounds = geometryCompressionUtils.getPositionsBounds(cfg.positions); + const result = geometryCompressionUtils.compressPositions(cfg.positions, bounds.min, bounds.max); + positions = result.quantized; + state.positionsDecodeMatrix = result.decodeMatrix; + state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, positions, positions.length, 3, gl.STATIC_DRAW); + memoryStats.positions += state.positionsBuf.numItems; + math.positions3ToAABB3(cfg.positions, this._aabb); + math.positions3ToAABB3(positions, tempAABB$1, state.positionsDecodeMatrix); + math.AABB3ToOBB3(tempAABB$1, this._obb); + } } - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); + if (cfg.colors) { + const colors = cfg.colors.constructor === Float32Array ? cfg.colors : new Float32Array(cfg.colors); + state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, colors.length, 4, gl.STATIC_DRAW); + memoryStats.colors += state.colorsBuf.numItems; } - this._aPosition = program.getAttribute("position"); - this._aColor = program.getAttribute("color"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + if (cfg.uv) { + const bounds = geometryCompressionUtils.getUVBounds(cfg.uv); + const result = geometryCompressionUtils.compressUVs(cfg.uv, bounds.min, bounds.max); + const uv = result.quantized; + state.uvDecodeMatrix = result.decodeMatrix; + state.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uv, uv.length, 2, gl.STATIC_DRAW); + memoryStats.uvs += state.uvBuf.numItems; } - } - - _bindProgram() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const project = scene.camera.project; - program.bind(); + if (cfg.normals) { + const normals = geometryCompressionUtils.compressNormals(cfg.normals); + let normalized = state.compressGeometry; + state.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, normals, normals.length, 3, gl.STATIC_DRAW, normalized); + memoryStats.normals += state.normalsBuf.numItems; + } - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + { + const indices = (cfg.indices.constructor === Uint32Array || cfg.indices.constructor === Uint16Array) ? cfg.indices : new Uint32Array(cfg.indices); + state.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, indices, indices.length, 1, gl.STATIC_DRAW); + memoryStats.indices += state.indicesBuf.numItems; + const edgeIndices = buildEdgeIndices(positions, indices, state.positionsDecodeMatrix, this._edgeThreshold); + this._edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, edgeIndices, edgeIndices.length, 1, gl.STATIC_DRAW); - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + if (this._state.primitiveName === "triangles") { + this._numTriangles = (cfg.indices.length / 3); + } } - } - - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; - } - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry edges drawing vertex shader"); + this._buildHash(); - src.push("uniform int renderPass;"); + memoryStats.meshes++; + } - src.push("in vec3 position;"); - src.push("in vec4 color;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); + _buildHash() { + const state = this._state; + const hash = ["/g"]; + hash.push("/" + state.primitive + ";"); + if (state.positionsBuf) { + hash.push("p"); } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); + if (state.colorsBuf) { + hash.push("c"); } - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); + if (state.normalsBuf || state.autoVertexNormals) { + hash.push("n"); } + if (state.uvBuf) { + hash.push("u"); + } + hash.push("cp"); // Always compressed + hash.push(";"); + state.hash = hash.join(""); + } - src.push("out vec4 vColor;"); - src.push("void main(void) {"); - - // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - // renderPass = EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT + _getEdgeIndices() { + return this._edgeIndicesBuf; + } - src.push(`if (int(flags.z) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + /** + * Gets the primitive type. + * + * Possible types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'. + * + * @type {String} + */ + get primitive() { + return this._state.primitiveName; + } - src.push("} else {"); + /** + * Gets the local-space axis-aligned 3D boundary (AABB). + * + * The AABB is represented by a six-element Float64Array containing the min/max extents of the axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. + * + * @type {Number[]} + */ + get aabb() { + return this._aabb; + } - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + /** + * Gets the local-space oriented 3D boundary (OBB). + * + * The OBB is represented by a 32-element Float64Array containing the eight vertices of the box, where each vertex is a homogeneous coordinate having [x,y,z,w] elements. + * + * @type {Number[]} + */ + get obb() { + return this._obb; + } - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } + /** + * Approximate number of triangles in this VBOGeometry. + * + * Will be zero if {@link VBOGeometry#primitive} is not 'triangles', 'triangle-strip' or 'triangle-fan'. + * + * @type {Number} + */ + get numTriangles() { + return this._numTriangles; + } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - //src.push("vColor = vec4(float(color.r-100.0) / 255.0, float(color.g-100.0) / 255.0, float(color.b-100.0) / 255.0, float(color.a) / 255.0);"); - src.push("vColor = vec4(float(color.r*0.5) / 255.0, float(color.g*0.5) / 255.0, float(color.b*0.5) / 255.0, float(color.a) / 255.0);"); - src.push("}"); - src.push("}"); - return src; + /** @private */ + _getState() { + return this._state; } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry edges drawing fragment shader"); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + /** + * Destroys this component. + */ + destroy() { + super.destroy(); + const state = this._state; + if (state.indicesBuf) { + state.indicesBuf.destroy(); } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } + if (state.positionsBuf) { + state.positionsBuf.destroy(); } - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push("}"); + if (state.normalsBuf) { + state.normalsBuf.destroy(); } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + if (state.uvBuf) { + state.uvBuf.destroy(); } - src.push("outColor = vColor;"); - src.push("}"); - return src; - } - - webglContextRestored() { - this._program = null; - } - - destroy() { - if (this._program) { - this._program.destroy(); + if (state.colorsBuf) { + state.colorsBuf.destroy(); } - this._program = null; + if (this._edgeIndicesBuf) { + this._edgeIndicesBuf.destroy(); + } + state.destroy(); + memoryStats.meshes--; } } -const tempVec3a$R = math.vec3(); - /** * @private */ -class TrianglesBatchingPickMeshRenderer { - - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); - } - - getValid() { - return this._hash === this._getHash(); - }; - - _getHash() { - return this._scene._sectionPlanesState.getHash(); - } - - drawLayer(frameCtx, batchingLayer, renderPass) { - - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; +var K3D = {}; - if (!this._program) { - this._allocate(batchingLayer); - } +K3D.load = function(path, resp) +{ + var request = new XMLHttpRequest(); + request.open("GET", path, true); + request.responseType = "arraybuffer"; + request.onload = function(e){resp(e.target.response);}; + request.send(); +}; - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); - } +K3D.save = function(buff, path) +{ + var dataURI = "data:application/octet-stream;base64," + btoa(K3D.parse._buffToStr(buff)); + window.location.href = dataURI; +}; - gl.uniform1i(this._uRenderPass, renderPass); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); +K3D.clone = function(o) +{ + return JSON.parse(JSON.stringify(o)); +}; - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } +K3D.bin = {}; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$R); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } +K3D.bin.f = new Float32Array(1); +K3D.bin.fb = new Uint8Array(K3D.bin.f.buffer); - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); +K3D.bin.rf = function(buff, off) { var f = K3D.bin.f, fb = K3D.bin.fb; for(var i=0; i<4; i++) fb[i] = buff[off+i]; return f[0]; }; +K3D.bin.rsl = function(buff, off) { return buff[off] | buff[off+1]<<8; }; +K3D.bin.ril = function(buff, off) { return buff[off] | buff[off+1]<<8 | buff[off+2]<<16 | buff[off+3]<<24; }; +K3D.bin.rASCII0 = function(buff, off) { var s = ""; while(buff[off]!=0) s += String.fromCharCode(buff[off++]); return s; }; - this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } +K3D.bin.wf = function(buff, off, v) { var f=new Float32Array(buff.buffer, off, 1); f[0]=v; }; +K3D.bin.wsl = function(buff, off, v) { buff[off]=v; buff[off+1]=v>>8; }; +K3D.bin.wil = function(buff, off, v) { buff[off]=v; buff[off+1]=v>>8; buff[off+2]=v>>16; buff[off+3]>>24; }; +K3D.parse = {}; - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } +K3D.parse._buffToStr = function(buff) +{ + var a = new Uint8Array(buff); + var s = ""; + for(var i=0; i 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry picking vertex shader"); - + head.num_skins = K3D.bin.ril(buff, 20); /* number of skins */ + head.num_vertices = K3D.bin.ril(buff, 24); /* number of vertices per frame */ + head.num_st = K3D.bin.ril(buff, 28); /* number of texture coordinates */ + head.num_tris = K3D.bin.ril(buff, 32); /* number of triangles */ + head.num_glcmds = K3D.bin.ril(buff, 36); /* number of opengl commands */ + head.num_frames = K3D.bin.ril(buff, 40); /* number of frames */ - src.push("uniform int renderPass;"); + head.offset_skins = K3D.bin.ril(buff, 44); /* offset skin data */ + head.offset_st = K3D.bin.ril(buff, 48); /* offset texture coordinate data */ + head.offset_tris = K3D.bin.ril(buff, 52); /* offset triangle data */ + head.offset_frames = K3D.bin.ril(buff, 56); /* offset frame data */ + head.offset_glcmds = K3D.bin.ril(buff, 60); /* offset OpenGL command data */ + head.offset_end = K3D.bin.ril(buff, 64); /* offset end of file */ - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + var off = head.offset_st; + res.c_uvt = []; + for(var i=0; i 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry picking fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec4 vPickColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" outColor = vPickColor; "); - src.push("}"); - return src; - } - - webglContextRestored() { - this._program = null; - } +K3D.parse.fromMD2._normals = + [ + -0.525731, 0.000000, 0.850651, + -0.442863, 0.238856, 0.864188, + -0.295242, 0.000000, 0.955423, + -0.309017, 0.500000, 0.809017, + -0.162460, 0.262866, 0.951056, + 0.000000, 0.000000, 1.000000, + 0.000000, 0.850651, 0.525731, + -0.147621, 0.716567, 0.681718, + 0.147621, 0.716567, 0.681718, + 0.000000, 0.525731, 0.850651, + 0.309017, 0.500000, 0.809017, + 0.525731, 0.000000, 0.850651, + 0.295242, 0.000000, 0.955423, + 0.442863, 0.238856, 0.864188, + 0.162460, 0.262866, 0.951056, + -0.681718, 0.147621, 0.716567, + -0.809017, 0.309017, 0.500000, + -0.587785, 0.425325, 0.688191, + -0.850651, 0.525731, 0.000000, + -0.864188, 0.442863, 0.238856, + -0.716567, 0.681718, 0.147621, + -0.688191, 0.587785, 0.425325, + -0.500000, 0.809017, 0.309017, + -0.238856, 0.864188, 0.442863, + -0.425325, 0.688191, 0.587785, + -0.716567, 0.681718, -0.147621, + -0.500000, 0.809017, -0.309017, + -0.525731, 0.850651, 0.000000, + 0.000000, 0.850651, -0.525731, + -0.238856, 0.864188, -0.442863, + 0.000000, 0.955423, -0.295242, + -0.262866, 0.951056, -0.162460, + 0.000000, 1.000000, 0.000000, + 0.000000, 0.955423, 0.295242, + -0.262866, 0.951056, 0.162460, + 0.238856, 0.864188, 0.442863, + 0.262866, 0.951056, 0.162460, + 0.500000, 0.809017, 0.309017, + 0.238856, 0.864188, -0.442863, + 0.262866, 0.951056, -0.162460, + 0.500000, 0.809017, -0.309017, + 0.850651, 0.525731, 0.000000, + 0.716567, 0.681718, 0.147621, + 0.716567, 0.681718, -0.147621, + 0.525731, 0.850651, 0.000000, + 0.425325, 0.688191, 0.587785, + 0.864188, 0.442863, 0.238856, + 0.688191, 0.587785, 0.425325, + 0.809017, 0.309017, 0.500000, + 0.681718, 0.147621, 0.716567, + 0.587785, 0.425325, 0.688191, + 0.955423, 0.295242, 0.000000, + 1.000000, 0.000000, 0.000000, + 0.951056, 0.162460, 0.262866, + 0.850651, -0.525731, 0.000000, + 0.955423, -0.295242, 0.000000, + 0.864188, -0.442863, 0.238856, + 0.951056, -0.162460, 0.262866, + 0.809017, -0.309017, 0.500000, + 0.681718, -0.147621, 0.716567, + 0.850651, 0.000000, 0.525731, + 0.864188, 0.442863, -0.238856, + 0.809017, 0.309017, -0.500000, + 0.951056, 0.162460, -0.262866, + 0.525731, 0.000000, -0.850651, + 0.681718, 0.147621, -0.716567, + 0.681718, -0.147621, -0.716567, + 0.850651, 0.000000, -0.525731, + 0.809017, -0.309017, -0.500000, + 0.864188, -0.442863, -0.238856, + 0.951056, -0.162460, -0.262866, + 0.147621, 0.716567, -0.681718, + 0.309017, 0.500000, -0.809017, + 0.425325, 0.688191, -0.587785, + 0.442863, 0.238856, -0.864188, + 0.587785, 0.425325, -0.688191, + 0.688191, 0.587785, -0.425325, + -0.147621, 0.716567, -0.681718, + -0.309017, 0.500000, -0.809017, + 0.000000, 0.525731, -0.850651, + -0.525731, 0.000000, -0.850651, + -0.442863, 0.238856, -0.864188, + -0.295242, 0.000000, -0.955423, + -0.162460, 0.262866, -0.951056, + 0.000000, 0.000000, -1.000000, + 0.295242, 0.000000, -0.955423, + 0.162460, 0.262866, -0.951056, + -0.442863, -0.238856, -0.864188, + -0.309017, -0.500000, -0.809017, + -0.162460, -0.262866, -0.951056, + 0.000000, -0.850651, -0.525731, + -0.147621, -0.716567, -0.681718, + 0.147621, -0.716567, -0.681718, + 0.000000, -0.525731, -0.850651, + 0.309017, -0.500000, -0.809017, + 0.442863, -0.238856, -0.864188, + 0.162460, -0.262866, -0.951056, + 0.238856, -0.864188, -0.442863, + 0.500000, -0.809017, -0.309017, + 0.425325, -0.688191, -0.587785, + 0.716567, -0.681718, -0.147621, + 0.688191, -0.587785, -0.425325, + 0.587785, -0.425325, -0.688191, + 0.000000, -0.955423, -0.295242, + 0.000000, -1.000000, 0.000000, + 0.262866, -0.951056, -0.162460, + 0.000000, -0.850651, 0.525731, + 0.000000, -0.955423, 0.295242, + 0.238856, -0.864188, 0.442863, + 0.262866, -0.951056, 0.162460, + 0.500000, -0.809017, 0.309017, + 0.716567, -0.681718, 0.147621, + 0.525731, -0.850651, 0.000000, + -0.238856, -0.864188, -0.442863, + -0.500000, -0.809017, -0.309017, + -0.262866, -0.951056, -0.162460, + -0.850651, -0.525731, 0.000000, + -0.716567, -0.681718, -0.147621, + -0.716567, -0.681718, 0.147621, + -0.525731, -0.850651, 0.000000, + -0.500000, -0.809017, 0.309017, + -0.238856, -0.864188, 0.442863, + -0.262866, -0.951056, 0.162460, + -0.864188, -0.442863, 0.238856, + -0.809017, -0.309017, 0.500000, + -0.688191, -0.587785, 0.425325, + -0.681718, -0.147621, 0.716567, + -0.442863, -0.238856, 0.864188, + -0.587785, -0.425325, 0.688191, + -0.309017, -0.500000, 0.809017, + -0.147621, -0.716567, 0.681718, + -0.425325, -0.688191, 0.587785, + -0.162460, -0.262866, 0.951056, + 0.442863, -0.238856, 0.864188, + 0.162460, -0.262866, 0.951056, + 0.309017, -0.500000, 0.809017, + 0.147621, -0.716567, 0.681718, + 0.000000, -0.525731, 0.850651, + 0.425325, -0.688191, 0.587785, + 0.587785, -0.425325, 0.688191, + 0.688191, -0.587785, 0.425325, + -0.955423, 0.295242, 0.000000, + -0.951056, 0.162460, 0.262866, + -1.000000, 0.000000, 0.000000, + -0.850651, 0.000000, 0.525731, + -0.955423, -0.295242, 0.000000, + -0.951056, -0.162460, 0.262866, + -0.864188, 0.442863, -0.238856, + -0.951056, 0.162460, -0.262866, + -0.809017, 0.309017, -0.500000, + -0.864188, -0.442863, -0.238856, + -0.951056, -0.162460, -0.262866, + -0.809017, -0.309017, -0.500000, + -0.681718, 0.147621, -0.716567, + -0.681718, -0.147621, -0.716567, + -0.850651, 0.000000, -0.525731, + -0.688191, 0.587785, -0.425325, + -0.587785, 0.425325, -0.688191, + -0.425325, 0.688191, -0.587785, + -0.425325, -0.688191, -0.587785, + -0.587785, -0.425325, -0.688191, + -0.688191, -0.587785, -0.425325 + ]; - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; - } -} +K3D.parse.fromCollada = function(buff) +{ + var str = K3D.parse._buffToStr(buff); + var xml = new DOMParser().parseFromString(str,"text/xml"); + xml = xml.childNodes[0]; + var resp = {}; -const tempVec3a$Q = math.vec3(); + //console.log(xml); -/** - * @private - */ -class TrianglesBatchingPickDepthRenderer { + var ass = xml.getElementsByTagName("asset" )[0]; + var geo = xml.getElementsByTagName("library_geometries")[0]; + var ima = xml.getElementsByTagName("library_images" )[0]; + var mat = xml.getElementsByTagName("library_materials" )[0]; + var eff = xml.getElementsByTagName("library_effects" )[0]; - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); - } + //console.log(xml); + if(ass) resp.asset = K3D.parse.fromCollada._asset (ass); + if(geo) resp.geometries = K3D.parse.fromCollada._libGeometries(geo); + if(ima) resp.images = K3D.parse.fromCollada._libImages (ima); + if(mat) resp.materials = K3D.parse.fromCollada._libMaterials (mat); + if(eff) resp.effects = K3D.parse.fromCollada._libEffects (eff); + return resp; +}; - getValid() { - return this._hash === this._getHash(); +K3D.parse.fromCollada._asset = function(xml) +{ + //console.log(xml); + return { + created : xml.getElementsByTagName("created" )[0].textContent, + modified: xml.getElementsByTagName("modified")[0].textContent, + up_axis : xml.getElementsByTagName("up_axis" )[0].textContent }; +}; - _getHash() { - return this._scene._sectionPlanesState.getHash(); +K3D.parse.fromCollada._libGeometries = function(xml) +{ + xml = xml.getElementsByTagName("geometry"); + var res = []; + for(var i=0; i 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$Q); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } - //============================================================= - // TODO: Use drawElements count and offset to draw only one entity - //============================================================= - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } +K3D.parse.from3DS = function(buff) +{ + buff = new Uint8Array(buff); + var res = {}; + if(K3D.bin.rsl(buff, 0) != 0x4d4d) return null; + var lim = K3D.bin.ril(buff, 2); - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } + var off = 6; + while(off < lim) + { + var cid = K3D.bin.rsl(buff, off); + var lng = K3D.bin.ril(buff, off+2); + //console.log(cid.toString(16), lng); - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + if(cid == 0x3d3d) res.edit = K3D.parse.from3DS._edit3ds(buff, off, lng); + if(cid == 0xb000) res.keyf = K3D.parse.from3DS._keyf3ds(buff, off, lng); - state.indicesBuf.bind(); + off += lng; + } + return res; +}; - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); +K3D.parse.from3DS._edit3ds = function(buff, coff, clng) // buffer, chunk offset, length +{ + var res = {}; + var off = coff+6; + while(off < coff+clng) + { + var cid = K3D.bin.rsl(buff, off); + var lng = K3D.bin.ril(buff, off+2); + //console.log("\t", cid.toString(16), lng); + + if(cid == 0x4000) { if(res.objects==null) res.objects = []; res.objects.push(K3D.parse.from3DS._edit_object(buff, off, lng)); } + //if(cid == 0xb000) res.KEYF3DS = K3D.parse.from3DS._keyf3ds(buff, off, lng); + + off += lng; } + return res; +}; - _allocate() { +K3D.parse.from3DS._keyf3ds = function(buff, coff, clng) +{ + var res = {}; + var off = coff+6; + while(off < coff+clng) + { + var cid = K3D.bin.rsl(buff, off); + var lng = K3D.bin.ril(buff, off+2); + //console.log("\t\t", cid.toString(16), lng); - const scene = this._scene; - const gl = scene.canvas.gl; + //if(cid == 0x4000) { res.objects.push(K3D.parse.from3DS._edit_object(buff, off, lng)); } + if(cid == 0xb002) { if(res.desc==null) res.desc = []; res.desc.push(K3D.parse.from3DS._keyf_objdes(buff, off, lng)); } - this._program = new Program(gl, this._buildShader()); + off += lng; + } + return res; +}; - if (this._program.errors) { - this.errors = this._program.errors; - return; - } +K3D.parse.from3DS._keyf_objdes = function(buff, coff, clng) +{ + var res = {}; + var off = coff+6; + while(off < coff+clng) + { + var cid = K3D.bin.rsl(buff, off); + var lng = K3D.bin.ril(buff, off+2); + //console.log("\t\t\t", cid.toString(16), lng); - const program = this._program; + if(cid == 0xb010) res.hierarchy = K3D.parse.from3DS._keyf_objhierarch(buff, off, lng); + if(cid == 0xb011) res.dummy_name = K3D.bin.rASCII0(buff, off+6); + off += lng; + } + return res; +}; - this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; +K3D.parse.from3DS._keyf_objhierarch = function(buff, coff, clng) +{ + var res = {}; + var off = coff+6; + res.name = K3D.bin.rASCII0(buff, off); off += res.name.length+1; + res.hierarchy = K3D.bin.rsl(buff, off+4); + return res; +}; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } +K3D.parse.from3DS._edit_object = function(buff, coff, clng) // buffer, chunk offset, length +{ + var res = {}; + var off = coff+6; + res.name = K3D.bin.rASCII0(buff, off); off += res.name.length+1; + //console.log(res.name); + while(off < coff+clng) + { + var cid = K3D.bin.rsl(buff, off); + var lng = K3D.bin.ril(buff, off+2); + //console.log("\t\t", cid.toString(16), lng); - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._uPickZNear = program.getLocation("pickZNear"); - this._uPickZFar = program.getLocation("pickZFar"); + if(cid == 0x4100) res.mesh = K3D.parse.from3DS._obj_trimesh(buff, off, lng); + //if(cid == 0xb000) res.KEYF3DS = K3D.parse.from3DS._keyf3ds(buff, off, lng); - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } + off += lng; } + return res; +}; - _bindProgram() { - this._program.bind(); +K3D.parse.from3DS._obj_trimesh = function(buff, coff, clng) // buffer, chunk offset, length +{ + var res = {}; + var off = coff+6; + + while(off < coff+clng) + { + var cid = K3D.bin.rsl(buff, off); + var lng = K3D.bin.ril(buff, off+2); + //console.log("\t\t\t", cid.toString(16), lng); + + if(cid == 0x4110) res.vertices = K3D.parse.from3DS._tri_vertexl (buff, off, lng); + if(cid == 0x4120) res.indices = K3D.parse.from3DS._tri_facel1 (buff, off, lng); + if(cid == 0x4140) res.uvt = K3D.parse.from3DS._tri_mappingcoors(buff, off, lng); + if(cid == 0x4160) res.local = K3D.parse.from3DS._tri_local (buff, off, lng); + off += lng; } + return res; +}; - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; +K3D.parse.from3DS._tri_vertexl = function(buff, coff, clng) // buffer, chunk offset, length +{ + var res = []; + var off = coff+6; + var n = K3D.bin.rsl(buff, off); off += 2; + for(var i=0; i 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching pick depth vertex shader"); +K3D.parse.from3DS._tri_mappingcoors = function(buff, coff, clng) // buffer, chunk offset, length +{ + var res = []; + var off = coff+6; + var n = K3D.bin.rsl(buff, off); off += 2; + for(var i=0; i 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching pick depth fragment shader"); + var len = 40; + if(obj.vertices) len+=obj.vertices.length*4; + if(obj.uvt ) len+=obj.uvt .length*4; + if(obj.indices ) len+=obj.indices .length*indS/8; - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); + var buff = new Uint8Array(len); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } + K3D.bin.wil(buff, 0, 0x6976616e); - src.push("uniform float pickZNear;"); - src.push("uniform float pickZFar;"); + K3D.bin.wil(buff, 4, 32); + K3D.bin.wil(buff, 8, 32); + K3D.bin.wil(buff, 12, indS); - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec4 vViewPosition;"); - src.push("vec4 packDepth(const in float depth) {"); - src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); - src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); - src.push(" vec4 res = fract(depth * bitShift);"); - src.push(" res -= res.xxyz * bitMask;"); - src.push(" return res;"); - src.push("}"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); - src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth - src.push("}"); - return src; + var off = 40; + if(obj.vertices) + { + K3D.bin.wil(buff, 16, off); + K3D.bin.wil(buff, 20, 4*obj.vertices.length); + K3D.parse.fromBIV._writeFloats(buff, off, obj.vertices); + off += 4*obj.vertices.length; } - - webglContextRestored() { - this._program = null; + if(obj.uvt) + { + K3D.bin.wil(buff, 24, off); + K3D.bin.wil(buff, 28, 4*obj.uvt.length); + K3D.parse.fromBIV._writeFloats(buff, off, obj.uvt); + off += 4*obj.uvt.length; } - - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + if(obj.indices) + { + K3D.bin.wil(buff, 32, off); + K3D.bin.wil(buff, 36, 4*obj.indices.length); + K3D.parse.fromBIV._writeInts (buff, off, obj.indices, indS); } -} + return buff.buffer; +}; -const tempVec3a$P = math.vec3(); +K3D.parse.fromBIV._readFloats = function(buff, off, len) +{ + var arr = []; + for(var i=0; i 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$P); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } +K3D.mat.rotateDeg = function(x,y,z){ + var r = Math.PI/180; + return K3D.mat.rotate(x*r, y*r, z*r); +}; - //============================================================= - // TODO: Use drawElements count and offset to draw only one entity - //============================================================= +K3D.mat.rotate = function(x,y,z){ + var m = [ + 1,0,0,0, + 0,1,0,0, + 0,0,1,0, + 0,0,0,1 + ]; + var a = x; // alpha + var b = y; // beta + var g = z; // gama - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + var ca = Math.cos(a), cb = Math.cos(b), cg = Math.cos(g); + var sa = Math.sin(a), sb = Math.sin(b), sg = Math.sin(g); - this._aPosition.bindArrayBuffer(state.positionsBuf); + m[0] = cb*cg; m[1] = -cb*sg; m[2 ] = sb; + m[4] = (ca*sg+sa*sb*cg); m[5] = (ca*cg-sa*sb*sg); m[6 ] = -sa*cb; + m[8] = (sa*sg-ca*sb*cg); m[9] = (sa*cg+ca*sb*sg); m[10] = ca*cb; - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + return m; +}; - if (this._aNormal) { - this._aNormal.bindArrayBuffer(state.normalsBuf); - } - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } +K3D.edit = {}; - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } +K3D.edit.interpolate = function(a, b, d, t){ + for(var i=0; i 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching pick normals vertex shader"); - - src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec3 normal;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("uniform bool pickInvisible;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } - src.push("out vec3 vWorldNormal;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK - src.push(`if (int(flags.w) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vec3 worldNormal = octDecode(normal.xy); "); - src.push(" vWorldNormal = worldNormal;"); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - src.push(" }"); - src.push("}"); - return src; - } - - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching pick normals fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec3 vWorldNormal;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" outColor = vec4((vWorldNormal * 0.5) + 0.5, 1.0);"); - src.push("}"); - return src; - } - - webglContextRestored() { - this._program = null; - } +K3D.utils.getAABB = function(vts) +{ + var minx, miny, minz, maxx, maxy, maxz; + minx = miny = minz = 999999999; + maxx = maxy = maxz = -minx; - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + for(var i=0; imaxx) maxx = vx; + if(vymaxy) maxy = vy; + if(vzmaxz) maxz = vz; } -} - -const tempVec3a$O = math.vec3(); + return {min:{x:minx, y:miny, z:minz}, max:{x:maxx, y:maxy, z:maxz}}; +}; /** - * @private + * @desc Loads {@link Geometry} from 3DS. + * + * ## Usage + * + * In the example below we'll create a {@link Mesh} with {@link PhongMaterial}, {@link Texture} and a {@link ReadableGeometry} loaded from 3DS. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_loaders_3DS)] + * + * ````javascript + * import {Viewer, Mesh, load3DSGeometry, ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [40.04, 23.46, 79.06]; + * viewer.scene.camera.look = [-6.48, 13.92, -0.56]; + * viewer.scene.camera.up = [-0.04, 0.98, -0.08]; + * + * load3DSGeometry(viewer.scene, { + * src: "models/3ds/lexus.3ds", + * compressGeometry: false + * + * }).then(function (geometryCfg) { + * + * // Success + * + * new Mesh(viewer.scene, { + * + * geometry: new ReadableGeometry(viewer.scene, geometryCfg), + * + * material: new PhongMaterial(viewer.scene, { + * + * emissive: [1, 1, 1], + * emissiveMap: new Texture({ // .3DS has no normals so relies on emissive illumination + * src: "models/3ds/lexus.jpg" + * }) + * }), + * + * rotation: [-90, 0, 0] // +Z is up for this particular 3DS + * }); + * }, function () { + * // Error + * }); + * ```` + * + * @function load3DSGeometry + * @param {Scene} scene Scene we're loading the geometry for. + * @param {*} cfg Configs, also added to the result object. + * @param {String} [cfg.src] Path to 3DS file. + * @returns {Object} Configuration to pass into a {@link Geometry} constructor, containing geometry arrays loaded from the OBJ file. */ -class TrianglesBatchingOcclusionRenderer { +function load3DSGeometry(scene, cfg = {}) { - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); - } + return new Promise(function (resolve, reject) { - getValid() { - return this._hash === this._getHash(); - }; + if (!cfg.src) { + console.error("load3DSGeometry: Parameter expected: src"); + reject(); + } - _getHash() { - return this._scene._sectionPlanesState.getHash(); - } + var spinner = scene.canvas.spinner; + spinner.processes++; - drawLayer(frameCtx, batchingLayer, renderPass) { + utils.loadArraybuffer(cfg.src, function (data) { - const model = batchingLayer.model; - const scene = model.scene; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const camera = scene.camera; - const origin = batchingLayer._state.origin; + if (!data.byteLength) { + console.error("load3DSGeometry: no data loaded"); + spinner.processes--; + reject(); + } - if (!this._program) { - this._allocate(batchingLayer); - if (this.errors) { - return; - } - } + var m = K3D.parse.from3DS(data); // done ! - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); - } + var mesh = m.edit.objects[0].mesh; + var positions = mesh.vertices; + var uv = mesh.uvt; + var indices = mesh.indices; - gl.uniform1i(this._uRenderPass, renderPass); + spinner.processes--; - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + resolve(utils.apply(cfg, { + primitive: "triangles", + positions: positions, + normals: null, + uv: uv, + indices: indices + })); + }, - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$O); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + function (msg) { + console.error("load3DSGeometry: " + msg); + spinner.processes--; + reject(); + }); + }); +} - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); +/** + * @desc Loads {@link Geometry} from OBJ. + * + * ## Usage + * + * In the example below we'll create a {@link Mesh} with {@link MetallicMaterial} and {@link ReadableGeometry} loaded from OBJ. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_loaders_OBJ)] + * + * ````javascript + * import {Viewer, Mesh, loadOBJGeometry, ReadableGeometry, + * MetallicMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [0.57, 1.37, 1.14]; + * viewer.scene.camera.look = [0.04, 0.58, 0.00]; + * viewer.scene.camera.up = [-0.22, 0.84, -0.48]; + * + * loadOBJGeometry(viewer.scene, { + * + * src: "models/obj/fireHydrant/FireHydrantMesh.obj", + * compressGeometry: false + * + * }).then(function (geometryCfg) { + * + * // Success + * + * new Mesh(viewer.scene, { + * + * geometry: new ReadableGeometry(viewer.scene, geometryCfg), + * + * material: new MetallicMaterial(viewer.scene, { + * + * baseColor: [1, 1, 1], + * metallic: 1.0, + * roughness: 1.0, + * + * baseColorMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", + * encoding: "sRGB" + * }), + * normalMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" + * }), + * roughnessMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Roughness.png" + * }), + * metallicMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Metallic.png" + * }), + * occlusionMap: new Texture(viewer.scene, { + * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" + * }), + * + * specularF0: 0.7 + * }) + * }); + * }, function () { + * // Error + * }); + * ```` + * + * @function loadOBJGeometry + * @param {Scene} scene Scene we're loading the geometry for. + * @param {*} [cfg] Configs, also added to the result object. + * @param {String} [cfg.src] Path to OBJ file. + * @returns {Object} Configuration to pass into a {@link Geometry} constructor, containing geometry arrays loaded from the OBJ file. + */ +function loadOBJGeometry(scene, cfg = {}) { - this._aPosition.bindArrayBuffer(state.positionsBuf); + return new Promise(function (resolve, reject) { - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); + if (!cfg.src) { + console.error("loadOBJGeometry: Parameter expected: src"); + reject(); } - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); - } + var spinner = scene.canvas.spinner; + spinner.processes++; - this._aFlags.bindArrayBuffer(state.flagsBuf); + utils.loadArraybuffer(cfg.src, function (data) { - if (this._aFlags2) { // Won't be in shader when not clipping - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + if (!data.byteLength) { + console.error("loadOBJGeometry: no data loaded"); + spinner.processes--; + reject(); + } - state.indicesBuf.bind(); + var m = K3D.parse.fromOBJ(data); // done ! - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - } + // unwrap simply duplicates some values, so they can be indexed with indices [0,1,2,3 ... ] + // In some rendering engines, you can have only one index value for vertices, UVs, normals ..., + // so "unwrapping" is a simple solution. - _allocate() { + var positions = K3D.edit.unwrap(m.i_verts, m.c_verts, 3); + var normals = K3D.edit.unwrap(m.i_norms, m.c_norms, 3); + var uv = K3D.edit.unwrap(m.i_uvt, m.c_uvt, 2); + var indices = new Int32Array(m.i_verts.length); - const scene = this._scene; - const gl = scene.canvas.gl; + for (var i = 0; i < m.i_verts.length; i++) { + indices[i] = i; + } - this._program = new Program(gl, this._buildShader()); + spinner.processes--; - if (this._program.errors) { - this.errors = this._program.errors; - return; - } + resolve(utils.apply(cfg, { + primitive: "triangles", + positions: positions, + normals: normals.length > 0 ? normals : null, + autoNormals: normals.length === 0, + uv: uv, + indices: indices + })); + }, - const program = this._program; + function (msg) { + console.error("loadOBJGeometry: " + msg); + spinner.processes--; + reject(); + }); + }); +} - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; +/** + * @desc Creates a box-shaped lines {@link Geometry}. + * + * ## Usage + * + * In the example below we'll create a {@link Mesh} with a box-shaped {@link ReadableGeometry} that has lines primitives. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildBoxLinesGeometry)] + * + * ````javascript + * import {Viewer, Mesh, buildBoxLinesGeometry, ReadableGeometry, PhongMaterial} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [0, 0, 5]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildBoxLinesGeometry({ + * center: [0,0,0], + * xSize: 1, // Half-size on each axis + * ySize: 1, + * zSize: 1 + * }), + * material: new PhongMaterial(viewer.scene, { + * emissive: [0,1,0] + * }) + * }); + * ```` + * + * @function buildBoxLinesGeometry + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} [cfg.center] 3D point indicating the center position. + * @param {Number} [cfg.xSize=1.0] Half-size on the X-axis. + * @param {Number} [cfg.ySize=1.0] Half-size on the Y-axis. + * @param {Number} [cfg.zSize=1.0] Half-size on the Z-axis. + * @returns {Object} Configuration for a {@link Geometry} subtype. + */ +function buildBoxLinesGeometry(cfg = {}) { - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + let xSize = cfg.xSize || 1; + if (xSize < 0) { + console.error("negative xSize not allowed - will invert"); + xSize *= -1; + } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + let ySize = cfg.ySize || 1; + if (ySize < 0) { + console.error("negative ySize not allowed - will invert"); + ySize *= -1; + } - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } + let zSize = cfg.zSize || 1; + if (zSize < 0) { + console.error("negative zSize not allowed - will invert"); + zSize *= -1; } - _bindProgram() { + const center = cfg.center; + const centerX = center ? center[0] : 0; + const centerY = center ? center[1] : 0; + const centerZ = center ? center[2] : 0; - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; + const xmin = -xSize + centerX; + const ymin = -ySize + centerY; + const zmin = -zSize + centerZ; + const xmax = xSize + centerX; + const ymax = ySize + centerY; + const zmax = zSize + centerZ; - this._program.bind(); + return utils.apply(cfg, { + primitive: "lines", + positions: [ + xmin, ymin, zmin, + xmin, ymin, zmax, + xmin, ymax, zmin, + xmin, ymax, zmax, + xmax, ymin, zmin, + xmax, ymin, zmax, + xmax, ymax, zmin, + xmax, ymax, zmax + ], + indices: [ + 0, 1, + 1, 3, + 3, 2, + 2, 0, + 4, 5, + 5, 7, + 7, 6, + 6, 4, + 0, 4, + 1, 5, + 2, 6, + 3, 7 + ] + }); +} - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); +/** + * @desc Creates a grid-shaped {@link Geometry}. + * + * ## Usage + * + * Creating a {@link Mesh} with a GridGeometry and a {@link PhongMaterial}: + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildGridGeometry)] + * + * ````javascript + * import {Viewer, Mesh, buildGridGeometry, VBOGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [0, 0, 5]; + * viewer.camera.look = [0, 0, 0]; + * viewer.camera.up = [0, 1, 0]; + * + * new Mesh(viewer.scene, { + * geometry: new VBOGeometry(viewer.scene, buildGridGeometry({ + * size: 1000, + * divisions: 500 + * })), + * material: new PhongMaterial(viewer.scene, { + * color: [0.0, 0.0, 0.0], + * emissive: [0.4, 0.4, 0.4] + * }), + * position: [0, -1.6, 0] + * }); + * ```` + * + * @function buildGridGeometry + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for the {@link Geometry}, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number} [cfg.size=1] Dimension on the X and Z-axis. + * @param {Number} [cfg.divisions=1] Number of divisions on X and Z axis.. + * @returns {Object} Configuration for a {@link Geometry} subtype. + */ +function buildGridGeometry(cfg = {}) { - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + let size = cfg.size || 1; + if (size < 0) { + console.error("negative size not allowed - will invert"); + size *= -1; } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + let divisions = cfg.divisions || 1; + if (divisions < 0) { + console.error("negative divisions not allowed - will invert"); + divisions *= -1; + } + if (divisions < 1) { + divisions = 1; } - _buildVertexShader() { - const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching occlusion vertex shader"); - - src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + size = size || 10; + divisions = divisions || 10; - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } - src.push("void main(void) {"); + const step = size / divisions; + const halfSize = size / 2; - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE - // Only opaque objects can be occluders + const positions = []; + const indices = []; + let l = 0; - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + for (let i = 0, k = -halfSize; i <= divisions; i++, k += step) { - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } + positions.push(-halfSize); + positions.push(0); + positions.push(k); - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - src.push(" }"); - src.push("}"); - return src; - } + positions.push(halfSize); + positions.push(0); + positions.push(k); - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching occlusion fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue - src.push("}"); - return src; - } + positions.push(k); + positions.push(0); + positions.push(-halfSize); - webglContextRestored() { - this._program = null; - } + positions.push(k); + positions.push(0); + positions.push(halfSize); - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + indices.push(l++); + indices.push(l++); + indices.push(l++); + indices.push(l++); } -} -const tempVec3a$N = math.vec3(); + return utils.apply(cfg, { + primitive: "lines", + positions: positions, + indices: indices + }); +} /** - * @private + * @desc Creates a plane-shaped {@link Geometry}. + * + * ## Usage + * + * Creating a {@link Mesh} with a PlaneGeometry and a {@link PhongMaterial} with diffuse {@link Texture}: + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildPlaneGeometry)] + * + * ````javascript + * import {Viewer, Mesh, buildPlaneGeometry, ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [0, 0, 5]; + * viewer.camera.look = [0, 0, 0]; + * viewer.camera.up = [0, 1, 0]; + + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildPlaneGeometry({ + * center: [0,0,0], + * xSize: 2, + * zSize: 2, + * xSegments: 10, + * zSegments: 10 + * }), + * material: new PhongMaterial(viewer.scene, { + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }) + * }) + * }); + * ```` + * + * @function buildPlaneGeometry + * @param {*} [cfg] Configs + * @param {Number[]} [cfg.center] 3D point indicating the center position. + * @param {String} [cfg.id] Optional ID for the {@link Geometry}, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number} [cfg.xSize=1] Dimension on the X-axis. + * @param {Number} [cfg.zSize=1] Dimension on the Z-axis. + * @param {Number} [cfg.xSegments=1] Number of segments on the X-axis. + * @param {Number} [cfg.zSegments=1] Number of segments on the Z-axis. + * @returns {Object} Configuration for a {@link Geometry} subtype. */ -class TrianglesBatchingDepthRenderer { +function buildPlaneGeometry(cfg = {}) { - constructor(scene) { - this._scene = scene; - this._allocate(); - this._hash = this._getHash(); + let xSize = cfg.xSize || 1; + if (xSize < 0) { + console.error("negative xSize not allowed - will invert"); + xSize *= -1; } - getValid() { - return this._hash === this._getHash(); - }; - - _getHash() { - return this._scene._sectionPlanesState.getHash(); + let zSize = cfg.zSize || 1; + if (zSize < 0) { + console.error("negative zSize not allowed - will invert"); + zSize *= -1; } - drawLayer(frameCtx, batchingLayer, renderPass) { + let xSegments = cfg.xSegments || 1; + if (xSegments < 0) { + console.error("negative xSegments not allowed - will invert"); + xSegments *= -1; + } + if (xSegments < 1) { + xSegments = 1; + } - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; + let zSegments = cfg.xSegments || 1; + if (zSegments < 0) { + console.error("negative zSegments not allowed - will invert"); + zSegments *= -1; + } + if (zSegments < 1) { + zSegments = 1; + } - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } - } + const center = cfg.center; + const centerX = center ? center[0] : 0; + const centerY = center ? center[1] : 0; + const centerZ = center ? center[2] : 0; - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); - } + const halfWidth = xSize / 2; + const halfHeight = zSize / 2; - gl.uniform1i(this._uRenderPass, renderPass); + const planeX = Math.floor(xSegments) || 1; + const planeZ = Math.floor(zSegments) || 1; - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + const planeX1 = planeX + 1; + const planeZ1 = planeZ + 1; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$N); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + const segmentWidth = xSize / planeX; + const segmentHeight = zSize / planeZ; - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + const positions = new Float32Array(planeX1 * planeZ1 * 3); + const normals = new Float32Array(planeX1 * planeZ1 * 3); + const uvs = new Float32Array(planeX1 * planeZ1 * 2); - this._aPosition.bindArrayBuffer(state.positionsBuf); + let offset = 0; + let offset2 = 0; - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + let iz; + let ix; + let x; + let a; + let b; + let c; + let d; - this._aFlags.bindArrayBuffer(state.flagsBuf); + for (iz = 0; iz < planeZ1; iz++) { - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + const z = iz * segmentHeight - halfHeight; - state.indicesBuf.bind(); + for (ix = 0; ix < planeX1; ix++) { - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - } + x = ix * segmentWidth - halfWidth; - _allocate() { + positions[offset] = x + centerX; + positions[offset + 1] = centerY; + positions[offset + 2] = -z + centerZ; - const scene = this._scene; - const gl = scene.canvas.gl; + normals[offset + 2] = -1; - this._program = new Program(gl, this._buildShader()); + uvs[offset2] = (ix) / planeX; + uvs[offset2 + 1] = ((planeZ - iz) / planeZ); - if (this._program.errors) { - this.errors = this._program.errors; - return; + offset += 3; + offset2 += 2; } + } - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + offset = 0; - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + const indices = new ((positions.length / 3) > 65535 ? Uint32Array : Uint16Array)(planeX * planeZ * 6); - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } - } + for (iz = 0; iz < planeZ; iz++) { - _bindProgram() { + for (ix = 0; ix < planeX; ix++) { - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; + a = ix + planeX1 * iz; + b = ix + planeX1 * (iz + 1); + c = (ix + 1) + planeX1 * (iz + 1); + d = (ix + 1) + planeX1 * iz; - this._program.bind(); + indices[offset] = d; + indices[offset + 1] = b; + indices[offset + 2] = a; - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + indices[offset + 3] = d; + indices[offset + 4] = c; + indices[offset + 5] = b; - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + offset += 6; } } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; - } - - _buildVertexShader() { - const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching depth vertex shader"); - - src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } - src.push("out vec2 vHighPrecisionZW;"); - src.push("void main(void) {"); + return utils.apply(cfg, { + positions: positions, + normals: normals, + uv: uvs, + indices: indices + }); +} - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE +/** + * @desc Creates a torus-shaped {@link Geometry}. + * + * ## Usage + * Creating a {@link Mesh} with a torus-shaped {@link ReadableGeometry} : + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildTorusGeometry)] + * + * ````javascript + * import {Viewer, Mesh, buildTorusGeometry, ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [0, 0, 5]; + * viewer.camera.look = [0, 0, 0]; + * viewer.camera.up = [0, 1, 0]; + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ + * center: [0,0,0], + * radius: 1.0, + * tube: 0.5, + * radialSegments: 32, + * tubeSegments: 24, + * arc: Math.PI * 2.0 + * }), + * material: new PhongMaterial(viewer.scene, { + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }) + * }) + * }); + * ```` + * + * @function buildTorusGeometry + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for the {@link Geometry}, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} [cfg.center] 3D point indicating the center position. + * @param {Number} [cfg.radius=1] The overall radius. + * @param {Number} [cfg.tube=0.3] The tube radius. + * @param {Number} [cfg.radialSegments=32] The number of radial segments. + * @param {Number} [cfg.tubeSegments=24] The number of tubular segments. + * @param {Number} [cfg.arc=Math.PI*0.5] The length of the arc in radians, where Math.PI*2 is a closed torus. + * @returns {Object} Configuration for a {@link Geometry} subtype. + */ +function buildTorusGeometry(cfg = {}) { - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - src.push("vHighPrecisionZW = gl_Position.zw;"); - src.push(" }"); - src.push("}"); - return src; + let radius = cfg.radius || 1; + if (radius < 0) { + console.error("negative radius not allowed - will invert"); + radius *= -1; } + radius *= 0.5; - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = (sectionPlanesState.sectionPlanes.length > 0); - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching depth fragment shader"); - - src.push("precision highp float;"); - src.push("precision highp int;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("const float packUpScale = 256. / 255.;"); - src.push("const float unpackDownscale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unpackFactors = unpackDownscale / vec4( packFactors, 1. );"); - src.push("const float shiftRight8 = 1.0 / 256.;"); - - src.push("vec4 packDepthToRGBA( const in float v ) {"); - src.push(" vec4 r = vec4( fract( v * packFactors ), v );"); - src.push(" r.yzw -= r.xyz * shiftRight8;"); - src.push(" return r * packUpScale;"); - src.push("}"); - src.push("in vec2 vHighPrecisionZW;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push("float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;"); - src.push(" outColor = vec4(vec3(1.0 - fragCoordZ), 1.0); "); - src.push("}"); - return src; + let tube = cfg.tube || 0.3; + if (tube < 0) { + console.error("negative tube not allowed - will invert"); + tube *= -1; } - webglContextRestored() { - this._program = null; + let radialSegments = cfg.radialSegments || 32; + if (radialSegments < 0) { + console.error("negative radialSegments not allowed - will invert"); + radialSegments *= -1; } - - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; - stats.memory.programs--; + if (radialSegments < 4) { + radialSegments = 4; } -} - -const tempVec3a$M = math.vec3(); - -/** - * @private - */ -class TrianglesBatchingNormalsRenderer { - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); + let tubeSegments = cfg.tubeSegments || 24; + if (tubeSegments < 0) { + console.error("negative tubeSegments not allowed - will invert"); + tubeSegments *= -1; } - - getValid() { - return this._hash === this._getHash(); - }; - - _getHash() { - return this._scene._sectionPlanesState.getHash(); + if (tubeSegments < 4) { + tubeSegments = 4; } - drawLayer(frameCtx, batchingLayer, renderPass) { - - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; - - if (!this._program) { - this._allocate(batchingLayer); - if (this.errors) { - return; - } - } + let arc = cfg.arc || Math.PI * 2; + if (arc < 0) { + console.warn("negative arc not allowed - will invert"); + arc *= -1; + } + if (arc > 360) { + arc = 360; + } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(batchingLayer); - } + const center = cfg.center; + let centerX = center ? center[0] : 0; + let centerY = center ? center[1] : 0; + const centerZ = center ? center[2] : 0; - gl.uniform1i(this._uRenderPass, renderPass); + const positions = []; + const normals = []; + const uvs = []; + const indices = []; - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + let u; + let v; + let x; + let y; + let z; + let vec; - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + let i; + let j; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$M); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + for (j = 0; j <= tubeSegments; j++) { + for (i = 0; i <= radialSegments; i++) { - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + u = i / radialSegments * arc; + v = 0.785398 + (j / tubeSegments * Math.PI * 2); - this._aPosition.bindArrayBuffer(state.positionsBuf); - this._aOffset.bindArrayBuffer(state.offsetsBuf); - this._aNormal.bindArrayBuffer(state.normalsBuf); - this._aColor.bindArrayBuffer(state.colorsBuf);// Needed for masking out transparent entities using alpha channel - this._aFlags.bindArrayBuffer(state.flagsBuf); - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } - state.indicesBuf.bind(); + centerX = radius * Math.cos(u); + centerY = radius * Math.sin(u); - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - } + x = (radius + tube * Math.cos(v)) * Math.cos(u); + y = (radius + tube * Math.cos(v)) * Math.sin(u); + z = tube * Math.sin(v); - _allocate() { + positions.push(x + centerX); + positions.push(y + centerY); + positions.push(z + centerZ); - const scene = this._scene; - const gl = scene.canvas.gl; + uvs.push(1 - (i / radialSegments)); + uvs.push((j / tubeSegments)); - this._program = new Program(gl, this._buildShader()); + vec = math.normalizeVec3(math.subVec3([x, y, z], [centerX, centerY, centerZ], []), []); - if (this._program.errors) { - this.errors = this._program.errors; - return; + normals.push(vec[0]); + normals.push(vec[1]); + normals.push(vec[2]); } + } - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; + let a; + let b; + let c; + let d; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + for (j = 1; j <= tubeSegments; j++) { + for (i = 1; i <= radialSegments; i++) { - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aNormal = program.getAttribute("normal"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); + a = (radialSegments + 1) * j + i - 1; + b = (radialSegments + 1) * (j - 1) + i - 1; + c = (radialSegments + 1) * (j - 1) + i; + d = (radialSegments + 1) * j + i; - if (this._aFlags2) { // Won't be in shader when not clipping - this._aFlags2 = program.getAttribute("flags2"); - } + indices.push(a); + indices.push(b); + indices.push(c); - if ( scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + indices.push(c); + indices.push(d); + indices.push(a); } } - _bindProgram() { + return utils.apply(cfg, { + positions: positions, + normals: normals, + uv: uvs, + indices: indices + }); +} - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; +/** + * A plane-shaped 3D object containing a bitmap image. + * + * * Creates a 3D quad containing our bitmap, located and oriented using ````pos````, ````normal```` and ````up```` vectors. + * * Registered by {@link Bitmap#id} in {@link Scene#bitmaps}. + * * {@link BCFViewpointsPlugin} will save and load Bitmaps in BCF viewpoints. + * + * ## Usage + * + * In the example below, we'll load the Schependomlaan model, then use + * an ````Bitmap```` to show a storey plan next to the model. + * + * [](http://xeokit.github.io/xeokit-sdk/examples/#Bitmap_storeyPlan) + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#Bitmap_grid)] + * + * ````javascript + * import {Viewer, Bitmap, XKTLoaderPlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [-24.65, 21.69, 8.16]; + * viewer.camera.look = [-14.62, 2.16, -1.38]; + * viewer.camera.up = [0.59, 0.57, -0.56]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true + * }); + * + * new Bitmap(viewer.scene, { + * src: "./images/schependomlaanPlanView.png", + * visible: true, // Show the Bitmap + * height: 24.0, // Height of Bitmap + * pos: [-15, 0, -10], // World-space position of Bitmap's center + * normal: [0, -1, 0], // Vector perpendicular to Bitmap + * up: [0, 0, 1], // Direction of Bitmap "up" + * collidable: false, // Bitmap does not contribute to Scene boundary + * clippable: true, // Bitmap can be clipped by SectionPlanes + * pickable: true // Allow the ground plane to be picked + * }); + * ```` + */ +class Bitmap extends Component { - this._program.bind(); + /** + * Creates a new Bitmap. + * + * Registers the Bitmap in {@link Scene#bitmaps}; causes Scene to fire a "bitmapCreated" event. + * + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this ````Bitmap```` as well. + * @param {*} [cfg] ````Bitmap```` configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Boolean} [cfg.visible=true] Indicates whether or not this ````Bitmap```` is visible. + * @param {Number[]} [cfg.pos=[0,0,0]] World-space position of the ````Bitmap````. + * @param {Number[]} [cfg.normal=[0,0,1]] Normal vector indicating the direction the ````Bitmap```` faces. + * @param {Number[]} [cfg.up=[0,1,0]] Direction of "up" for the ````Bitmap````. + * @param {Number[]} [cfg.height=1] World-space height of the ````Bitmap````. + * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Modelling transform matrix for the ````Bitmap````. Overrides the ````position````, ````height```, ````rotation```` and ````normal```` parameters. + * @param {Boolean} [cfg.collidable=true] Indicates if the ````Bitmap```` is initially included in boundary calculations. + * @param {Boolean} [cfg.clippable=true] Indicates if the ````Bitmap```` is initially clippable. + * @param {Boolean} [cfg.pickable=true] Indicates if the ````Bitmap```` is initially pickable. + * @param {Number} [cfg.opacity=1.0] ````Bitmap````'s initial opacity factor, multiplies by the rendered fragment alpha. + * @param {String} [cfg.src] URL of image. Accepted file types are PNG and JPEG. + * @param {HTMLImageElement} [cfg.image] An ````HTMLImageElement```` to source the image from. Overrides ````src````. + * @param {String} [cfg.imageData] Image data as a base64 encoded string. + * @param {String} [cfg.type="jpg"] Image MIME type. Accepted values are "jpg" and "png". Default is "jpg". Normally only needed with ````image```` or ````imageData````. Automatically inferred from file extension of ````src````, if the file has a recognized extension. + */ + constructor(owner, cfg = {}) { - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + super(owner, cfg); - if ( scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } - } + this._type = cfg.type || (cfg.src ? cfg.src.split('.').pop() : null) || "jpg"; + this._pos = math.vec3(cfg.pos || [0, 0, 0]); + this._up = math.vec3(cfg.up || [0, 1, 0]); + this._normal = math.vec3(cfg.normal || [0, 0, 1]); + this._height = cfg.height || 1.0; - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; - } + this._origin = math.vec3(); + this._rtcPos = math.vec3(); + this._imageSize = math.vec2(); - _buildVertexShader() { - const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry normals vertex shader"); - src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec3 normal;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); + this._texture = new Texture(this); + this._image = new Image(); + + if (this._type !== "jpg" && this._type !== "png") { + this.error(`Unsupported type - defaulting to "jpg"`); + this._type = "jpg"; } - src.push("out vec3 vViewNormal;"); - src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + this._node = new Node$1(this, { + matrix: math.inverseMat4( + math.lookAtMat4v(this._pos, math.subVec3(this._pos, this._normal, math.mat4()), + this._up, + math.mat4())), + children: [ - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); + this._bitmapMesh = new Mesh(this, { + scale: [1, 1, 1], + rotation: [-90, 0, 0], + collidable: cfg.collidable, + pickable: cfg.pickable, + opacity: cfg.opacity, + clippable: cfg.clippable, + + geometry: new ReadableGeometry(this, buildPlaneGeometry({ + center: [0, 0, 0], + xSize: 1, + zSize: 1, + xSegments: 2, + zSegments: 2 + })), + + material: new PhongMaterial(this, { + diffuse: [0, 0, 0], + ambient: [0, 0, 0], + specular: [0, 0, 0], + diffuseMap: this._texture, + emissiveMap: this._texture, + backfaces: true + }) + }) + ] + }); - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); - src.push(" vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - src.push(" vViewNormal = viewNormal;"); - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + if (cfg.image) { + this.image = cfg.image; + } else if (cfg.src) { + this.src = cfg.src; + } else if (cfg.imageData) { + this.imageData = cfg.imageData; } - src.push("gl_Position = clipPos;"); - src.push(" }"); - src.push("}"); - return src; - } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = (sectionPlanesState.sectionPlanes.length > 0); - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry normals fragment shader"); + this.scene._bitmapCreated(this); + } - + /** + * Sets if this ````Bitmap```` is visible or not. + * + * Default value is ````true````. + * + * @param {Boolean} visible Set ````true```` to make this ````Bitmap```` visible. + */ + set visible(visible) { + this._bitmapMesh.visible = visible; + } - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); + /** + * Gets if this ````Bitmap```` is visible or not. + * + * Default value is ````true````. + * + * @returns {Boolean} Returns ````true```` if visible. + */ + get visible() { + return this._bitmapMesh.visible; + } - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + /** + * Sets an ````HTMLImageElement```` to source the image from. + * + * Sets {@link Texture#src} null. + * + * You may also need to set {@link Bitmap#type}, if you want to read the image data with {@link Bitmap#imageData}. + * + * @type {HTMLImageElement} + */ + set image(image) { + this._image = image; + if (this._image) { + this._texture.image = this._image; + this._imageSize[0] = this._image.width; + this._imageSize[1] = this._image.height; + this._updateBitmapMeshScale(); } + } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec3 vViewNormal;"); - src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); - src.push(" return normalize( normal ) * 0.5 + 0.5;"); - src.push("}"); - src.push("out vec4 outColor;"); + /** + * Gets the ````HTMLImageElement```` the ````Bitmap````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {HTMLImageElement} + */ + get image() { + return this._image; + } - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); + /** + * Sets an image file path that the ````Bitmap````'s image is sourced from. + * + * If the file extension is a recognized MIME type, also sets {@link Bitmap#type} to that MIME type. + * + * Accepted file types are PNG and JPEG. + * + * @type {String} + */ + set src(src) { + if (src) { + this._image.onload = () => { + this._texture.image = this._image; + this._imageSize[0] = this._image.width; + this._imageSize[1] = this._image.height; + this._updateBitmapMeshScale(); + }; + this._image.src = src; + const ext = src.split('.').pop(); + switch (ext) { + case "jpeg": + case "jpg": + this._type = "jpg"; + break; + case "png": + this._type = "png"; } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); - src.push("}"); - return src; } - webglContextRestored() { - this._program = null; + /** + * Gets the image file path that the ````Bitmap````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {String} + */ + get src() { + return this._image.src; } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + /** + * Sets an image file path that the ````Bitmap````'s image is sourced from. + * + * Accepted file types are PNG and JPEG. + * + * Sets {@link Texture#image} null. + * + * You may also need to set {@link Bitmap#type}, if you want to read the image data with {@link Bitmap#imageData}. + * + * @type {String} + */ + set imageData(imageData) { + this._image.onload = () => { + this._texture.image = image; + this._imageSize[0] = image.width; + this._imageSize[1] = image.height; + this._updateBitmapMeshScale(); + }; + this._image.src = imageData; } -} - -const tempVec3a$L = math.vec3(); -/** - * Renders BatchingLayer fragment depths to a shadow map. - * - * @private - */ -class TrianglesBatchingShadowRenderer { + /** + * Gets the image file path that the ````Bitmap````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {String} + */ + get imageData() { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.width = this._image.width; + canvas.height = this._image.height; + context.drawImage(this._image, 0, 0); + return canvas.toDataURL(this._type === "jpg" ? 'image/jpeg' : 'image/png'); + } - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); + /** + * Sets the MIME type of this Bitmap. + * + * This is used by ````Bitmap```` when getting image data with {@link Bitmap#imageData}. + * + * Supported values are "jpg" and "png", + * + * Default is "jpg". + * + * @type {String} + */ + set type(type) { + type = type || "jpg"; + if (type !== "png" || type !== "jpg") { + this.error("Unsupported value for `type` - supported types are `jpg` and `png` - defaulting to `jpg`"); + type = "jpg"; + } + this._type = type; } - getValid() { - return this._hash === this._getHash(); - }; + /** + * Gets the MIME type of this Bitmap. + * + * @type {String} + */ + get type() { + return this._type; + } - _getHash() { - return this._scene._sectionPlanesState.getHash(); + /** + * Gets the World-space position of this ````Bitmap````. + * + * Default value is ````[0, 0, 0]````. + * + * @returns {Number[]} Current position. + */ + get pos() { + return this._pos; } - drawLayer(frameCtx, batchingLayer) { - const scene = this._scene; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - if (!this._program) { - this._allocate(); - } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); - } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - if (scene.logarithmicDepthBufferEnabled) { - gl.uniform1f(this._uZFar, scene.camera.project.far); - } - this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aColor) { // Needed for masking out transparent entities using alpha channel - this._aColor.bindArrayBuffer(state.colorsBuf); - } - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } - state.indicesBuf.bind(); + /** + * Gets the direction of the normal vector that is perpendicular to this ````Bitmap````. + * + * @returns {Number[]} value Current normal direction. + */ + get normal() { + return this._normal; + } - // TODO: Section planes need to be set if RTC center has changed since last RTC center recorded on frameCtx + /** + * Gets the "up" direction of this ````Bitmap````. + * + * @returns {Number[]} value Current "up" direction. + */ + get up() { + return this._up; + } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - const origin = batchingLayer._state.origin; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$L); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } + /** + * Sets the World-space height of the ````Bitmap````. + * + * Default value is ````1.0````. + * + * @param {Number} height New World-space height of the ````Bitmap````. + */ + set height(height) { + this._height = (height === undefined || height === null) ? 1.0 : height; + if (this._image) { + this._updateBitmapMeshScale(); } + } - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + /** + * Gets the World-space height of the ````Bitmap````. + * + * Returns {Number} World-space height of the ````Bitmap````. + */ + get height() { + return this._height; } - _allocate() { - const scene = this._scene; - const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; - this._program = new Program(gl, this._buildShader()); - if (this._program.errors) { - this.errors = this._program.errors; - return; - } - const program = this._program; - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uShadowViewMatrix = program.getLocation("shadowViewMatrix"); - this._uShadowProjMatrix = program.getLocation("shadowProjMatrix"); - if (scene.logarithmicDepthBufferEnabled) { - this._uZFar = program.getLocation("zFar"); - } - this._uSectionPlanes = []; - const sectionPlanes = sectionPlanesState.sectionPlanes; - for (let i = 0, len = sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + /** + * Sets if this ````Bitmap```` is included in boundary calculations. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set collidable(value) { + this._bitmapMesh.collidable = (value !== false); } - _bindProgram(frameCtx) { - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - program.bind(); - gl.uniformMatrix4fv(this._uShadowViewMatrix, false, frameCtx.shadowViewMatrix); - gl.uniformMatrix4fv(this._uShadowProjMatrix, false, frameCtx.shadowProjMatrix); - this._lastLightId = null; + /** + * Gets if this ````Bitmap```` is included in boundary calculations. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get collidable() { + return this._bitmapMesh.collidable; } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + /** + * Sets if this ````Bitmap```` is clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set clippable(value) { + this._bitmapMesh.clippable = (value !== false); } + /** + * Gets if this ````Bitmap```` is clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get clippable() { + return this._bitmapMesh.clippable; + } - _buildVertexShader() { - const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry shadow vertex shader"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("uniform mat4 shadowViewMatrix;"); - src.push("uniform mat4 shadowProjMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } - src.push("out vec4 vViewPosition;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - src.push(" bool visible = (float(flags.x) > 0.0);"); - src.push(" bool transparent = ((float(color.a) / 255.0) < 1.0);"); - src.push(" if (!visible || transparent) {"); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); - src.push(" } else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = shadowViewMatrix * worldPosition; "); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - src.push(" vViewPosition = viewPosition;"); - src.push(" gl_Position = shadowProjMatrix * viewPosition;"); - src.push(" }"); - src.push("}"); - return src; + /** + * Sets if this ````Bitmap```` is pickable. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set pickable(value) { + this._bitmapMesh.pickable = (value !== false); } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = (sectionPlanesState.sectionPlanes.length > 0); - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry shadow fragment shader"); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec4 vViewPosition;"); + /** + * Gets if this ````Bitmap```` is pickable. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get pickable() { + return this._bitmapMesh.pickable; + } - src.push("vec4 encodeFloat( const in float v ) {"); - src.push(" const vec4 bitShift = vec4(256 * 256 * 256, 256 * 256, 256, 1.0);"); - src.push(" const vec4 bitMask = vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);"); - src.push(" vec4 comp = fract(v * bitShift);"); - src.push(" comp -= comp.xxyz * bitMask;"); - src.push(" return comp;"); - src.push("}"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - src.push(" outColor = encodeFloat( gl_FragCoord.z); "); - src.push("}"); - return src; + /** + * Sets the opacity factor for this ````Bitmap````. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + set opacity(opacity) { + this._bitmapMesh.opacity = opacity; } - webglContextRestored() { - this._program = null; + /** + * Gets this ````Bitmap````'s opacity factor. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + get opacity() { + return this._bitmapMesh.opacity; } + /** + * Destroys this ````Bitmap````. + * + * Removes the ```Bitmap```` from {@link Scene#bitmaps}; causes Scene to fire a "bitmapDestroyed" event. + */ destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + super.destroy(); + this.scene._bitmapDestroyed(this); } -} - -const tempVec4$5 = math.vec4(); -const tempVec3a$K = math.vec3(); -// const TEXTURE_DECODE_FUNCS = {}; -// TEXTURE_DECODE_FUNCS[LinearEncoding] = "linearToLinear"; -// TEXTURE_DECODE_FUNCS[sRGBEncoding] = "sRGBToLinear"; + _updateBitmapMeshScale() { + const aspect = this._imageSize[1] / this._imageSize[0]; + this._bitmapMesh.scale = [this._height * aspect, 1.0, this._height]; + } +} /** - * @private + * A set of 3D line segments. + * + * * Creates a set of 3D line segments. + * * Registered by {@link LineSet#id} in {@link Scene#lineSets}. + * * Configure color using the {@link LinesMaterial} located at {@link Scene#linesMaterial}. + * * {@link BCFViewpointsPlugin} will save and load Linesets in BCF viewpoints. + * + * ## Usage + * + * In the example below, we'll load the Schependomlaan model, then use + * a ````LineSet```` to show a grid underneath the model. + * + * [](http://xeokit.github.io/xeokit-sdk/examples/#LineSet_grid) + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#LineSet_grid)] + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, LineSet, buildGridGeometry} from "../dist/xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * const camera = viewer.camera; + * + * viewer.camera.eye = [-2.56, 8.38, 8.27]; + * viewer.camera.look = [13.44, 3.31, -14.83]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "../assets/models/xkt/v8/ifc/Schependomlaan.ifc.xkt", + * position: [0,1,0], + * edges: true, + * saoEnabled: true + * }); + * + * const geometryArrays = buildGridGeometry({ + * size: 100, + * divisions: 30 + * }); + * + * new LineSet(viewer.scene, { + * positions: geometryArrays.positions, + * indices: geometryArrays.indices + * }); + * ```` */ -class TrianglesBatchingPBRRenderer { +class LineSet extends Component { - constructor(scene, withSAO) { - this._scene = scene; - this._withSAO = withSAO; - this._hash = this._getHash(); - this._allocate(); - } + /** + * Creates a new LineSet. + * + * Registers the LineSet in {@link Scene#lineSets}; causes Scene to fire a "lineSetCreated" event. + * + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this ````LineSet```` as well. + * @param {*} [cfg] ````LineSet```` configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} cfg.positions World-space 3D vertex positions. + * @param {Number[]} [cfg.indices] Indices to connect ````positions```` into line segments. Note that these are separate line segments, not a polyline. + * @param {Number[]} [cfg.color=[0,0,0]] The color of this ````LineSet````. This is both emissive and diffuse. + * @param {Boolean} [cfg.visible=true] Indicates whether or not this ````LineSet```` is visible. + * @param {Number} [cfg.opacity=1.0] ````LineSet````'s initial opacity factor. + */ + constructor(owner, cfg = {}) { - getValid() { - return this._hash === this._getHash(); - }; - - _getHash() { - const scene = this._scene; - return [scene.gammaOutput, scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); - } - - drawLayer(frameCtx, batchingLayer, renderPass) { + super(owner, cfg); - const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; + this._positions = cfg.positions || []; - const scene = this._scene; - const camera = scene.camera; - const model = batchingLayer.model; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; - const textureSet = state.textureSet; - const lightsState = scene._lightsState; + this._origin = math.vec3(cfg.origin || [0, 0, 0]); - if (!this._program) { - this._allocate(); - if (this.errors) { - return; + if (cfg.indices) { + this._indices = cfg.indices; + } else { + this._indices = []; + for (let i = 0, len = (this._positions.length / 3) - 1; i < len; i += 2) { + this._indices.push(i); + this._indices.push(i + 1); } } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); - } + this._mesh = new Mesh(this, { + visible: cfg.visible, + clippable: cfg.clippable, + collidable: cfg.collidable, + geometry: new VBOGeometry(this, { + primitive: "lines", + positions: this._positions, + indices: this._indices, + origin: cfg.origin + }), + material: new PhongMaterial(this, { + diffuse: cfg.color || [0, 0, 0], + emissive: cfg.color || [0, 0, 0] + }) + }); - gl.uniform1i(this._uRenderPass, renderPass); + this.scene._lineSetCreated(this); + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + /** + * Sets if this ````LineSet```` is visible. + * + * Default value is ````true````. + * + * @param {Boolean} visible Set ````true```` to make this ````LineSet```` visible. + */ + set visible(visible) { + this._mesh.visible = visible; + } - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + /** + * Gets if this ````LineSet```` is visible. + * + * Default value is ````true````. + * + * @returns {Boolean} Returns ````true```` if visible. + */ + get visible() { + return this._mesh.visible; + } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$K); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + /** + * Gets the 3D World-space vertex positions of the lines in this ````LineSet````. + * + * @returns {Number[]} + */ + get positions() { + return this._positions; + } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, state.positionsDecodeMatrix); + /** + * Gets the vertex indices of the lines in this ````LineSet````. + * + * @returns {Number[]} + */ + get indices() { + return this._indices; + } - if (this._uUVDecodeMatrix) { - gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, state.uvDecodeMatrix); - } + /** + * Destroys this ````LineSet````. + * + * Removes the ```LineSet```` from {@link Scene#lineSets}; causes Scene to fire a "lineSetDestroyed" event. + */ + destroy() { + super.destroy(); + this.scene._lineSetDestroyed(this); + } +} - this._aPosition.bindArrayBuffer(state.positionsBuf); +const tempVec3$4 = math.vec3(); +const tempVec3a$X = math.vec3(); +const tempVec3b$9 = math.vec3(); +const tempVec3c$6 = math.vec3(); - if (this._aNormal) { - this._aNormal.bindArrayBuffer(state.normalsBuf); - } +/** + * {@link Viewer} plugin that saves and loads BCF viewpoints as JSON objects. + * + * [](http://xeokit.github.io/xeokit-sdk/examples/#BCF_SaveViewpoint) + * + * * [[Example 1: Saving viewer state to a BCF viewpoint](https://xeokit.github.io/xeokit-sdk/examples/#BCF_SaveViewpoint)] + * * [[Example 2: Loading viewer state from a BCF viewpoint](https://xeokit.github.io/xeokit-sdk/examples/#BCF_LoadViewpoint)] + * + * ## Overview + * + * BCF is an open standard that enables workflow communications between BIM software tools. An XML schema, called + * Building Collaboration Format (BCF), encodes messages that inform one BIM tool of issues found by another. + * + * A BCF viewpoint captures a viewpoint of a model that highlights an issue. The viewpoint can then be loaded by another + * viewer to examine the issue. + * + * Using this plugin, a xeokit {@link Viewer} can exchange BCF-encoded viewpoints with other BIM software, + * allowing us to use the Viewer to report and view issues in BIM models. + * + * This plugin's viewpoints conform to the BCF Version 2.1 specification. + * + * ## Supported BCF Elements + * + * BCFViewpointsPlugin saves and loads the following state in BCF viewpoints: + * + * * {@link Camera} position, orientation and projection + * * {@link Entity} visibilities and selection states + * * {@link SectionPlane}s to slice the model + * * {@link LineSet}s to show 3D lines + * * {@link Bitmap}s to show images + * + * ## Saving a BCF Viewpoint + * + * In the example below we'll create a {@link Viewer}, load an ````.XKT```` model into it using an {@link XKTLoaderPlugin}, + * slice the model in half using a {@link SectionPlanesPlugin}, create a grid ground plane using a {@link LineSet} and a 2D + * plan view using a {@link Bitmap}, then use a {@link BCFViewpointsPlugin#getViewpoint} + * to save a viewpoint to JSON, which we'll log to the JavaScript developer console. + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#BCF_SaveViewpoint)] + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, SectionPlanesPlugin, + * LineSet, Bitmap, buildGridGeometry, BCFViewpointsPlugin} from "xeokit-sdk.es.js"; + * + * // Create a Viewer + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * // Set camera position and orientation + * viewer.scene.camera.eye = [-48.93, 54.54, 50.41]; + * viewer.scene.camera.look = [0.55, -0.61, -0.55]; + * viewer.scene.camera.up = [0, -1, 0]; + * viewer.scene.camera.perspective.fov = 60; + * + * // Add a XKTLoaderPlugin + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * // Add a SectionPlanesPlugin + * const sectionPlanes = new SectionPlanesPlugin(viewer); + * + * // Add a BCFViewpointsPlugin + * const bcfViewpoints = new BCFViewpointsPlugin(viewer); + * + * // Load an .XKT model + * const modelNode = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true // Emphasise edges + * }); + * + * // Slice it in half + * sectionPlanes.createSectionPlane({ + * id: "myClip", + * pos: [0, 0, 0], + * dir: [0.5, 0.0, 0.5] + * }); + * + * // Create a bitmap + * const bitmap = new Bitmap(viewer.scene, { + * src: "../assets/images/schependomlaanPlanView.png", + * visible: true, + * height: 24.0, + * pos: [-15, 0, -10], + * normal: [0, -1, 0], + * up: [0, 0, 1], + * collidable: false, + * opacity: 1.0, + * clippable: false, + * pickable: true + * }); + * + * // Create a grid ground plane + * const geometryArrays = buildGridGeometry({ + * size: 60, + * divisions: 10 + * }); + * + * new LineSet(viewer.scene, { + * positions: geometryArrays.positions, + * indices: geometryArrays.indices, + * position: [10,0,10], + * clippable: false + * }); + * + * // When model is loaded, select some objects and capture a BCF viewpoint to the console + * modelNode.on("loaded", () => { + * + * const scene = viewer.scene; + * + * scene.setObjectsSelected([ + * "3b2U496P5Ebhz5FROhTwFH", + * "2MGtJUm9nD$Re1_MDIv0g2", + * "3IbuwYOm5EV9Q6cXmwVWqd", + * "3lhisrBxL8xgLCRdxNG$2v", + * "1uDn0xT8LBkP15zQc9MVDW" + * ], true); + * + * const viewpoint = bcfViewpoints.getViewpoint(); + * const viewpointStr = JSON.stringify(viewpoint, null, 4); + * + * console.log(viewpointStr); + * }); + * ```` + * + * The saved BCF viewpoint would look something like below. Note that some elements are truncated for brevity. + * + * ````json + * { + * "perspective_camera": { + * "camera_view_point": { "x": -48.93, "y": 54.54, "z": 50.41 }, + * "camera_direction": { "x": 0.55, "y": -0.61, "z": -0.55}, + * "camera_up_vector": { "x": 0.37, "y": -0.41, "z": 0.83 }, + * "field_of_view": 60.0 + * }, + * "lines": [{ + * "start_point": { "x": 1.0, "y": 1.0, "z": 1.0 }, + * "end_point": { "x": 0.0, "y": 0.0, "z": 0.0 }, + * //...(truncated) + * }], + * "bitmaps": [{ + * "bitmap_type": "png", + * "bitmap_data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB9AAAAdp...", //...(truncated) + * "location": { "x": -15, "y": 10, "z": 0 }, + * "normal": { "x": 0, "y": 0, "z": -1 }, + * "up": { "x": 0, "y": -1, "z": 0 }, + * "height": 24 + * }], + * "clipping_planes": [{ + * "location": { "x": 0.0, "y": 0.0, "z": 0.0 }, + * "direction": { "x": 0.5, "y": 0.0, "z": 0.5 } + * }], + * "snapshot": { + * "snapshot_type": "png", + * "snapshot_data": "data:image/png;base64,......" + * }, + * "components": { + * "visibility": { + * "default_visibility": false, + * "exceptions": [{ + * "ifc_guid": "4$cshxZO9AJBebsni$z9Yk", + * "originating_system": "xeokit.io", + * "authoring_tool_id": "xeokit/v3.2" + * }, + * //... + * ] + * }, + * "selection": [{ + * "ifc_guid": "4$cshxZO9AJBebsni$z9Yk", + * }, + * //... + * ] + * } + * } + * ```` + * + * ## Saving View Setup Hints + * + * BCFViewpointsPlugin can optionally save hints in the viewpoint, which indicate how to set up the view when + * loading it again. + * + * Here's the {@link BCFViewpointsPlugin#getViewpoint} call again, this time saving some hints: + * + * ````javascript + * const viewpoint = bcfViewpoints.getViewpoint({ // Options + * spacesVisible: true, // Force IfcSpace types visible in the viewpoint (default is false) + * spaceBoundariesVisible: false, // Show IfcSpace boundaries in the viewpoint (default is false) + * openingsVisible: true // Force IfcOpening types visible in the viewpoint (default is false) + * }); + * ```` + * + * ## Loading a BCF Viewpoint + * + * Assuming that we have our BCF viewpoint in a JSON object, let's now restore it with {@link BCFViewpointsPlugin#setViewpoint}: + * + * ````javascript + * bcfViewpoints.setViewpoint(viewpoint); + * ```` + * + * ## Handling BCF Incompatibility with xeokit's Camera + * + * xeokit's {@link Camera#look} is the current 3D *point-of-interest* (POI). + * + * A BCF viewpoint, however, has a direction vector instead of a POI, and so {@link BCFViewpointsPlugin#getViewpoint} saves + * xeokit's POI as a normalized vector from {@link Camera#eye} to {@link Camera#look}, which unfortunately loses + * that positional information. Loading the viewpoint with {@link BCFViewpointsPlugin#setViewpoint} will restore {@link Camera#look} to + * the viewpoint's camera position, offset by the normalized vector. + * + * As shown below, providing a ````rayCast```` option to ````setViewpoint```` will set {@link Camera#look} to the closest + * surface intersection on the direction vector. Internally, ````setViewpoint```` supports this option by firing a ray + * along the vector, and if that hits an {@link Entity}, sets {@link Camera#look} to ray's intersection point with the + * Entity's surface. + * + * ````javascript + * bcfViewpoints.setViewpoint(viewpoint, { + * rayCast: true // <<--------------- Attempt to set Camera#look to surface intersection point (default) + * }); + * ```` + * + * ## Dealing With Loaded Models that are not in the Viewpoint + * + * If, for example, we load model "duplex", hide some objects, then save a BCF viewpoint with + * ````BCFViewpointsPlugin#getViewpoint````, then load another model, "schependomlaan", then load the viewpoint again + * with ````BCFViewpointsPlugin#setViewpoint````, then sometimes all of the objects in model "schependomlaan" become + * visible, along with the visible objects in the viewpoint, which belong to model "duplex". + * + * The reason is that, when saving a BCF viewpoint, BCF logic works like the following pseudo code: + * + * ```` + * If numVisibleObjects < numInvisibleObjects + * save IDs of visible objects in BCF + * exceptions = "visible objects" + * else + * save IDS of invisible objects in BCF + * exceptions = "invisible objects" + * ```` + * + * When loading the viewpoint again: + * + * ```` + * If exceptions = "visible objects" + * hide all objects + * show visible objects in BCF + * else + * show all objects + * hide invisible objects in BCF + * ```` + * + * When the exception is "visible objects", loading the viewpoint shows all the objects in the first, which includes + * objects in "schependomlaan", which can be confusing, because those were not even loaded when we first + * saved the viewpoint.. + * + * To solve this, we can supply a ````defaultInvisible```` option to {@link BCFViewpointsPlugin#getViewpoint}, which + * will force the plugin to save the IDs of all visible objects while making invisible objects the exception. + * + * That way, when we load the viewpoint again, after loading model "schependomlaan", the plugin will hide all objects + * in the scene first (which will include objects belonging to model "schependomlaan"), then make the objects in the + * viewpoint visible (which will only be those of object "duplex"). + * + * ````javascript + * const viewpoint = bcfViewpoints.getViewpoint({ // Options + * //.. + * defaultInvisible: true + * }); + * ```` + * + * [[Run an example](http://xeokit.github.io/xeokit-sdk/examples/#BCF_LoadViewpoint_defaultInvisible)] + * + * ## Behaviour with XKTLoaderPlugin globalizeObjectIds + * + * Whenever we use {@link XKTLoaderPlugin} to load duplicate copies of the same model, after configuring + * {@link XKTLoaderPlugin#globalizeObjectIds} ````true```` to avoid ````Entity```` ID clashes, this has consequences + * for BCF viewpoints created by {@link BCFViewpointsPlugin#getViewpoint}. + * + * When no duplicate copies of a model are loaded like this, viewpoints created by {@link BCFViewpointsPlugin#getViewpoint} will + * continue to load as usual in other BIM viewers. Conversely, a viewpoint created for a single model in other BIM viewers + * will continue to load as usual with ````BCFViewpointsPlugin````. + * + * When duplicate copies of a model are loaded, however, viewpoints created by {@link BCFViewpointsPlugin#getViewpoint} + * will contain certain changes that will affect the viewpoint's portability, however. Such viewpoints will + * use ````authoring_tool_id```` fields to save the globalized ````Entity#id```` values, which enables the viewpoints to + * capture the states of the individual ````Entitys```` that represent the duplicate IFC elements. Take a look at the + * following two examples to learn more. + * + * * [Example: Saving a BCF viewpoint containing duplicate models](https://xeokit.github.io/xeokit-sdk/examples/#BCF_SaveViewpoint_MultipleModels) + * * [Example: Loading a BCF viewpoint containing duplicate models](https://xeokit.github.io/xeokit-sdk/examples/#BCF_LoadViewpoint_MultipleModels) + * + * **Caveat:** when loading a BCF viewpoint, we always assume that we have loaded in our target BIM viewer the same models that were + * loaded in the viewpoint's original authoring application when the viewpoint was created. In the case of multi-model + * viewpoints, the target BIM viewer, whether it be xeokit or another BIM viewer, will need to first have those exact + * models loaded, with their objects having globalized IDs, following the same prefixing scheme we're using in + * xeokit. Then, the viewpoint's ````authoring_tool_id```` fields will be able to resolve to their objects within the + * target viewer. + * + * @class BCFViewpointsPlugin + */ +class BCFViewpointsPlugin extends Plugin { - if (this._aUV) { - this._aUV.bindArrayBuffer(state.uvBuf); - } + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="BCFViewpoints"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {String} [cfg.originatingSystem] Identifies the originating system for BCF records. + * @param {String} [cfg.authoringTool] Identifies the authoring tool for BCF records. + */ + constructor(viewer, cfg = {}) { - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); - } + super("BCFViewpoints", viewer, cfg); - if (this._aMetallicRoughness) { - this._aMetallicRoughness.bindArrayBuffer(state.metallicRoughnessBuf); - } + /** + * Identifies the originating system to include in BCF viewpoints saved by this plugin. + * @property originatingSystem + * @type {string} + */ + this.originatingSystem = cfg.originatingSystem || "xeokit.io"; - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } + /** + * Identifies the authoring tool to include in BCF viewpoints saved by this plugin. + * @property authoringTool + * @type {string} + */ + this.authoringTool = cfg.authoringTool || "xeokit.io"; + } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + /** + * Saves viewer state to a BCF viewpoint. + * + * See ````BCFViewpointsPlugin```` class comments for more info. + * + * @param {*} [options] Options for getting the viewpoint. + * @param {Boolean} [options.spacesVisible=false] Indicates whether ````IfcSpace```` types should be forced visible in the viewpoint. + * @param {Boolean} [options.openingsVisible=false] Indicates whether ````IfcOpening```` types should be forced visible in the viewpoint. + * @param {Boolean} [options.spaceBoundariesVisible=false] Indicates whether the boundaries of ````IfcSpace```` types should be visible in the viewpoint. + * @param {Boolean} [options.snapshot=true] Indicates whether the snapshot should be included in the viewpoint. + * @param {Boolean} [options.defaultInvisible=false] When ````true````, will save the default visibility of all objects + * as ````false````. This means that when we load the viewpoint again, and there are additional models loaded that + * were not saved in the viewpoint, those models will be hidden when we load the viewpoint, and that only the + * objects in the viewpoint will be visible. + * @param {Boolean} [options.reverseClippingPlanes=false] When ````true````, clipping planes are reversed (https://github.com/buildingSMART/BCF-XML/issues/193) + * @returns {*} BCF JSON viewpoint object + */ + getViewpoint(options = {}) { + const scene = this.viewer.scene; + const camera = scene.camera; + const realWorldOffset = scene.realWorldOffset; + const reverseClippingPlanes = (options.reverseClippingPlanes === true); + let bcfViewpoint = {}; - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + // Camera + let lookDirection = math.normalizeVec3(math.subVec3(camera.look, camera.eye, math.vec3())); + let eye = camera.eye; + let up = camera.up; - if (lightsState.reflectionMaps.length > 0 && lightsState.reflectionMaps[0].texture && this._uReflectionMap) { - this._program.bindTexture(this._uReflectionMap, lightsState.reflectionMaps[0].texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; + if (camera.yUp) { + // BCF is Z up + lookDirection = YToZ(lookDirection); + eye = YToZ(eye); + up = YToZ(up); } - if (lightsState.lightMaps.length > 0 && lightsState.lightMaps[0].texture && this._uLightMap) { - this._program.bindTexture(this._uLightMap, lightsState.lightMaps[0].texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; - } + const camera_view_point = xyzArrayToObject(math.addVec3(eye, realWorldOffset)); - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$5[0] = viewportWidth; - tempVec4$5[1] = viewportHeight; - tempVec4$5[2] = sao.blendCutoff; - tempVec4$5[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$5); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; - } + if (camera.projection === "ortho") { + bcfViewpoint.orthogonal_camera = { + camera_view_point: camera_view_point, + camera_direction: xyzArrayToObject(lookDirection), + camera_up_vector: xyzArrayToObject(up), + view_to_world_scale: camera.ortho.scale, + }; + } else { + bcfViewpoint.perspective_camera = { + camera_view_point: camera_view_point, + camera_direction: xyzArrayToObject(lookDirection), + camera_up_vector: xyzArrayToObject(up), + field_of_view: camera.perspective.fov, + }; } - this._program.bindTexture(this._uBaseColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uMetallicRoughMap, textureSet.metallicRoughnessTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uEmissiveMap, textureSet.emissiveTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uNormalMap, textureSet.normalsTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uAOMap, textureSet.occlusionTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - - state.indicesBuf.bind(); - - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + // Section planes - frameCtx.drawElements++; - } + const sectionPlanes = scene.sectionPlanes; + for (let id in sectionPlanes) { + if (sectionPlanes.hasOwnProperty(id)) { + let sectionPlane = sectionPlanes[id]; - _allocate() { + let location = sectionPlane.pos; - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; + let direction; + if (reverseClippingPlanes) { + direction = math.negateVec3(sectionPlane.dir, math.vec3()); + } else { + direction = sectionPlane.dir; + } - this._program = new Program(gl, this._buildShader()); + if (camera.yUp) { + // BCF is Z up + location = YToZ(location); + direction = YToZ(direction); + } + math.addVec3(location, realWorldOffset); - if (this._program.errors) { - this.errors = this._program.errors; - return; + location = xyzArrayToObject(location); + direction = xyzArrayToObject(direction); + if (!bcfViewpoint.clipping_planes) { + bcfViewpoint.clipping_planes = []; + } + bcfViewpoint.clipping_planes.push({location, direction}); + } } - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); + // Lines - this._uGammaFactor = program.getLocation("gammaFactor"); + const lineSets = scene.lineSets; + for (let id in lineSets) { + if (lineSets.hasOwnProperty(id)) { + const lineSet = lineSets[id]; + if (!bcfViewpoint.lines) { + bcfViewpoint.lines = []; + } + const positions = lineSet.positions; + const indices = lineSet.indices; + for (let i = 0, len = indices.length / 2; i < len; i++) { + const a = indices[i * 2]; + const b = indices[(i * 2) + 1]; + bcfViewpoint.lines.push({ + start_point: { + x: positions[a * 3 + 0], + y: positions[a * 3 + 1], + z: positions[a * 3 + 2] + }, + end_point: { + x: positions[b * 3 + 0], + y: positions[b * 3 + 1], + z: positions[b * 3 + 2] + } + }); + } - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; + } + } - const lights = lightsState.lights; - let light; + // Bitmaps - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; + const bitmaps = scene.bitmaps; + for (let id in bitmaps) { + if (bitmaps.hasOwnProperty(id)) { + let bitmap = bitmaps[id]; + let location = bitmap.pos; + let normal = bitmap.normal; + let up = bitmap.up; + if (camera.yUp) { + // BCF is Z up + location = YToZ(location); + normal = YToZ(normal); + up = YToZ(up); + } + math.addVec3(location, realWorldOffset); + if (!bcfViewpoint.bitmaps) { + bcfViewpoint.bitmaps = []; + } + bcfViewpoint.bitmaps.push({ + bitmap_type: bitmap.type, + bitmap_data: bitmap.imageData, + location: xyzArrayToObject(location), + normal: xyzArrayToObject(normal), + up: xyzArrayToObject(up), + height: bitmap.height + }); } } - if (lightsState.reflectionMaps.length > 0) { - this._uReflectionMap = "reflectionMap"; - } + // Entity states - if (lightsState.lightMaps.length > 0) { - this._uLightMap = "lightMap"; - } + bcfViewpoint.components = { + visibility: { + view_setup_hints: { + spaces_visible: !!options.spacesVisible, + space_boundaries_visible: !!options.spaceBoundariesVisible, + openings_visible: !!options.openingsVisible + } + } + }; - this._uSectionPlanes = []; + const opacityObjectIds = new Set(scene.opacityObjectIds); + const xrayedObjectIds = new Set(scene.xrayedObjectIds); + const colorizedObjectIds = new Set(scene.colorizedObjectIds); - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + const coloringMap = Object.values(scene.objects) + .filter(entity => opacityObjectIds.has(entity.id) || colorizedObjectIds.has(entity.id) || xrayedObjectIds.has(entity.id)) + .reduce((coloringMap, entity) => { - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aNormal = program.getAttribute("normal"); - this._aUV = program.getAttribute("uv"); - this._aColor = program.getAttribute("color"); - this._aMetallicRoughness = program.getAttribute("metallicRoughness"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + let color = colorizeToRGB(entity.colorize); + let alpha; - this._uBaseColorMap = "uBaseColorMap"; - this._uMetallicRoughMap = "uMetallicRoughMap"; - this._uEmissiveMap = "uEmissiveMap"; - this._uNormalMap = "uNormalMap"; - this._uAOMap = "uAOMap"; + if (entity.xrayed) { + if (scene.xrayMaterial.fillAlpha === 0.0 && scene.xrayMaterial.edgeAlpha !== 0.0) { + // BCF can't deal with edges. If xRay is implemented only with edges, set an arbitrary opacity + alpha = 0.1; + } else { + alpha = scene.xrayMaterial.fillAlpha; + } + alpha = Math.round(alpha * 255).toString(16).padStart(2, "0"); + color = alpha + color; + } else if (opacityObjectIds.has(entity.id)) { + alpha = Math.round(entity.opacity * 255).toString(16).padStart(2, "0"); + color = alpha + color; + } - if (this._withSAO) { - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); - } + if (!coloringMap[color]) { + coloringMap[color] = []; + } - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } - } + const objectId = entity.id; + const originalSystemId = entity.originalSystemId; + const component = { + ifc_guid: originalSystemId, + originating_system: this.originatingSystem + }; + if (originalSystemId !== objectId) { + component.authoring_tool_id = objectId; + } - _bindProgram(frameCtx) { - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const lightsState = scene._lightsState; - const lights = lightsState.lights; - const project = scene.camera.project; + coloringMap[color].push(component); - program.bind(); + return coloringMap; - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + }, {}); - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); - } + const coloringArray = Object.entries(coloringMap).map(([color, components]) => { + return {color, components}; + }); - for (let i = 0, len = lights.length; i < len; i++) { + bcfViewpoint.components.coloring = coloringArray; - const light = lights[i]; + const objectIds = scene.objectIds; + const visibleObjects = scene.visibleObjects; + const visibleObjectIds = scene.visibleObjectIds; + const invisibleObjectIds = objectIds.filter(id => !visibleObjects[id]); + const selectedObjectIds = scene.selectedObjectIds; - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); - } - } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } + if (options.defaultInvisible || visibleObjectIds.length < invisibleObjectIds.length) { + bcfViewpoint.components.visibility.exceptions = this._createBCFComponents(visibleObjectIds); + bcfViewpoint.components.visibility.default_visibility = false; + } else { + bcfViewpoint.components.visibility.exceptions = this._createBCFComponents(invisibleObjectIds); + bcfViewpoint.components.visibility.default_visibility = true; } - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + bcfViewpoint.components.selection = this._createBCFComponents(selectedObjectIds); - if (this._uGammaFactor) { - gl.uniform1f(this._uGammaFactor, scene.gammaFactor); + if (options.snapshot !== false) { + bcfViewpoint.snapshot = { + snapshot_type: "png", + snapshot_data: this.viewer.getSnapshot({format: "png"}) + }; } + + return bcfViewpoint; } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + _createBCFComponents(objectIds) { + const scene = this.viewer.scene; + const components = []; + for (let i = 0, len = objectIds.length; i < len; i++) { + const objectId = objectIds[i]; + const entity = scene.objects[objectId]; + if (entity) { + const component = { + ifc_guid: entity.originalSystemId, + originating_system: this.originatingSystem + }; + if (entity.originalSystemId !== objectId) { + component.authoring_tool_id = objectId; + } + components.push(component); + } + } + return components; } - _buildVertexShader() { + /** + * Sets viewer state to the given BCF viewpoint. + * + * Note that xeokit's {@link Camera#look} is the **point-of-interest**, whereas the BCF ````camera_direction```` is a + * direction vector. Therefore, when loading a BCF viewpoint, we set {@link Camera#look} to the absolute position + * obtained by offsetting the BCF ````camera_view_point```` along ````camera_direction````. + * + * When loading a viewpoint, we also have the option to find {@link Camera#look} as the closest point of intersection + * (on the surface of any visible and pickable {@link Entity}) with a 3D ray fired from ````camera_view_point```` in + * the direction of ````camera_direction````. + * + * @param {*} bcfViewpoint BCF JSON viewpoint object, + * shows default visible entities and restores camera to initial default position. + * @param {*} [options] Options for setting the viewpoint. + * @param {Boolean} [options.rayCast=true] When ````true```` (default), will attempt to set {@link Camera#look} to the closest + * point of surface intersection with a ray fired from the BCF ````camera_view_point```` in the direction of ````camera_direction````. + * @param {Boolean} [options.immediate=true] When ````true```` (default), immediately set camera position. + * @param {Boolean} [options.duration] Flight duration in seconds. Overrides {@link CameraFlightAnimation#duration}. Only applies when ````immediate```` is ````false````. + * @param {Boolean} [options.reset=true] When ````true```` (default), set {@link Entity#xrayed} and {@link Entity#highlighted} ````false```` on all scene objects. + * @param {Boolean} [options.reverseClippingPlanes=false] When ````true````, clipping planes are reversed (https://github.com/buildingSMART/BCF-XML/issues/193) + * @param {Boolean} [options.updateCompositeObjects=false] When ````true````, then when visibility and selection updates refer to composite objects (eg. an IfcBuildingStorey), + * then this method will apply the updates to objects within those composites. + */ + setViewpoint(bcfViewpoint, options = {}) { + if (!bcfViewpoint) { + return; + } - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const clippingCaps = sectionPlanesState.clippingCaps; + const viewer = this.viewer; + const scene = viewer.scene; + const camera = scene.camera; + const rayCast = (options.rayCast !== false); + const immediate = (options.immediate !== false); + const reset = (options.reset !== false); + const realWorldOffset = scene.realWorldOffset; + const reverseClippingPlanes = (options.reverseClippingPlanes === true); - const src = []; + scene.clearSectionPlanes(); - src.push("#version 300 es"); - src.push("// Triangles batching quality draw vertex shader"); + if (bcfViewpoint.clipping_planes) { + bcfViewpoint.clipping_planes.forEach(function (e) { + let pos = xyzObjectToArray(e.location, tempVec3$4); + let dir = xyzObjectToArray(e.direction, tempVec3$4); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("precision highp usampler2D;"); - src.push("precision highp isampler2D;"); - src.push("precision highp sampler2D;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("precision mediump usampler2D;"); - src.push("precision mediump isampler2D;"); - src.push("precision mediump sampler2D;"); - src.push("#endif"); + if (reverseClippingPlanes) { + math.negateVec3(dir); + } + math.subVec3(pos, realWorldOffset); - src.push("uniform int renderPass;"); + if (camera.yUp) { + pos = ZToY(pos); + dir = ZToY(dir); + } + new SectionPlane(scene, {pos, dir}); + }); + } - src.push("in vec3 position;"); - src.push("in vec3 normal;"); - src.push("in vec4 color;"); - src.push("in vec2 uv;"); - src.push("in vec2 metallicRoughness;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + scene.clearLines(); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); + if (bcfViewpoint.lines) { + const positions = []; + const indices = []; + let i = 0; + bcfViewpoint.lines.forEach((e) => { + if (!e.start_point) { + return; + } + if (!e.end_point) { + return; + } + positions.push(e.start_point.x); + positions.push(e.start_point.y); + positions.push(e.start_point.z); + positions.push(e.end_point.x); + positions.push(e.end_point.y); + positions.push(e.end_point.z); + indices.push(i++); + indices.push(i++); + }); + new LineSet(scene, { + positions, + indices, + clippable: false, + collidable: true + }); } - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); + scene.clearBitmaps(); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform mat3 uvDecodeMatrix;"); + if (bcfViewpoint.bitmaps) { + bcfViewpoint.bitmaps.forEach(function (e) { + const bitmap_type = e.bitmap_type || "jpg"; // "jpg" | "png" + const bitmap_data = e.bitmap_data; // base64 + let location = xyzObjectToArray(e.location, tempVec3a$X); + let normal = xyzObjectToArray(e.normal, tempVec3b$9); + let up = xyzObjectToArray(e.up, tempVec3c$6); + let height = e.height || 1; + if (!bitmap_type) { + return; + } + if (!bitmap_data) { + return; + } + if (!location) { + return; + } + if (!normal) { + return; + } + if (!up) { + return; + } + if (camera.yUp) { + location = ZToY(location); + normal = ZToY(normal); + up = ZToY(up); + } + new Bitmap(scene, { + src: bitmap_data, + type: bitmap_type, + pos: location, + normal: normal, + up: up, + clippable: false, + collidable: true, + height + }); + }); + } - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); + if (reset) { + scene.setObjectsXRayed(scene.xrayedObjectIds, false); + scene.setObjectsHighlighted(scene.highlightedObjectIds, false); + scene.setObjectsSelected(scene.selectedObjectIds, false); } - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); + if (bcfViewpoint.components) { - src.push("out vec4 vViewPosition;"); - src.push("out vec3 vViewNormal;"); - src.push("out vec4 vColor;"); - src.push("out vec2 vUV;"); - src.push("out vec2 vMetallicRoughness;"); + if (bcfViewpoint.components.visibility) { - if (lightsState.lightMaps.length > 0) { - src.push("out vec3 vWorldNormal;"); - } + if (!bcfViewpoint.components.visibility.default_visibility) { + scene.setObjectsVisible(scene.objectIds, false); + if (bcfViewpoint.components.visibility.exceptions) { + bcfViewpoint.components.visibility.exceptions.forEach((component) => this._withBCFComponent(options, component, entity => entity.visible = true)); + } + } else { + scene.setObjectsVisible(scene.objectIds, true); + if (bcfViewpoint.components.visibility.exceptions) { + bcfViewpoint.components.visibility.exceptions.forEach((component) => this._withBCFComponent(options, component, entity => entity.visible = false)); + } + } - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - if (clippingCaps) { - src.push("out vec4 vClipPosition;"); + const view_setup_hints = bcfViewpoint.components.visibility.view_setup_hints; + if (view_setup_hints) { + if (view_setup_hints.spaces_visible === false) { + scene.setObjectsVisible(viewer.metaScene.getObjectIDsByType("IfcSpace"), false); + } + if (view_setup_hints.openings_visible === false) { + scene.setObjectsVisible(viewer.metaScene.getObjectIDsByType("IfcOpening"), false); + } + if (view_setup_hints.space_boundaries_visible !== undefined) ; + } } - } - src.push("void main(void) {"); + if (bcfViewpoint.components.selection) { + scene.setObjectsSelected(scene.selectedObjectIds, false); + bcfViewpoint.components.selection.forEach(component => this._withBCFComponent(options, component, entity => entity.selected = true)); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + } - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + if (bcfViewpoint.components.coloring) { + bcfViewpoint.components.coloring.forEach(coloring => { - src.push("} else {"); + let color = coloring.color; + let alpha = 0; + let alphaDefined = false; - src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push("worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); - src.push("vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); + if (color.length === 8) { + alpha = parseInt(color.substring(0, 2), 16) / 256; + if (alpha <= 1.0 && alpha >= 0.95) { + alpha = 1.0; + } + color = color.substring(2); + alphaDefined = true; + } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - src.push("vFragDepth = 1.0 + clipPos.w;"); - } + const colorize = [ + parseInt(color.substring(0, 2), 16) / 256, + parseInt(color.substring(2, 4), 16) / 256, + parseInt(color.substring(4, 6), 16) / 256 + ]; - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - if (clippingCaps) { - src.push("vClipPosition = clipPos;"); + coloring.components.map(component => + this._withBCFComponent(options, component, entity => { + entity.colorize = colorize; + if (alphaDefined) { + entity.opacity = alpha; + } + })); + }); } } - src.push("vViewPosition = viewPosition;"); - src.push("vViewNormal = viewNormal;"); - src.push("vColor = color;"); - src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); - src.push("vMetallicRoughness = metallicRoughness;"); + if (bcfViewpoint.perspective_camera || bcfViewpoint.orthogonal_camera) { + let eye; + let look; + let up; + let projection; - if (lightsState.lightMaps.length > 0) { - src.push("vWorldNormal = worldNormal.xyz;"); - } + if (bcfViewpoint.perspective_camera) { + eye = xyzObjectToArray(bcfViewpoint.perspective_camera.camera_view_point, tempVec3$4); + look = xyzObjectToArray(bcfViewpoint.perspective_camera.camera_direction, tempVec3$4); + up = xyzObjectToArray(bcfViewpoint.perspective_camera.camera_up_vector, tempVec3$4); - src.push("gl_Position = clipPos;"); - src.push("}"); + camera.perspective.fov = bcfViewpoint.perspective_camera.field_of_view; - src.push("}"); - return src; - } + projection = "perspective"; + } else { + eye = xyzObjectToArray(bcfViewpoint.orthogonal_camera.camera_view_point, tempVec3$4); + look = xyzObjectToArray(bcfViewpoint.orthogonal_camera.camera_direction, tempVec3$4); + up = xyzObjectToArray(bcfViewpoint.orthogonal_camera.camera_up_vector, tempVec3$4); - _buildFragmentShader() { + camera.ortho.scale = bcfViewpoint.orthogonal_camera.view_to_world_scale; - const scene = this._scene; - const gammaOutput = scene.gammaOutput; // If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is false. - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const clippingCaps = sectionPlanesState.clippingCaps; - const src = []; + projection = "ortho"; + } - src.push('#version 300 es'); - src.push("// Triangles batching quality draw fragment shader"); + math.subVec3(eye, realWorldOffset); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); + if (camera.yUp) { + eye = ZToY(eye); + look = ZToY(look); + up = ZToY(up); + } - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + if (rayCast) { + const hit = scene.pick({ + pickSurface: true, // <<------ This causes picking to find the intersection point on the entity + origin: eye, + direction: look + }); + look = (hit ? hit.worldPos : math.addVec3(eye, look, tempVec3$4)); + } else { + look = math.addVec3(eye, look, tempVec3$4); + } + + if (immediate) { + camera.eye = eye; + camera.look = look; + camera.up = up; + camera.projection = projection; + } else { + viewer.cameraFlight.flyTo({eye, look, up, duration: options.duration, projection}); + } } + } - src.push("uniform sampler2D uBaseColorMap;"); - src.push("uniform sampler2D uMetallicRoughMap;"); - src.push("uniform sampler2D uEmissiveMap;"); - src.push("uniform sampler2D uNormalMap;"); - src.push("uniform sampler2D uAOMap;"); + _withBCFComponent(options, component, callback) { - src.push("in vec4 vViewPosition;"); - src.push("in vec3 vViewNormal;"); - src.push("in vec4 vColor;"); - src.push("in vec2 vUV;"); - src.push("in vec2 vMetallicRoughness;"); + const viewer = this.viewer; + const scene = viewer.scene; - if (lightsState.lightMaps.length > 0) { - src.push("in vec3 vWorldNormal;"); - } + if (component.authoring_tool_id && component.originating_system === this.originatingSystem) { - src.push("uniform mat4 viewMatrix;"); + const id = component.authoring_tool_id; + const entity = scene.objects[id]; - if (lightsState.reflectionMaps.length > 0) { - src.push("uniform samplerCube reflectionMap;"); - } + if (entity) { + callback(entity); + return + } - if (lightsState.lightMaps.length > 0) { - src.push("uniform samplerCube lightMap;"); + if (options.updateCompositeObjects) { + const metaObject = viewer.metaScene.metaObjects[id]; + if (metaObject) { + scene.withObjects(viewer.metaScene.getObjectIDsInSubtree(id), callback); + return; + } + } } - src.push("uniform vec4 lightAmbient;"); + if (component.ifc_guid) { - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); + const originalSystemId = component.ifc_guid; + const entity = scene.objects[originalSystemId]; + + if (entity) { + callback(entity); + return; } - } - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); + if (options.updateCompositeObjects) { + const metaObject = viewer.metaScene.metaObjects[originalSystemId]; + if (metaObject) { + scene.withObjects(viewer.metaScene.getObjectIDsInSubtree(originalSystemId), callback); + return; + } + } - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + Object.keys(scene.models).forEach((modelId) => { - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); - } + const id = math.globalizeObjectId(modelId, originalSystemId); + const entity = scene.objects[id]; - src.push("uniform float gammaFactor;"); - src.push("vec4 linearToLinear( in vec4 value ) {"); - src.push(" return value;"); - src.push("}"); - src.push("vec4 sRGBToLinear( in vec4 value ) {"); - src.push(" return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );"); - src.push("}"); - src.push("vec4 gammaToLinear( in vec4 value) {"); - src.push(" return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );"); - src.push("}"); + if (entity) { + callback(entity); + return; + } - if (gammaOutput) { - src.push("vec4 linearToGamma( in vec4 value, in float gammaFactor ) {"); - src.push(" return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );"); - src.push("}"); - } + if (options.updateCompositeObjects) { + const metaObject = viewer.metaScene.metaObjects[id]; + if (metaObject) { + scene.withObjects(viewer.metaScene.getObjectIDsInSubtree(id), callback); - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - if (clippingCaps) { - src.push("in vec4 vClipPosition;"); - } - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } + } + } + }); } + } - // CONSTANT DEFINITIONS - - src.push("#define PI 3.14159265359"); - src.push("#define RECIPROCAL_PI 0.31830988618"); - src.push("#define RECIPROCAL_PI2 0.15915494"); - src.push("#define EPSILON 1e-6"); - - src.push("#define saturate(a) clamp( a, 0.0, 1.0 )"); + /** + * Destroys this BCFViewpointsPlugin. + */ + destroy() { + super.destroy(); + } +} - // UTILITY DEFINITIONS +function xyzArrayToObject(arr) { + return {"x": arr[0], "y": arr[1], "z": arr[2]}; +} - src.push("vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {"); - src.push(" vec3 texel = texture( uNormalMap, uv ).xyz;"); - src.push(" if (texel.x == 0.0 && texel.y == 0.0 && texel.z == 0.0) {"); - src.push(" return surf_norm;"); - src.push(" }"); - src.push(" vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );"); - src.push(" vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );"); - src.push(" vec2 st0 = dFdx( uv.st );"); - src.push(" vec2 st1 = dFdy( uv.st );"); - src.push(" vec3 S = normalize( q0 * st1.t - q1 * st0.t );"); - src.push(" vec3 T = normalize( -q0 * st1.s + q1 * st0.s );"); - src.push(" vec3 N = normalize( surf_norm );"); - src.push(" vec3 mapN = texel.xyz * 2.0 - 1.0;"); - src.push(" mat3 tsn = mat3( S, T, N );"); - //src.push(" mapN *= 3.0;"); - src.push(" return normalize( tsn * mapN );"); - src.push("}"); +function xyzObjectToArray(xyz, arry) { + arry = new Float64Array(3); + arry[0] = xyz.x; + arry[1] = xyz.y; + arry[2] = xyz.z; + return arry; +} - src.push("vec3 inverseTransformDirection(in vec3 dir, in mat4 matrix) {"); - src.push(" return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );"); - src.push("}"); +function YToZ(vec) { + return new Float64Array([vec[0], -vec[2], vec[1]]); +} - // STRUCTURES +function ZToY(vec) { + return new Float64Array([vec[0], vec[2], -vec[1]]); +} - src.push("struct IncidentLight {"); - src.push(" vec3 color;"); - src.push(" vec3 direction;"); - src.push("};"); +function colorizeToRGB(color) { + let rgb = ""; + rgb += Math.round(color[0] * 255).toString(16).padStart(2, "0"); + rgb += Math.round(color[1] * 255).toString(16).padStart(2, "0"); + rgb += Math.round(color[2] * 255).toString(16).padStart(2, "0"); + return rgb; +} - src.push("struct ReflectedLight {"); - src.push(" vec3 diffuse;"); - src.push(" vec3 specular;"); - src.push("};"); +var distVec3 = math.vec3(); - src.push("struct Geometry {"); - src.push(" vec3 position;"); - src.push(" vec3 viewNormal;"); - src.push(" vec3 worldNormal;"); - src.push(" vec3 viewEyeDir;"); - src.push("};"); +const lengthWire = (x1, y1, x2, y2) => { + var a = x1 - x2; + var b = y1 - y2; + return Math.sqrt(a * a + b * b); +}; - src.push("struct Material {"); - src.push(" vec3 diffuseColor;"); - src.push(" float specularRoughness;"); - src.push(" vec3 specularColor;"); - src.push(" float shine;"); // Only used for Phong - src.push("};"); +/** + * @desc Measures the distance between two 3D points. + * + * See {@link DistanceMeasurementsPlugin} for more info. + */ +class DistanceMeasurement extends Component { - // IRRADIANCE EVALUATION + /** + * @private + */ + constructor(plugin, cfg = {}) { - src.push("float GGXRoughnessToBlinnExponent(const in float ggxRoughness) {"); - src.push(" float r = ggxRoughness + 0.0001;"); - src.push(" return (2.0 / (r * r) - 2.0);"); - src.push("}"); + super(plugin.viewer.scene, cfg); - src.push("float getSpecularMIPLevel(const in float blinnShininessExponent, const in int maxMIPLevel) {"); - src.push(" float maxMIPLevelScalar = float( maxMIPLevel );"); - src.push(" float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( ( blinnShininessExponent * blinnShininessExponent ) + 1.0 );"); - src.push(" return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );"); - src.push("}"); + /** + * The {@link DistanceMeasurementsPlugin} that owns this DistanceMeasurement. + * @type {DistanceMeasurementsPlugin} + */ + this.plugin = plugin; - if (lightsState.reflectionMaps.length > 0) { - src.push("vec3 getLightProbeIndirectRadiance(const in vec3 reflectVec, const in float blinnShininessExponent, const in int maxMIPLevel) {"); - src.push(" float mipLevel = 0.5 * getSpecularMIPLevel(blinnShininessExponent, maxMIPLevel);"); //TODO: a random factor - fix this - src.push(" vec3 envMapColor = sRGBToLinear(texture(reflectionMap, reflectVec, mipLevel)).rgb;"); - src.push(" return envMapColor;"); - src.push("}"); + this._container = cfg.container; + if (!this._container) { + throw "config missing: container"; } - // SPECULAR BRDF EVALUATION + this._eventSubs = {}; - src.push("vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) {"); - src.push(" float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );"); - src.push(" return ( 1.0 - specularColor ) * fresnel + specularColor;"); - src.push("}"); + var scene = this.plugin.viewer.scene; - src.push("float G_GGX_Smith(const in float alpha, const in float dotNL, const in float dotNV) {"); - src.push(" float a2 = ( alpha * alpha );"); - src.push(" float gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); - src.push(" float gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); - src.push(" return 1.0 / ( gl * gv );"); - src.push("}"); + this._originMarker = new Marker(scene, cfg.origin); + this._targetMarker = new Marker(scene, cfg.target); - src.push("float G_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) {"); - src.push(" float a2 = ( alpha * alpha );"); - src.push(" float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); - src.push(" float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); - src.push(" return 0.5 / max( gv + gl, EPSILON );"); - src.push("}"); + this._originWorld = math.vec3(); + this._targetWorld = math.vec3(); - src.push("float D_GGX(const in float alpha, const in float dotNH) {"); - src.push(" float a2 = ( alpha * alpha );"); - src.push(" float denom = ( dotNH * dotNH) * ( a2 - 1.0 ) + 1.0;"); - src.push(" return RECIPROCAL_PI * a2 / ( denom * denom);"); - src.push("}"); + this._wp = new Float64Array(24); + this._vp = new Float64Array(24); + this._pp = new Float64Array(24); + this._cp = new Int16Array(8); - src.push("vec3 BRDF_Specular_GGX(const in IncidentLight incidentLight, const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); - src.push(" float alpha = ( roughness * roughness );"); - src.push(" vec3 halfDir = normalize( incidentLight.direction + geometry.viewEyeDir );"); - src.push(" float dotNL = saturate( dot( geometry.viewNormal, incidentLight.direction ) );"); - src.push(" float dotNV = saturate( dot( geometry.viewNormal, geometry.viewEyeDir ) );"); - src.push(" float dotNH = saturate( dot( geometry.viewNormal, halfDir ) );"); - src.push(" float dotLH = saturate( dot( incidentLight.direction, halfDir ) );"); - src.push(" vec3 F = F_Schlick( specularColor, dotLH );"); - src.push(" float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );"); - src.push(" float D = D_GGX( alpha, dotNH );"); - src.push(" return F * (G * D);"); - src.push("}"); + this._xAxisLabelCulled = false; + this._yAxisLabelCulled = false; + this._zAxisLabelCulled = false; - src.push("vec3 BRDF_Specular_GGX_Environment(const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); - src.push(" float dotNV = saturate(dot(geometry.viewNormal, geometry.viewEyeDir));"); - src.push(" const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022);"); - src.push(" const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04);"); - src.push(" vec4 r = roughness * c0 + c1;"); - src.push(" float a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y;"); - src.push(" vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;"); - src.push(" return specularColor * AB.x + AB.y;"); - src.push("}"); + this._color = cfg.color || this.plugin.defaultColor; - if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { - src.push("void computePBRLightMapping(const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); - if (lightsState.lightMaps.length > 0) { - src.push(" vec3 irradiance = sRGBToLinear(texture(lightMap, geometry.worldNormal)).rgb;"); - src.push(" irradiance *= PI;"); - src.push(" vec3 diffuseBRDFContrib = (RECIPROCAL_PI * material.diffuseColor);"); - src.push(" reflectedLight.diffuse += irradiance * diffuseBRDFContrib;"); - } - if (lightsState.reflectionMaps.length > 0) { - src.push(" vec3 reflectVec = reflect(geometry.viewEyeDir, geometry.viewNormal);"); - src.push(" reflectVec = inverseTransformDirection(reflectVec, viewMatrix);"); - src.push(" float blinnExpFromRoughness = GGXRoughnessToBlinnExponent(material.specularRoughness);"); - src.push(" vec3 radiance = getLightProbeIndirectRadiance(reflectVec, blinnExpFromRoughness, 8);"); - src.push(" vec3 specularBRDFContrib = BRDF_Specular_GGX_Environment(geometry, material.specularColor, material.specularRoughness);"); - src.push(" reflectedLight.specular += radiance * specularBRDFContrib;"); - } - src.push("}"); - } + this._originDot = new Dot(this._container, { + fillColor: this._color, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined + }); - // MAIN LIGHTING COMPUTATION FUNCTION + this._targetDot = new Dot(this._container, { + fillColor: this._color, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 2: undefined + }); - src.push("void computePBRLighting(const in IncidentLight incidentLight, const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); - src.push(" float dotNL = saturate(dot(geometry.viewNormal, incidentLight.direction));"); - src.push(" vec3 irradiance = dotNL * incidentLight.color * PI;"); - src.push(" reflectedLight.diffuse += irradiance * (RECIPROCAL_PI * material.diffuseColor);"); - src.push(" reflectedLight.specular += irradiance * BRDF_Specular_GGX(incidentLight, geometry, material.specularColor, material.specularRoughness);"); - src.push("}"); + this._lengthWire = new Wire(this._container, { + color: this._color, + thickness: 2, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined + }); - src.push("out vec4 outColor;"); + this._xAxisWire = new Wire(this._container, { + color: "red", + thickness: 1, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined + }); - src.push("void main(void) {"); + this._yAxisWire = new Wire(this._container, { + color: "green", + thickness: 1, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined + }); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - if (clippingCaps) { - src.push(" if (dist > (0.002 * vClipPosition.w)) {"); - src.push(" discard;"); - src.push(" }"); - src.push(" if (dist > 0.0) { "); - src.push(" outColor=vec4(1.0, 0.0, 0.0, 1.0);"); - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" return;"); - src.push("}"); - } else { - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - } - src.push("}"); - } + this._zAxisWire = new Wire(this._container, { + color: "blue", + thickness: 1, + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 1: undefined + }); - src.push("IncidentLight light;"); - src.push("Material material;"); - src.push("Geometry geometry;"); - src.push("ReflectedLight reflectedLight = ReflectedLight(vec3(0.0,0.0,0.0), vec3(0.0,0.0,0.0));"); + this._lengthLabel = new Label(this._container, { + fillColor: this._color, + prefix: "", + text: "", + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 4: undefined + }); - src.push("vec3 rgb = (vec3(float(vColor.r) / 255.0, float(vColor.g) / 255.0, float(vColor.b) / 255.0));"); - src.push("float opacity = float(vColor.a) / 255.0;"); + this._xAxisLabel = new Label(this._container, { + fillColor: "red", + prefix: "X", + text: "", + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 3: undefined + }); - src.push("vec3 baseColor = rgb;"); - src.push("float specularF0 = 1.0;"); - src.push("float metallic = float(vMetallicRoughness.r) / 255.0;"); - src.push("float roughness = float(vMetallicRoughness.g) / 255.0;"); - src.push("float dielectricSpecular = 0.16 * specularF0 * specularF0;"); + this._yAxisLabel = new Label(this._container, { + fillColor: "green", + prefix: "Y", + text: "", + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 3: undefined + }); - src.push("vec4 baseColorTexel = sRGBToLinear(texture(uBaseColorMap, vUV));"); - src.push("baseColor *= baseColorTexel.rgb;"); - // src.push("opacity *= baseColorTexel.a;"); + this._zAxisLabel = new Label(this._container, { + fillColor: "blue", + prefix: "Z", + text: "", + zIndex: plugin.zIndex !== undefined ? plugin.zIndex + 3: undefined + }); - src.push("vec3 metalRoughTexel = texture(uMetallicRoughMap, vUV).rgb;"); - src.push("metallic *= metalRoughTexel.b;"); - src.push("roughness *= metalRoughTexel.g;"); + this._wpDirty = false; + this._vpDirty = false; + this._cpDirty = false; - src.push("vec3 viewNormal = perturbNormal2Arb(vViewPosition.xyz, normalize(vViewNormal), vUV );"); + this._visible = false; + this._originVisible = false; + this._targetVisible = false; + this._wireVisible = false; + this._axisVisible = false; + this._axisEnabled = true; - src.push("material.diffuseColor = baseColor * (1.0 - dielectricSpecular) * (1.0 - metallic);"); - src.push("material.specularRoughness = clamp(roughness, 0.04, 1.0);"); - src.push("material.specularColor = mix(vec3(dielectricSpecular), baseColor, metallic);"); + this._originMarker.on("worldPos", (value) => { + this._originWorld.set(value || [0, 0, 0]); + this._wpDirty = true; + this._needUpdate(0); // No lag + }); - src.push("geometry.position = vViewPosition.xyz;"); - src.push("geometry.viewNormal = -normalize(viewNormal);"); - src.push("geometry.viewEyeDir = normalize(vViewPosition.xyz);"); + this._targetMarker.on("worldPos", (value) => { + this._targetWorld.set(value || [0, 0, 0]); + this._wpDirty = true; + this._needUpdate(0); // No lag + }); - if (lightsState.lightMaps.length > 0) { - src.push("geometry.worldNormal = normalize(vWorldNormal);"); - } + this._onViewMatrix = scene.camera.on("viewMatrix", () => { + this._vpDirty = true; + this._needUpdate(0); // No lag + }); - if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { - src.push("computePBRLightMapping(geometry, material, reflectedLight);"); - } + this._onProjMatrix = scene.camera.on("projMatrix", () => { + this._cpDirty = true; + this._needUpdate(); + }); - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - if (light.type === "dir") { - if (light.space === "view") { - src.push("light.direction = normalize(lightDir" + i + ");"); - } else { - src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("light.direction = normalize(lightPos" + i + " - vViewPosition.xyz);"); - } else { - src.push("light.direction = normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("light.direction = normalize(lightDir" + i + ");"); - } else { - src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else { - continue; - } + this._onCanvasBoundary = scene.canvas.on("boundary", () => { + this._cpDirty = true; + this._needUpdate(0); // No lag + }); - src.push("light.color = lightColor" + i + ".rgb * lightColor" + i + ".a;"); // a is intensity + this._onMetricsUnits = scene.metrics.on("units", () => { + this._cpDirty = true; + this._needUpdate(); + }); - src.push("computePBRLighting(light, geometry, material, reflectedLight);"); - } + this._onMetricsScale = scene.metrics.on("scale", () => { + this._cpDirty = true; + this._needUpdate(); + }); - src.push("vec3 emissiveColor = sRGBToLinear(texture(uEmissiveMap, vUV)).rgb;"); // TODO: correct gamma function - src.push("float aoFactor = texture(uAOMap, vUV).r;"); + this._onMetricsOrigin = scene.metrics.on("origin", () => { + this._cpDirty = true; + this._needUpdate(); + }); - src.push("vec3 outgoingLight = (lightAmbient.rgb * lightAmbient.a * baseColor * opacity * rgb) + (reflectedLight.diffuse) + (reflectedLight.specular) + emissiveColor;"); - src.push("vec4 fragColor;"); + this.approximate = cfg.approximate; + this.visible = cfg.visible; + this.originVisible = cfg.originVisible; + this.targetVisible = cfg.targetVisible; + this.wireVisible = cfg.wireVisible; + this.axisVisible = cfg.axisVisible; + } - if (this._withSAO) { - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" fragColor = vec4(outgoingLight.rgb * ambient * aoFactor, opacity);"); - } else { - src.push(" fragColor = vec4(outgoingLight.rgb * aoFactor, opacity);"); - } + _update() { - if (gammaOutput) { - src.push("fragColor = linearToGamma(fragColor, gammaFactor);"); + if (!this._visible) { + return; } - src.push("outColor = fragColor;"); + const scene = this.plugin.viewer.scene; - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } + if (this._wpDirty) { - src.push("}"); - return src; - } + this._wp[0] = this._originWorld[0]; + this._wp[1] = this._originWorld[1]; + this._wp[2] = this._originWorld[2]; + this._wp[3] = 1.0; - webglContextRestored() { - this._program = null; - } + this._wp[4] = this._targetWorld[0]; + this._wp[5] = this._originWorld[1]; + this._wp[6] = this._originWorld[2]; + this._wp[7] = 1.0; - destroy() { - if (this._program) { - this._program.destroy(); + this._wp[8] = this._targetWorld[0]; + this._wp[9] = this._targetWorld[1]; + this._wp[10] = this._originWorld[2]; + this._wp[11] = 1.0; + + this._wp[12] = this._targetWorld[0]; + this._wp[13] = this._targetWorld[1]; + this._wp[14] = this._targetWorld[2]; + this._wp[15] = 1.0; + + this._wpDirty = false; + this._vpDirty = true; } - this._program = null; - } -} -const tempVec3a$J = math.vec3(); + if (this._vpDirty) { -/** - * @private - */ -class TrianglesBatchingPickNormalsFlatRenderer { + math.transformPositions4(scene.camera.viewMatrix, this._wp, this._vp); - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); - } + this._vp[3] = 1.0; + this._vp[7] = 1.0; + this._vp[11] = 1.0; + this._vp[15] = 1.0; - getValid() { - return this._hash === this._getHash(); - }; + this._vpDirty = false; + this._cpDirty = true; + } - _getHash() { - return this._scene._sectionPlanesState.getHash(); - } + const near = -0.3; + const vpz1 = this._originMarker.viewPos[2]; + const vpz2 = this._targetMarker.viewPos[2]; - drawLayer(frameCtx, batchingLayer, renderPass) { + if (vpz1 > near || vpz2 > near) { - const model = batchingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; + this._xAxisLabel.setVisible(false); + this._yAxisLabel.setVisible(false); + this._zAxisLabel.setVisible(false); + this._lengthLabel.setVisible(false); - if (!this._program) { - this._allocate(batchingLayer); - } + this._xAxisWire.setVisible(false); + this._yAxisWire.setVisible(false); + this._zAxisWire.setVisible(false); + this._lengthWire.setVisible(false); - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._originDot.setVisible(false); + this._targetDot.setVisible(false); + + return; } - gl.uniform1i(this._uRenderPass, renderPass); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + if (this._cpDirty) { - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + math.transformPositions4(scene.camera.project.matrix, this._vp, this._pp); - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + var pp = this._pp; + var cp = this._cp; - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + var canvas = scene.canvas.canvas; + var offsets = canvas.getBoundingClientRect(); + const containerOffsets = this._container.getBoundingClientRect(); + var top = offsets.top - containerOffsets.top; + var left = offsets.left - containerOffsets.left; + var aabb = scene.canvas.boundary; + var canvasWidth = aabb[2]; + var canvasHeight = aabb[3]; + var j = 0; - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far should be from projection matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + const metrics = this.plugin.viewer.scene.metrics; + const scale = metrics.scale; + const units = metrics.units; + const unitInfo = metrics.unitsInfo[units]; + const unitAbbrev = unitInfo.abbrev; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$J); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } + for (var i = 0, len = pp.length; i < len; i += 4) { + cp[j] = left + Math.floor((1 + pp[i + 0] / pp[i + 3]) * canvasWidth / 2); + cp[j + 1] = top + Math.floor((1 - pp[i + 1] / pp[i + 3]) * canvasHeight / 2); + j += 2; } - } - //============================================================= - // TODO: Use drawElements count and offset to draw only one entity - //============================================================= - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + this._originDot.setPos(cp[0], cp[1]); + this._targetDot.setPos(cp[6], cp[7]); - this._aPosition.bindArrayBuffer(state.positionsBuf); + this._lengthWire.setStartAndEnd(cp[0], cp[1], cp[6], cp[7]); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + this._xAxisWire.setStartAndEnd(cp[0], cp[1], cp[2], cp[3]); + this._yAxisWire.setStartAndEnd(cp[2], cp[3], cp[4], cp[5]); + this._zAxisWire.setStartAndEnd(cp[4], cp[5], cp[6], cp[7]); - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } + this._lengthLabel.setPosOnWire(cp[0], cp[1], cp[6], cp[7]); + this._xAxisLabel.setPosOnWire(cp[0], cp[1], cp[2], cp[3]); + this._yAxisLabel.setPosOnWire(cp[2], cp[3], cp[4], cp[5]); + this._zAxisLabel.setPosOnWire(cp[4], cp[5], cp[6], cp[7]); - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + const tilde = this._approximate ? " ~ " : " = "; - state.indicesBuf.bind(); + this._length = Math.abs(math.lenVec3(math.subVec3(this._targetWorld, this._originWorld, distVec3))); + this._lengthLabel.setText(tilde + (this._length * scale).toFixed(2) + unitAbbrev); - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - } + const xAxisCanvasLength = Math.abs(lengthWire(cp[0], cp[1], cp[2], cp[3])); + const yAxisCanvasLength = Math.abs(lengthWire(cp[2], cp[3], cp[4], cp[5])); + const zAxisCanvasLength = Math.abs(lengthWire(cp[4], cp[5], cp[6], cp[7])); - _allocate() { + const labelMinAxisLength = this.plugin.labelMinAxisLength; - const scene = this._scene; - const gl = scene.canvas.gl; + this._xAxisLabelCulled = (xAxisCanvasLength < labelMinAxisLength); + this._yAxisLabelCulled = (yAxisCanvasLength < labelMinAxisLength); + this._zAxisLabelCulled = (zAxisCanvasLength < labelMinAxisLength); - this._program = new Program(gl, this._buildShader()); + if (!this._xAxisLabelCulled) { + this._xAxisLabel.setText(tilde + Math.abs((this._targetWorld[0] - this._originWorld[0]) * scale).toFixed(2) + unitAbbrev); + this._xAxisLabel.setVisible(this.axisVisible); + } else { + this._xAxisLabel.setVisible(false); + } - if (this._program.errors) { - this.errors = this._program.errors; - return; - } + if (!this._yAxisLabelCulled) { + this._yAxisLabel.setText(tilde + Math.abs((this._targetWorld[1] - this._originWorld[1]) * scale).toFixed(2) + unitAbbrev); + this._yAxisLabel.setVisible(this.axisVisible); + } else { + this._yAxisLabel.setVisible(false); + } - const program = this._program; + if (!this._zAxisLabelCulled) { + this._zAxisLabel.setText(tilde + Math.abs((this._targetWorld[2] - this._originWorld[2]) * scale).toFixed(2) + unitAbbrev); + this._zAxisLabel.setVisible(this.axisVisible); + } else { + this._zAxisLabel.setVisible(false); + } - this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; + this._originDot.setVisible(this._visible && this._originVisible); + this._targetDot.setVisible(this._visible && this._targetVisible); + this._xAxisWire.setVisible(this.axisVisible); + this._yAxisWire.setVisible(this.axisVisible); + this._zAxisWire.setVisible(this.axisVisible); + this._lengthWire.setVisible(this.wireVisible); + this._lengthLabel.setVisible(this.wireVisible); - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); + this._cpDirty = false; } + } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + /** + * Sets whether this DistanceMeasurement indicates that its measurement is approximate. + * + * This is ````true```` by default. + * + * @type {Boolean} + */ + set approximate(approximate) { + approximate = approximate !== false; + if (this._approximate === approximate) { + return; } + this._approximate = approximate; + this._cpDirty = true; + this._needUpdate(0); } - _bindProgram() { - this._program.bind(); + /** + * Gets whether this DistanceMeasurement indicates that its measurement is approximate. + * + * This is ````true```` by default. + * + * @type {Boolean} + */ + get approximate() { + return this._approximate; + } + + /** + * Gets the origin {@link Marker}. + * + * @type {Marker} + */ + get origin() { + return this._originMarker; } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + /** + * Gets the target {@link Marker}. + * + * @type {Marker} + */ + get target() { + return this._targetMarker; } - _buildVertexShader() { - const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching pick flat normals vertex shader"); - - src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("uniform bool pickInvisible;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - src.push("out vec4 vWorldPosition;"); - if (clipping) { - src.push("out vec4 vFlags2;"); - } - src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK - src.push(`if (int(flags.w) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vWorldPosition = worldPosition;"); - if (clipping) { - src.push(" vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - src.push(" }"); - src.push("}"); - return src; + /** + * Gets the World-space direct point-to-point distance between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target}. + * + * @type {Number} + */ + get length() { + this._update(); + const scale = this.plugin.viewer.scene.metrics.scale; + return this._length * scale; } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching pick flat normals fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - src.push("in vec4 vWorldPosition;"); - if (clipping) { - src.push("in vec4 vFlags2;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" vec3 xTangent = dFdx( vWorldPosition.xyz );"); - src.push(" vec3 yTangent = dFdy( vWorldPosition.xyz );"); - src.push(" vec3 worldNormal = normalize( cross( xTangent, yTangent ) );"); - src.push(" outColor = vec4((worldNormal * 0.5) + 0.5, 1.0);"); - src.push("}"); - return src; + get color() { + return this._color; } - webglContextRestored() { - this._program = null; + set color(value) { + this._color = value; + this._originDot.setFillColor(value); + this._targetDot.setFillColor(value); + this._lengthWire.setColor(value); + this._lengthLabel.setFillColor(value); } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + /** + * Sets whether this DistanceMeasurement is visible or not. + * + * @type {Boolean} + */ + set visible(value) { + value = value !== undefined ? Boolean(value) : this.plugin.defaultVisible; + this._visible = value; + this._originDot.setVisible(this._visible && this._originVisible); + this._targetDot.setVisible(this._visible && this._targetVisible); + this._lengthWire.setVisible(this._visible && this._wireVisible); + this._lengthLabel.setVisible(this._visible && this._wireVisible); + var axisVisible = this._visible && this._axisVisible; + this._xAxisWire.setVisible(axisVisible); + this._yAxisWire.setVisible(axisVisible); + this._zAxisWire.setVisible(axisVisible); + this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled); + this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled); + this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled); } -} -const tempVec4$4 = math.vec4(); -const tempVec3a$I = math.vec3(); + /** + * Gets whether this DistanceMeasurement is visible or not. + * + * @type {Boolean} + */ + get visible() { + return this._visible; + } -/** - * @private - */ -class TrianglesBatchingColorTextureRenderer { + /** + * Sets if the origin {@link Marker} is visible. + * + * @type {Boolean} + */ + set originVisible(value) { + value = value !== undefined ? Boolean(value) : this.plugin.defaultOriginVisible; + this._originVisible = value; + this._originDot.setVisible(this._visible && this._originVisible); + } - constructor(scene, withSAO) { - this._scene = scene; - this._withSAO = withSAO; - this._hash = this._getHash(); - this._allocate(); + /** + * Gets if the origin {@link Marker} is visible. + * + * @type {Boolean} + */ + get originVisible() { + return this._originVisible; } - getValid() { - return this._hash === this._getHash(); - }; + /** + * Sets if the target {@link Marker} is visible. + * + * @type {Boolean} + */ + set targetVisible(value) { + value = value !== undefined ? Boolean(value) : this.plugin.defaultTargetVisible; + this._targetVisible = value; + this._targetDot.setVisible(this._visible && this._targetVisible); + } - _getHash() { - const scene = this._scene; - return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); + /** + * Gets if the target {@link Marker} is visible. + * + * @type {Boolean} + */ + get targetVisible() { + return this._targetVisible; } - drawLayer(frameCtx, batchingLayer, renderPass) { + /** + * Sets if the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} are visible. + * + * @type {Boolean} + */ + set axisEnabled(value) { + value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; + this._axisEnabled = value; + var axisVisible = this._visible && this._axisVisible && this._axisEnabled; + this._xAxisWire.setVisible(axisVisible); + this._yAxisWire.setVisible(axisVisible); + this._zAxisWire.setVisible(axisVisible); + this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled); + this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled); + this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled); + } - const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; + /** + * Gets if the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} are visible. + * + * @type {Boolean} + */ + get axisEnabled() { + return this._axisEnabled; + } + + /** + * Sets if the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} are visible. + * + * @type {Boolean} + */ + set axisVisible(value) { + value = value !== undefined ? Boolean(value) : this.plugin.defaultAxisVisible; + this._axisVisible = value; + var axisVisible = this._visible && this._axisVisible && this._axisEnabled; + this._xAxisWire.setVisible(axisVisible); + this._yAxisWire.setVisible(axisVisible); + this._zAxisWire.setVisible(axisVisible); + this._xAxisLabel.setVisible(axisVisible && !this._xAxisLabelCulled); + this._yAxisLabel.setVisible(axisVisible && !this._yAxisLabelCulled); + this._zAxisLabel.setVisible(axisVisible && !this._zAxisLabelCulled); + } - const scene = this._scene; - const camera = scene.camera; - const model = batchingLayer.model; - const gl = scene.canvas.gl; - const state = batchingLayer._state; - const origin = batchingLayer._state.origin; - const textureSet = state.textureSet; - - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } - } + /** + * Gets if the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} are visible. + * + * @type {Boolean} + */ + get axisVisible() { + return this._axisVisible; + } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); - } + /** + * Sets if the direct point-to-point wire between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} is visible. + * + * @type {Boolean} + */ + set wireVisible(value) { + value = value !== undefined ? Boolean(value) : this.plugin.defaultWireVisible; + this._wireVisible = value; + var wireVisible = this._visible && this._wireVisible; + this._lengthLabel.setVisible(wireVisible); + this._lengthWire.setVisible(wireVisible); + } - gl.uniform1i(this._uRenderPass, renderPass); + /** + * Gets if the direct point-to-point wire between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target} is visible. + * + * @type {Boolean} + */ + get wireVisible() { + return this._wireVisible; + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + /** + * @private + */ + destroy() { - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + const scene = this.plugin.viewer.scene; + const metrics = scene.metrics; - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = batchingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$I); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } + if (this._onViewMatrix) { + scene.camera.off(this._onViewMatrix); } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, state.positionsDecodeMatrix); - - if (this._uUVDecodeMatrix) { - gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, state.uvDecodeMatrix); + if (this._onProjMatrix) { + scene.camera.off(this._onProjMatrix); } - - this._aPosition.bindArrayBuffer(state.positionsBuf); - - if (this._aNormal) { - this._aNormal.bindArrayBuffer(state.normalsBuf); + if (this._onCanvasBoundary) { + scene.canvas.off(this._onCanvasBoundary); } - if (this._aUV) { - this._aUV.bindArrayBuffer(state.uvBuf); + if (this._onMetricsUnits) { + metrics.off(this._onMetricsUnits); } - - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); + if (this._onMetricsScale) { + metrics.off(this._onMetricsScale); } - - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); + if (this._onMetricsOrigin) { + metrics.off(this._onMetricsOrigin); } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - } + this._originDot.destroy(); + this._targetDot.destroy(); + this._xAxisWire.destroy(); + this._yAxisWire.destroy(); + this._zAxisWire.destroy(); + this._lengthLabel.destroy(); + this._xAxisLabel.destroy(); + this._yAxisLabel.destroy(); + this._zAxisLabel.destroy(); + this._lengthWire.destroy(); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + super.destroy(); + } +} - if (textureSet) { - if (textureSet.colorTexture) { - this._program.bindTexture(this._uColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - } - } +/** + * @desc Localization service for a {@link Viewer}. + * + * * A LocaleService is a container of string translations ("messages") for various locales. + * * A {@link Viewer} has its own default LocaleService at {@link Viewer#localeService}. + * * We can replace that with our own LocaleService, or a custom subclass, via the Viewer's constructor. + * * Viewer plugins that need localized translations will attempt to them for the currently active locale from the LocaleService. + * * Whenever we switch the LocaleService to a different locale, plugins will automatically refresh their translations for that locale. + * + * ## Usage + * + * In the example below, we'll create a {@link Viewer} that uses an {@link XKTLoaderPlugin} to load a BIM model, and a + * {@link NavCubePlugin}, which shows a camera navigation cube in the corner of the canvas. + * + * We'll also configure our Viewer with our own LocaleService instance, configured with English, Māori and French + * translations for our NavCubePlugin. + * + * We could instead have just used the Viewer's default LocaleService, but this example demonstrates how we might + * configure the Viewer our own custom LocaleService subclass. + * + * The translations fetched by our NavCubePlugin will be: + * + * * "NavCube.front" + * * "NavCube.back" + * * "NavCube.top" + * * "NavCube.bottom" + * * "NavCube.left" + * * "NavCube.right" + * + *
+ * These are paths that resolve to our translations for the currently active locale, and are hard-coded within + * the NavCubePlugin. + * + * For example, if the LocaleService's locale is set to "fr", then the path "NavCube.back" will drill down + * into ````messages->fr->NavCube->front```` and fetch "Arrière". + * + * If we didn't provide that particular translation in our LocaleService, or any translations for that locale, + * then the NavCubePlugin will just fall back on its own default hard-coded translation, which in this case is "BACK". + * + * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#localization_NavCubePlugin)] + * + * ````javascript + * import {Viewer, LocaleService, NavCubePlugin, XKTLoaderPlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * + * canvasId: "myCanvas", + * + * localeService: new LocaleService({ + * messages: { + * "en": { // English + * "NavCube": { + * "front": "Front", + * "back": "Back", + * "top": "Top", + * "bottom": "Bottom", + * "left": "Left", + * "right": "Right" + * } + * }, + * "mi": { // Māori + * "NavCube": { + * "front": "Mua", + * "back": "Tuarā", + * "top": "Runga", + * "bottom": "Raro", + * "left": "Mauī", + * "right": "Tika" + * } + * }, + * "fr": { // Francais + * "NavCube": { + * "front": "Avant", + * "back": "Arrière", + * "top": "Supérieur", + * "bottom": "Inférieur", + * "left": "Gauche", + * "right": "Droit" + * } + * } + * }, + * locale: "en" + * }) + * }); + * + * viewer.camera.eye = [-3.93, 2.85, 27.01]; + * viewer.camera.look = [4.40, 3.72, 8.89]; + * viewer.camera.up = [-0.01, 0.99, 0.03]; + * + * const navCubePlugin = new NavCubePlugin(viewer, { + * canvasID: "myNavCubeCanvas" + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Duplex.ifc.xkt", + * edges: true + * }); + * ```` + * + * We can dynamically switch our Viewer to a different locale at any time, which will update the text on the + * faces of our NavCube: + * + * ````javascript + * viewer.localeService.locale = "mi"; // Switch to Māori + * ```` + * + * We can load new translations at any time: + * + * ````javascript + * viewer.localeService.loadMessages({ + * "jp": { // Japanese + * "NavCube": { + * "front": "前部", + * "back": "裏", + * "top": "上", + * "bottom": "底", + * "left": "左", + * "right": "右" + * } + * } + * }); + * ```` + * + * And we can clear the translations if needed: + * + * ````javascript + * viewer.localeService.clearMessages(); + * ```` + * + * We can get an "updated" event from the LocaleService whenever we switch locales or load messages, which is useful + * for triggering UI elements to refresh themselves with updated translations. Internally, our {@link NavCubePlugin} + * subscribes to this event, fetching new strings for itself via {@link LocaleService#translate} each time the + * event is fired. + * + * ````javascript + * viewer.localeService.on("updated", () => { + * console.log( viewer.localeService.translate("NavCube.left") ); + * }); + * ```` + * @since 2.0 + */ +class LocaleService { - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$4[0] = viewportWidth; - tempVec4$4[1] = viewportHeight; - tempVec4$4[2] = sao.blendCutoff; - tempVec4$4[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$4); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; - } - } + /** + * Constructs a LocaleService. + * + * @param {*} [params={}] + * @param {JSON} [params.messages] + * @param {String} [params.locale] + */ + constructor(params = {}) { - state.indicesBuf.bind(); + this._eventSubIDMap = null; + this._eventSubEvents = null; + this._eventSubs = null; + this._events = null; - gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + this._locale = "en"; + this._messages = {}; + this._locales = []; + this._locale = "en"; - frameCtx.drawElements++; + this.messages = params.messages; + this.locale = params.locale; } - _allocate() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; - - this._program = new Program(gl, this._buildShader()); + /** + * Replaces the current set of locale translations. + * + * * Fires an "updated" event when done. + * * Automatically refreshes any plugins that depend on the translations. + * * Does not change the current locale. + * + * ## Usage + * + * ````javascript + * viewer.localeService.setMessages({ + * messages: { + * "en": { // English + * "NavCube": { + * "front": "Front", + * "back": "Back", + * "top": "Top", + * "bottom": "Bottom", + * "left": "Left", + * "right": "Right" + * } + * }, + * "mi": { // Māori + * "NavCube": { + * "front": "Mua", + * "back": "Tuarā", + * "top": "Runga", + * "bottom": "Raro", + * "left": "Mauī", + * "right": "Tika" + * } + * } + * } + * }); + * ```` + * + * @param {*} messages The new translations. + */ + set messages(messages) { + this._messages = messages || {}; + this._locales = Object.keys(this._messages); + this.fire("updated", this); + } - if (this._program.errors) { - this.errors = this._program.errors; - return; + /** + * Loads a new set of locale translations, adding them to the existing translations. + * + * * Fires an "updated" event when done. + * * Automatically refreshes any plugins that depend on the translations. + * * Does not change the current locale. + * + * ## Usage + * + * ````javascript + * viewer.localeService.loadMessages({ + * "jp": { // Japanese + * "NavCube": { + * "front": "前部", + * "back": "裏", + * "top": "上", + * "bottom": "底", + * "left": "左", + * "right": "右" + * } + * } + * }); + * ```` + * + * @param {*} messages The new translations. + */ + loadMessages(messages = {}) { + for (let locale in messages) { + this._messages[locale] = messages[locale]; } + this.messages = this._messages; + } - const program = this._program; + /** + * Clears all locale translations. + * + * * Fires an "updated" event when done. + * * Does not change the current locale. + * * Automatically refreshes any plugins that depend on the translations, which will cause those + * plugins to fall back on their internal hard-coded text values, since this method removes all + * our translations. + */ + clearMessages() { + this.messages = {}; + } - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); + /** + * Gets the list of available locales. + * + * These are derived from the currently configured set of translations. + * + * @returns {String[]} The list of available locales. + */ + get locales() { + return this._locales; + } - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; + /** + * Sets the current locale. + * + * * Fires an "updated" event when done. + * * The given locale does not need to be in the list of available locales returned by {@link LocaleService#locales}, since + * this method assumes that you may want to load the locales at a later point. + * * Automatically refreshes any plugins that depend on the translations. + * * We can then get translations for the locale, if translations have been loaded for it, via {@link LocaleService#translate} and {@link LocaleService#translatePlurals}. + * + * @param {String} locale The new current locale. + */ + set locale(locale) { + locale = locale || "de"; + if (this._locale === locale) { + return; + } + this._locale = locale; + this.fire("updated", locale); + } - const lights = lightsState.lights; - let light; + /** + * Gets the current locale. + * + * @returns {String} The current locale. + */ + get locale() { + return this._locale; + } - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; + /** + * Translates the given string according to the current locale. + * + * Returns null if no translation can be found. + * + * @param {String} msg String to translate. + * @param {*} [args] Extra parameters. + * @returns {String|null} Translated string if found, else null. + */ + translate(msg, args) { + const localeMessages = this._messages[this._locale]; + if (!localeMessages) { + return null; + } + const localeMessage = resolvePath$1(msg, localeMessages); + if (localeMessage) { + if (args) { + return vsprintf(localeMessage, args); } + return localeMessage; } + return null; + } - this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); + /** + * Translates the given phrase according to the current locale. + * + * Returns null if no translation can be found. + * + * @param {String} msg Phrase to translate. + * @param {Number} count The plural number. + * @param {*} [args] Extra parameters. + * @returns {String|null} Translated string if found, else null. + */ + translatePlurals(msg, count, args) { + const localeMessages = this._messages[this._locale]; + if (!localeMessages) { + return null; } - - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aNormal = program.getAttribute("normal"); - this._aUV = program.getAttribute("uv"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - - this._uColorMap = "uColorMap"; - - if (this._withSAO) { - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); + let localeMessage = resolvePath$1(msg, localeMessages); + count = parseInt("" + count, 10); + if (count === 0) { + localeMessage = localeMessage.zero; + } else { + localeMessage = (count > 1) ? localeMessage.other : localeMessage.one; } - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + if (!localeMessage) { + return null; + } + localeMessage = vsprintf(localeMessage, [count]); + if (args) { + localeMessage = vsprintf(localeMessage, args); } + return localeMessage; } - _bindProgram(frameCtx) { - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const lightsState = scene._lightsState; - const lights = lightsState.lights; - const project = scene.camera.project; - - program.bind(); - - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + /** + * Fires an event on this LocaleService. + * + * Notifies existing subscribers to the event, optionally retains the event to give to + * any subsequent notifications on the event as they are made. + * + * @param {String} event The event type name. + * @param {Object} value The event parameters. + * @param {Boolean} [forget=false] When true, does not retain for subsequent subscribers. + */ + fire(event, value, forget) { + if (!this._events) { + this._events = {}; } - - for (let i = 0, len = lights.length; i < len; i++) { - const light = lights[i]; - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + if (!this._eventSubs) { + this._eventSubs = {}; + } + if (forget !== true) { + this._events[event] = value || true; // Save notification + } + const subs = this._eventSubs[event]; + if (subs) { + for (const subId in subs) { + if (subs.hasOwnProperty(subId)) { + const sub = subs[subId]; + sub.callback(value); } } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } - } - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() + /** + * Subscribes to an event on this LocaleService. + * + * @param {String} event The event + * @param {Function} callback Callback fired on the event + * @return {String} Handle to the subscription, which may be used to unsubscribe with {@link #off}. + */ + on(event, callback) { + if (!this._events) { + this._events = {}; + } + if (!this._eventSubIDMap) { + this._eventSubIDMap = new Map$1(); // Subscription subId pool + } + if (!this._eventSubEvents) { + this._eventSubEvents = {}; + } + if (!this._eventSubs) { + this._eventSubs = {}; + } + let subs = this._eventSubs[event]; + if (!subs) { + subs = {}; + this._eventSubs[event] = subs; + } + const subId = this._eventSubIDMap.addItem(); // Create unique subId + subs[subId] = { + callback: callback }; + this._eventSubEvents[subId] = event; + const value = this._events[event]; + if (value !== undefined) { + callback(value); + } + return subId; } - _buildVertexShader() { - - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - let light; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching color texture vertex shader"); - - src.push("uniform int renderPass;"); - - src.push("in vec3 position;"); - src.push("in vec3 normal;"); - src.push("in vec4 color;"); - src.push("in vec2 uv;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); + /** + * Cancels an event subscription that was previously made with {@link LocaleService#on}. + * + * @param {String} subId Subscription ID + */ + off(subId) { + if (subId === undefined || subId === null) { + return; } - - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); - - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform mat3 uvDecodeMatrix;"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); + if (!this._eventSubEvents) { + return; } - - src.push("uniform vec4 lightAmbient;"); - - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); + const event = this._eventSubEvents[subId]; + if (event) { + delete this._eventSubEvents[subId]; + const subs = this._eventSubs[event]; + if (subs) { + delete subs[subId]; } + this._eventSubIDMap.removeItem(subId); // Release subId } + } +} - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); +function resolvePath$1(key, json) { + if (json[key]) { + return json[key]; + } + const parts = key.split("."); + let obj = json; + for (let i = 0, len = parts.length; obj && (i < len); i++) { + const part = parts[i]; + obj = obj[part]; + } + return obj; +} - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); +function vsprintf(msg, args = []) { + return msg.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) { + if (m === "{{") { + return "{"; } - src.push("out vec4 vColor;"); - src.push("out vec2 vUV;"); + if (m === "}}") { + return "}"; + } + return args[n]; + }); +} - src.push("void main(void) {"); +/** + * @desc Abstract base class for curve classes. + */ +class Curve extends Component { - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this Curve as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Curve}, generated automatically when omitted. + * @param {Object} [cfg] Configs for this Curve. + * @param {Number} [cfg.t=0] Current position on this Curve, in range between ````0..1````. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this.t = cfg.t; + } - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + /** + * Sets the progress along this Curve. + * + * Automatically clamps to range ````[0..1]````. + * + * Default value is ````0````. + * + * @param {Number} value The progress value. + */ + set t(value) { + value = value || 0; + this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); + } - src.push("} else {"); + /** + * Gets the progress along this Curve. + * + * @returns {Number} The progress value. + */ + get t() { + return this._t; + } - src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); - if (scene.entityOffsetsEnabled) { - src.push("worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); - src.push("vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); + /** + * Gets the tangent on this Curve at position {@link Curve#t}. + * + * @returns {Number[]} The tangent. + */ + get tangent() { + return this.getTangent(this._t); + } - src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); - src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + /** + * Gets the length of this Curve. + * + * @returns {Number} The Curve length. + */ + get length() { + var lengths = this._getLengths(); + return lengths[lengths.length - 1]; + } - src.push("float lambertian = 1.0;"); - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - if (light.type === "dir") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); - } else { - src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else { - continue; - } - src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); - src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); + /** + * Returns a normalized tangent vector on this Curve at the given position. + * + * @param {Number} t Position to get tangent at. + * @returns {Number[]} Normalized tangent vector + */ + getTangent(t) { + var delta = 0.0001; + if (t === undefined) { + t = this._t; } - - src.push("vec3 rgb = (vec3(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0));"); - src.push("vColor = vec4((lightAmbient.rgb * lightAmbient.a * rgb) + (reflectedColor * rgb), float(color.a) / 255.0);"); - src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); - - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + var t1 = t - delta; + var t2 = t + delta; + if (t1 < 0) { + t1 = 0; } - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + if (t2 > 1) { + t2 = 1; } - src.push("gl_Position = clipPos;"); - src.push("}"); - src.push("}"); - return src; + var pt1 = this.getPoint(t1); + var pt2 = this.getPoint(t2); + var vec = math.subVec3(pt2, pt1, []); + return math.normalizeVec3(vec, []); } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles batching color texture fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - - src.push("uniform sampler2D uColorMap;"); - - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); - - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + getPointAt(u) { + var t = this.getUToTMapping(u); + return this.getPoint(t); + } - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); + /** + * Samples points on this Curve, at the given number of equally-spaced divisions. + * + * @param {Number} divisions The number of divisions. + * @returns {{Array of Array}} Array of sampled 3D points. + */ + getPoints(divisions) { + if (!divisions) { + divisions = 5; } - - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } + var d, pts = []; + for (d = 0; d <= divisions; d++) { + pts.push(this.getPoint(d / divisions)); } + return pts; + } - src.push("in vec4 vColor;"); - src.push("in vec2 vUV;"); - src.push("out vec4 outColor;"); - - src.push("void main(void) {"); - - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - src.push("}"); + _getLengths(divisions) { + if (!divisions) { + divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; } + if (this.cacheArcLengths && (this.cacheArcLengths.length === divisions + 1) && !this.needsUpdate) { + return this.cacheArcLengths; - if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - - src.push("vec4 colorTexel = vColor * texture(uColorMap, vUV);"); - src.push("float opacity = vColor.a;"); - - if (this._withSAO) { - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - - src.push(" outColor = vec4(colorTexel.rgb * ambient, opacity);"); - } else { - src.push(" outColor = vec4(colorTexel.rgb, opacity);"); + this.needsUpdate = false; + var cache = []; + var current; + var last = this.getPoint(0); + var p; + var sum = 0; + cache.push(0); + for (p = 1; p <= divisions; p++) { + current = this.getPoint(p / divisions); + sum += math.lenVec3(math.subVec3(current, last, [])); + cache.push(sum); + last = current; } - - src.push("}"); - return src; + this.cacheArcLengths = cache; + return cache; // { sums: cache, sum:sum }, Sum is in the last element. } - webglContextRestored() { - this._program = null; + _updateArcLengths() { + this.needsUpdate = true; + this._getLengths(); } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; - } -} + // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance -/** - * @private - */ -class TrianglesBatchingRenderers { - - constructor(scene) { - this._scene = scene; - } - - _compile() { - if (this._colorRenderer && (!this._colorRenderer.getValid())) { - this._colorRenderer.destroy(); - this._colorRenderer = null; - } - if (this._colorRendererWithSAO && (!this._colorRendererWithSAO.getValid())) { - this._colorRendererWithSAO.destroy(); - this._colorRendererWithSAO = null; - } - if (this._flatColorRenderer && (!this._flatColorRenderer.getValid())) { - this._flatColorRenderer.destroy(); - this._flatColorRenderer = null; - } - if (this._flatColorRendererWithSAO && (!this._flatColorRendererWithSAO.getValid())) { - this._flatColorRendererWithSAO.destroy(); - this._flatColorRendererWithSAO = null; - } - if (this._colorTextureRenderer && (!this._colorTextureRenderer.getValid())) { - this._colorTextureRenderer.destroy(); - this._colorTextureRenderer = null; - } - if (this._colorTextureRendererWithSAO && (!this._colorTextureRendererWithSAO.getValid())) { - this._colorTextureRendererWithSAO.destroy(); - this._colorTextureRendererWithSAO = null; - } - if (this._pbrRenderer && (!this._pbrRenderer.getValid())) { - this._pbrRenderer.destroy(); - this._pbrRenderer = null; - } - if (this._pbrRendererWithSAO && (!this._pbrRendererWithSAO.getValid())) { - this._pbrRendererWithSAO.destroy(); - this._pbrRendererWithSAO = null; - } - if (this._depthRenderer && (!this._depthRenderer.getValid())) { - this._depthRenderer.destroy(); - this._depthRenderer = null; - } - if (this._normalsRenderer && (!this._normalsRenderer.getValid())) { - this._normalsRenderer.destroy(); - this._normalsRenderer = null; - } - if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { - this._silhouetteRenderer.destroy(); - this._silhouetteRenderer = null; - } - if (this._edgesRenderer && (!this._edgesRenderer.getValid())) { - this._edgesRenderer.destroy(); - this._edgesRenderer = null; - } - if (this._edgesColorRenderer && (!this._edgesColorRenderer.getValid())) { - this._edgesColorRenderer.destroy(); - this._edgesColorRenderer = null; - } - if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { - this._pickMeshRenderer.destroy(); - this._pickMeshRenderer = null; - } - if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { - this._pickDepthRenderer.destroy(); - this._pickDepthRenderer = null; - } - if (this._pickNormalsRenderer && this._pickNormalsRenderer.getValid() === false) { - this._pickNormalsRenderer.destroy(); - this._pickNormalsRenderer = null; - } - if (this._pickNormalsFlatRenderer && this._pickNormalsFlatRenderer.getValid() === false) { - this._pickNormalsFlatRenderer.destroy(); - this._pickNormalsFlatRenderer = null; + getUToTMapping(u, distance) { + var arcLengths = this._getLengths(); + var i = 0; + var il = arcLengths.length; + var t; + var targetArcLength; // The targeted u distance value to get + if (distance) { + targetArcLength = distance; + } else { + targetArcLength = u * arcLengths[il - 1]; } - if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { - this._occlusionRenderer.destroy(); - this._occlusionRenderer = null; + //var time = Date.now(); + var low = 0, high = il - 1, comparison; + while (low <= high) { + i = Math.floor(low + (high - low) / 2); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats + comparison = arcLengths[i] - targetArcLength; + if (comparison < 0) { + low = i + 1; + } else if (comparison > 0) { + high = i - 1; + } else { + high = i; + break; + // DONE + } } - if (this._shadowRenderer && (!this._shadowRenderer.getValid())) { - this._shadowRenderer.destroy(); - this._shadowRenderer = null; + i = high; + if (arcLengths[i] === targetArcLength) { + t = i / (il - 1); + return t; } + var lengthBefore = arcLengths[i]; + var lengthAfter = arcLengths[i + 1]; + var segmentLength = lengthAfter - lengthBefore; + var segmentFraction = (targetArcLength - lengthBefore) / segmentLength; + t = (i + segmentFraction) / (il - 1); + return t; } +} - get colorRenderer() { - if (!this._colorRenderer) { - this._colorRenderer = new TrianglesBatchingColorRenderer(this._scene, false); - } - return this._colorRenderer; - } +/** + * @desc A {@link Curve} along which a 3D position can be animated. + * + * * As shown in the diagram below, a SplineCurve is defined by three or more control points. + * * You can sample a {@link SplineCurve#point} and a {@link Curve#tangent} vector on a SplineCurve for any given value of {@link SplineCurve#t} in the range ````[0..1]````. + * * When you set {@link SplineCurve#t} on a SplineCurve, its {@link SplineCurve#point} and {@link Curve#tangent} will update accordingly. + * * To build a complex path, you can combine an unlimited combination of SplineCurves, {@link CubicBezierCurve} and {@link QuadraticBezierCurve} into a {@link Path}. + *
+ *
+ * + * * Spline Curve from Wikipedia* + */ +class SplineCurve extends Curve { - get colorRendererWithSAO() { - if (!this._colorRendererWithSAO) { - this._colorRendererWithSAO = new TrianglesBatchingColorRenderer(this._scene, true); - } - return this._colorRendererWithSAO; + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this SplineCurve as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Array} [cfg.points=[]] Control points on this SplineCurve. + * @param {Number} [cfg.t=0] Current position on this SplineCurve, in range between 0..1. + * @param {Number} [cfg.t=0] Current position on this CubicBezierCurve, in range between 0..1. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this.points = cfg.points; + this.t = cfg.t; } - get flatColorRenderer() { - if (!this._flatColorRenderer) { - this._flatColorRenderer = new TrianglesBatchingFlatColorRenderer(this._scene, false); - } - return this._flatColorRenderer; + /** + * Sets the control points on this SplineCurve. + * + * Default value is ````[]````. + * + * @param {Number[]} value New control points. + */ + set points(value) { + this._points = value || []; } - get flatColorRendererWithSAO() { - if (!this._flatColorRendererWithSAO) { - this._flatColorRendererWithSAO = new TrianglesBatchingFlatColorRenderer(this._scene, true); - } - return this._flatColorRendererWithSAO; + /** + * Gets the control points on this SplineCurve. + * + * Default value is ````[]````. + * + * @returns {Number[]} The control points. + */ + get points() { + return this._points; } - get colorTextureRenderer() { - if (!this._colorTextureRenderer) { - this._colorTextureRenderer = new TrianglesBatchingColorTextureRenderer(this._scene, false); - } - return this._colorTextureRenderer; + /** + * Sets the progress along this SplineCurve. + * + * Automatically clamps to range ````[0..1]````. + * + * Default value is ````0````. + * + * @param {Number} value The new progress. + */ + set t(value) { + value = value || 0; + this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); } - get colorTextureRendererWithSAO() { - if (!this._colorTextureRendererWithSAO) { - this._colorTextureRendererWithSAO = new TrianglesBatchingColorTextureRenderer(this._scene, true); - } - return this._colorTextureRendererWithSAO; - } - - get pbrRenderer() { - if (!this._pbrRenderer) { - this._pbrRenderer = new TrianglesBatchingPBRRenderer(this._scene, false); - } - return this._pbrRenderer; + /** + * Gets the progress along this SplineCurve. + * + * Automatically clamps to range ````[0..1]````. + * + * Default value is ````0````. + * + * @returns {Number} The new progress. + */ + get t() { + return this._t; } - get pbrRendererWithSAO() { - if (!this._pbrRendererWithSAO) { - this._pbrRendererWithSAO = new TrianglesBatchingPBRRenderer(this._scene, true); - } - return this._pbrRendererWithSAO; + /** + * Gets the point on this SplineCurve at position {@link SplineCurve#t}. + * + * @returns {Number[]} The point at {@link SplineCurve#t}. + */ + get point() { + return this.getPoint(this._t); } - get silhouetteRenderer() { - if (!this._silhouetteRenderer) { - this._silhouetteRenderer = new TrianglesBatchingSilhouetteRenderer(this._scene); - } - return this._silhouetteRenderer; - } + /** + * Returns point on this SplineCurve at the given position. + * + * @param {Number} t Position to get point at. + * @returns {Number[]} Point at the given position. + */ + getPoint(t) { - get depthRenderer() { - if (!this._depthRenderer) { - this._depthRenderer = new TrianglesBatchingDepthRenderer(this._scene); - } - return this._depthRenderer; - } + var points = this.points; - get normalsRenderer() { - if (!this._normalsRenderer) { - this._normalsRenderer = new TrianglesBatchingNormalsRenderer(this._scene); + if (points.length < 3) { + this.error("Can't sample point from SplineCurve - not enough points on curve - returning [0,0,0]."); + return; } - return this._normalsRenderer; - } - get edgesRenderer() { - if (!this._edgesRenderer) { - this._edgesRenderer = new TrianglesBatchingEdgesRenderer(this._scene); - } - return this._edgesRenderer; - } + var point = (points.length - 1) * t; - get edgesColorRenderer() { - if (!this._edgesColorRenderer) { - this._edgesColorRenderer = new TrianglesBatchingEdgesColorRenderer(this._scene); - } - return this._edgesColorRenderer; - } + var intPoint = Math.floor(point); + var weight = point - intPoint; - get pickMeshRenderer() { - if (!this._pickMeshRenderer) { - this._pickMeshRenderer = new TrianglesBatchingPickMeshRenderer(this._scene); - } - return this._pickMeshRenderer; - } + var point0 = points[intPoint === 0 ? intPoint : intPoint - 1]; + var point1 = points[intPoint]; + var point2 = points[intPoint > points.length - 2 ? points.length - 1 : intPoint + 1]; + var point3 = points[intPoint > points.length - 3 ? points.length - 1 : intPoint + 2]; - get pickNormalsRenderer() { - if (!this._pickNormalsRenderer) { - this._pickNormalsRenderer = new TrianglesBatchingPickNormalsRenderer(this._scene); - } - return this._pickNormalsRenderer; + var vector = math.vec3(); + + vector[0] = math.catmullRomInterpolate(point0[0], point1[0], point2[0], point3[0], weight); + vector[1] = math.catmullRomInterpolate(point0[1], point1[1], point2[1], point3[1], weight); + vector[2] = math.catmullRomInterpolate(point0[2], point1[2], point2[2], point3[2], weight); + + return vector; } - get pickNormalsFlatRenderer() { - if (!this._pickNormalsFlatRenderer) { - this._pickNormalsFlatRenderer = new TrianglesBatchingPickNormalsFlatRenderer(this._scene); - } - return this._pickNormalsFlatRenderer; + getJSON() { + return { + points: points, + t: this._t + }; } +} - get pickDepthRenderer() { - if (!this._pickDepthRenderer) { - this._pickDepthRenderer = new TrianglesBatchingPickDepthRenderer(this._scene); - } - return this._pickDepthRenderer; +const tempVec3a$W = math.vec3(); + +/** + * @desc Defines a sequence of frames along which a {@link CameraPathAnimation} can animate a {@link Camera}. + * + * See {@link CameraPathAnimation} for usage. + */ +class CameraPath extends Component { + + /** + * Returns "CameraPath". + * + * @private + * + * @returns {string} "CameraPath" + */ + get type() { + return "CameraPath" } - get occlusionRenderer() { - if (!this._occlusionRenderer) { - this._occlusionRenderer = new TrianglesBatchingOcclusionRenderer(this._scene); + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this CameraPath as well. + * @param [cfg] {*} Configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {{t:Number, eye:Object, look:Object, up: Object}[]} [cfg.frames] Initial sequence of frames. + */ + constructor(owner, cfg = {}) { + + super(owner, cfg); + + this._frames = []; + + this._eyeCurve = new SplineCurve(this); + this._lookCurve = new SplineCurve(this); + this._upCurve = new SplineCurve(this); + + if (cfg.frames) { + this.addFrames(cfg.frames); + this.smoothFrameTimes(1); } - return this._occlusionRenderer; } - get shadowRenderer() { - if (!this._shadowRenderer) { - this._shadowRenderer = new TrianglesBatchingShadowRenderer(this._scene); - } - return this._shadowRenderer; + /** + * Gets the camera frames in this CameraPath. + * + * @returns {{t:Number, eye:Object, look:Object, up: Object}[]} The frames on this CameraPath. + */ + get frames() { + return this._frames; } - _destroy() { - if (this._colorRenderer) { - this._colorRenderer.destroy(); - } - if (this._colorRendererWithSAO) { - this._colorRendererWithSAO.destroy(); - } - if (this._flatColorRenderer) { - this._flatColorRenderer.destroy(); - } - if (this._flatColorRendererWithSAO) { - this._flatColorRendererWithSAO.destroy(); - } - if (this._colorTextureRenderer) { - this._colorTextureRenderer.destroy(); - } - if (this._colorTextureRendererWithSAO) { - this._colorTextureRendererWithSAO.destroy(); - } - if (this._pbrRenderer) { - this._pbrRenderer.destroy(); - } - if (this._pbrRendererWithSAO) { - this._pbrRendererWithSAO.destroy(); - } - if (this._depthRenderer) { - this._depthRenderer.destroy(); - } - if (this._normalsRenderer) { - this._normalsRenderer.destroy(); - } - if (this._silhouetteRenderer) { - this._silhouetteRenderer.destroy(); - } - if (this._edgesRenderer) { - this._edgesRenderer.destroy(); - } - if (this._edgesColorRenderer) { - this._edgesColorRenderer.destroy(); - } - if (this._pickMeshRenderer) { - this._pickMeshRenderer.destroy(); - } - if (this._pickDepthRenderer) { - this._pickDepthRenderer.destroy(); - } - if (this._pickNormalsRenderer) { - this._pickNormalsRenderer.destroy(); - } - if (this._pickNormalsFlatRenderer) { - this._pickNormalsFlatRenderer.destroy(); - } - if (this._occlusionRenderer) { - this._occlusionRenderer.destroy(); - } - if (this._shadowRenderer) { - this._shadowRenderer.destroy(); - } + /** + * Gets the {@link SplineCurve} along which {@link Camera#eye} travels. + * @returns {SplineCurve} The SplineCurve for {@link Camera#eye}. + */ + get eyeCurve() { + return this._eyeCurve; } -} -const cachdRenderers = {}; + /** + * Gets the {@link SplineCurve} along which {@link Camera#look} travels. + * @returns {SplineCurve} The SplineCurve for {@link Camera#look}. + */ + get lookCurve() { + return this._lookCurve; + } -/** - * @private - */ -function getBatchingRenderers$1(scene) { - const sceneId = scene.id; - let batchingRenderers = cachdRenderers[sceneId]; - if (!batchingRenderers) { - batchingRenderers = new TrianglesBatchingRenderers(scene); - cachdRenderers[sceneId] = batchingRenderers; - batchingRenderers._compile(); - scene.on("compile", () => { - batchingRenderers._compile(); - }); - scene.on("destroyed", () => { - delete cachdRenderers[sceneId]; - batchingRenderers._destroy(); - }); + /** + * Gets the {@link SplineCurve} along which {@link Camera#up} travels. + * @returns {SplineCurve} The SplineCurve for {@link Camera#up}. + */ + get upCurve() { + return this._upCurve; } - return batchingRenderers; -} -/** - * @private - */ -class TrianglesBatchingBuffer { + /** + * Adds a frame to this CameraPath, given as the current position of the {@link Camera}. + * + * @param {Number} t Time instant for the new frame. + */ + saveFrame(t) { + const camera = this.scene.camera; + this.addFrame(t, camera.eye, camera.look, camera.up); + } - constructor(maxGeometryBatchSize = 5000000) { + /** + * Adds a frame to this CameraPath, specified as values for eye, look and up vectors at a given time instant. + * + * @param {Number} t Time instant for the new frame. + * @param {Number[]} eye A three-element vector specifying the eye position for the new frame. + * @param {Number[]} look A three-element vector specifying the look position for the new frame. + * @param {Number[]} up A three-element vector specifying the up vector for the new frame. + */ + addFrame(t, eye, look, up) { + const frame = { + t: t, + eye: eye.slice(0), + look: look.slice(0), + up: up.slice(0) + }; + this._frames.push(frame); + this._eyeCurve.points.push(frame.eye); + this._lookCurve.points.push(frame.look); + this._upCurve.points.push(frame.up); + } - if (maxGeometryBatchSize > 5000000) { - maxGeometryBatchSize = 5000000; + /** + * Adds multiple frames to this CameraPath, each frame specified as a set of values for eye, look and up vectors at a given time instant. + * + * @param {{t:Number, eye:Object, look:Object, up: Object}[]} frames Frames to add to this CameraPath. + */ + addFrames(frames) { + let frame; + for (let i = 0, len = frames.length; i < len; i++) { + frame = frames[i]; + this.addFrame(frame.t || 0, frame.eye, frame.look, frame.up); } - - this.maxVerts = maxGeometryBatchSize; - this.maxIndices = maxGeometryBatchSize * 3; // Rough rule-of-thumb - this.positions = []; - this.colors = []; - this.uv = []; - this.metallicRoughness = []; - this.normals = []; - this.pickColors = []; - this.flags = []; - this.flags2 = []; - this.offsets = []; - this.indices = []; - this.edgeIndices = []; } -} -const translate = math.mat4(); -const scale = math.mat4(); + /** + * Sets the position of the {@link Camera} to a position interpolated within this CameraPath at the given time instant. + * + * @param {Number} t Time instant. + */ + loadFrame(t) { -/** - * @private - */ -function quantizePositions(positions, aabb, positionsDecodeMatrix) { // http://cg.postech.ac.kr/research/mesh_comp_mobile/mesh_comp_mobile_conference.pdf - const lenPositions = positions.length; - const quantizedPositions = new Uint16Array(lenPositions); - const xmin = aabb[0]; - const ymin = aabb[1]; - const zmin = aabb[2]; - const xwid = aabb[3] - xmin; - const ywid = aabb[4] - ymin; - const zwid = aabb[5] - zmin; - const maxInt = 65525; - const xMultiplier = maxInt / xwid; - const yMultiplier = maxInt / ywid; - const zMultiplier = maxInt / zwid; - const verify = (num) => num >= 0 ? num : 0; - for (let i = 0; i < lenPositions; i += 3) { - quantizedPositions[i + 0] = Math.floor(verify(positions[i + 0] - xmin) * xMultiplier); - quantizedPositions[i + 1] = Math.floor(verify(positions[i + 1] - ymin) * yMultiplier); - quantizedPositions[i + 2] = Math.floor(verify(positions[i + 2] - zmin) * zMultiplier); - } - math.identityMat4(translate); - math.translationMat4v(aabb, translate); - math.identityMat4(scale); - math.scalingMat4v([xwid / maxInt, ywid / maxInt, zwid / maxInt], scale); - math.mulMat4(translate, scale, positionsDecodeMatrix); - return quantizedPositions; -} + const camera = this.scene.camera; -/** - * @private - */ -function transformAndOctEncodeNormals(worldNormalMatrix, normals, lenNormals, compressedNormals, lenCompressedNormals) { - // http://jcgt.org/published/0003/02/01/ - let oct, dec, best, currentCos, bestCos; - let i; - let localNormal = new Float32Array([0, 0, 0, 0]); - let worldNormal = new Float32Array([0, 0, 0, 0]); - for (i = 0; i < lenNormals; i += 3) { - localNormal[0] = normals[i]; - localNormal[1] = normals[i + 1]; - localNormal[2] = normals[i + 2]; + t = t / (this._frames[this._frames.length - 1].t - this._frames[0].t); + t = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t); - math.transformVec3(worldNormalMatrix, localNormal, worldNormal); - math.normalizeVec3(worldNormal, worldNormal); + camera.eye = this._eyeCurve.getPoint(t, tempVec3a$W); + camera.look = this._lookCurve.getPoint(t, tempVec3a$W); + camera.up = this._upCurve.getPoint(t, tempVec3a$W); + } - // Test various combinations of ceil and floor to minimize rounding errors - best = oct = octEncodeVec3(worldNormal, "floor", "floor"); - dec = octDecodeVec2(oct); - currentCos = bestCos = dot(worldNormal, dec); - oct = octEncodeVec3(worldNormal, "ceil", "floor"); - dec = octDecodeVec2(oct); - currentCos = dot(worldNormal, dec); - if (currentCos > bestCos) { - best = oct; - bestCos = currentCos; - } - oct = octEncodeVec3(worldNormal, "floor", "ceil"); - dec = octDecodeVec2(oct); - currentCos = dot(worldNormal, dec); - if (currentCos > bestCos) { - best = oct; - bestCos = currentCos; - } - oct = octEncodeVec3(worldNormal, "ceil", "ceil"); - dec = octDecodeVec2(oct); - currentCos = dot(worldNormal, dec); - if (currentCos > bestCos) { - best = oct; - bestCos = currentCos; - } - compressedNormals[lenCompressedNormals + i + 0] = best[0]; - compressedNormals[lenCompressedNormals + i + 1] = best[1]; - compressedNormals[lenCompressedNormals + i + 2] = 0.0; // Unused + /** + * Gets eye, look and up vectors on this CameraPath at a given instant. + * + * @param {Number} t Time instant. + * @param {Number[]} eye The eye position to update. + * @param {Number[]} look The look position to update. + * @param {Number[]} up The up vector to update. + */ + sampleFrame(t, eye, look, up) { + t = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t); + this._eyeCurve.getPoint(t, eye); + this._lookCurve.getPoint(t, look); + this._upCurve.getPoint(t, up); } - lenCompressedNormals += lenNormals; - return lenCompressedNormals; -} -/** - * @private - */ -function octEncodeNormals(normals) { // http://jcgt.org/published/0003/02/01/ - const lenNormals = normals.length; - const compressedNormals = new Int8Array(lenNormals); - let oct, best, currentCos, bestCos; - for (let i = 0; i < lenNormals; i += 3) { - // Test various combinations of ceil and floor to minimize rounding errors - best = oct = octEncodeNormal(normals, i, "floor", "floor"); - octDecodeVec2(oct); - currentCos = bestCos = dot(normals, i); - oct = octEncodeNormal(normals, i, "ceil", "floor"); - octDecodeVec2(oct); - currentCos = dot(normals, i); - if (currentCos > bestCos) { - best = oct; - bestCos = currentCos; + /** + * Given a total duration (in seconds) for this CameraPath, recomputes the time instant at each frame so that, + * when animated by {@link CameraPathAnimation}, the {@link Camera} will move along the path at a constant rate. + * + * @param {Number} duration The total duration for this CameraPath. + */ + smoothFrameTimes(duration) { + const numFrames = this._frames.length; + if (numFrames === 0) { + return; } - oct = octEncodeNormal(normals, i, "floor", "ceil"); - octDecodeVec2(oct); - currentCos = dot(normals, i); - if (currentCos > bestCos) { - best = oct; - bestCos = currentCos; + const vec = math.vec3(); + var totalLen = 0; + this._frames[0].t = 0; + const lens = []; + for (let i = 1, len = this._frames.length; i < len; i++) { + var lenVec = math.lenVec3(math.subVec3(this._frames[i].eye, this._frames[i - 1].eye, vec)); + lens[i] = lenVec; + totalLen += lenVec; } - oct = octEncodeNormal(normals, i, "ceil", "ceil"); - octDecodeVec2(oct); - currentCos = dot(normals, i); - if (currentCos > bestCos) { - best = oct; - bestCos = currentCos; + for (let i = 1, len = this._frames.length; i < len; i++) { + const interFrameRate = (lens[i] / totalLen) * duration; + this._frames[i].t = this._frames[i-1].t + interFrameRate; } - compressedNormals[i + 0] = best[0]; - compressedNormals[i + 1] = best[1]; - compressedNormals[i + 2] = 0.0; // Unused } - return compressedNormals; -} -/** - * @private - */ -function octEncodeVec3(p, xfunc, yfunc) { // Oct-encode single normal vector in 2 bytes - let x = p[0] / (Math.abs(p[0]) + Math.abs(p[1]) + Math.abs(p[2])); - let y = p[1] / (Math.abs(p[0]) + Math.abs(p[1]) + Math.abs(p[2])); - if (p[2] < 0) { - let tempx = x; - let tempy = y; - tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); - tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); - x = tempx; - y = tempy; + /** + * Removes all frames from this CameraPath. + */ + clearFrames() { + this._frames = []; + this._eyeCurve.points = []; + this._lookCurve.points = []; + this._upCurve.points = []; } - return new Int8Array([ - Math[xfunc](x * 127.5 + (x < 0 ? -1 : 0)), - Math[yfunc](y * 127.5 + (y < 0 ? -1 : 0)) - ]); } -/** - * @private - */ -function octEncodeNormal(array, i, xfunc, yfunc) { // Oct-encode single normal vector in 2 bytes - let x = array[i] / (Math.abs(array[i]) + Math.abs(array[i + 1]) + Math.abs(array[i + 2])); - let y = array[i + 1] / (Math.abs(array[i]) + Math.abs(array[i + 1]) + Math.abs(array[i + 2])); - if (array[i + 2] < 0) { - let tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); - let tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); - x = tempx; - y = tempy; - } - return new Int8Array([ - Math[xfunc](x * 127.5 + (x < 0 ? -1 : 0)), - Math[yfunc](y * 127.5 + (y < 0 ? -1 : 0)) - ]); -} +const tempVec3$3 = math.vec3(); +const newLook = math.vec3(); +const newEye = math.vec3(); +const newUp = math.vec3(); +const newLookEyeVec = math.vec3(); /** - * @private + * @desc Jumps or flies the {@link Scene}'s {@link Camera} to a given target. + * + * * Located at {@link Viewer#cameraFlight} + * * Can fly or jump to its target. + * * While flying, can be stopped, or redirected to a different target. + * * Can also smoothly transition between ortho and perspective projections. + * + * + * A CameraFlightAnimation's target can be: + * + * * specific ````eye````, ````look```` and ````up```` positions, + * * an axis-aligned World-space bounding box (AABB), or + * * an instance or ID of any {@link Component} subtype that provides a World-space AABB. + * + * A target can also contain a ````projection```` type to transition into. For example, if your {@link Camera#projection} is + * currently ````"perspective"```` and you supply {@link CameraFlightAnimation#flyTo} with a ````projection```` property + * equal to "ortho", then CameraFlightAnimation will smoothly transition the Camera into an orthographic projection. + * + * Configure {@link CameraFlightAnimation#fit} and {@link CameraFlightAnimation#fitFOV} to make it stop at the point + * where the target occupies a certain amount of the field-of-view. + * + * ## Flying to an Entity + * + * Flying to an {@link Entity}: + * + * ````Javascript + * var entity = new Mesh(viewer.scene); + * + * // Fly to the Entity's World-space AABB + * viewer.cameraFlight.flyTo(entity); + * ```` + * ## Flying to a Position + * + * Flying the CameraFlightAnimation from the previous example to specified eye, look and up positions: + * + * ````Javascript + * viewer.cameraFlight.flyTo({ + * eye: [-5,-5,-5], + * look: [0,0,0] + * up: [0,1,0], + * duration: 1 // Default, seconds + * },() => { + * // Done + * }); + * ```` + * + * ## Flying to an AABB + * + * Flying the CameraFlightAnimation from the previous two examples explicitly to the {@link Boundary3D"}}Boundary3D's{{/crossLink}} + * axis-aligned bounding box: + * + * ````Javascript + * viewer.cameraFlight.flyTo(entity.aabb); + * ```` + * + * ## Transitioning Between Projections + * + * CameraFlightAnimation also allows us to smoothly transition between Camera projections. We can do that by itself, or + * in addition to flying the Camera to a target. + * + * Let's transition the Camera to orthographic projection: + * + * [[Run example](http://xeokit.github.io/xeokit-sdk/examples/#camera_CameraFlightAnimation_projection)] + * + * ````Javascript + * viewer.cameraFlight.flyTo({ projection: "ortho", () => { + * // Done + * }); + * ```` + * + * Now let's transition the Camera back to perspective projection: + * + * ````Javascript + * viewer.cameraFlight.flyTo({ projection: "perspective"}, () => { + * // Done + * }); + * ```` + * + * Fly Camera to a position, while transitioning to orthographic projection: + * + * ````Javascript + * viewer.cameraFlight.flyTo({ + * eye: [-100,20,2], + * look: [0,0,-40], + * up: [0,1,0], + * projection: "ortho", () => { + * // Done + * }); + * ```` */ -function octDecodeVec2(oct) { // Decode an oct-encoded normal - let x = oct[0]; - let y = oct[1]; - x /= x < 0 ? 127 : 128; - y /= y < 0 ? 127 : 128; - const z = 1 - Math.abs(x) - Math.abs(y); - if (z < 0) { - x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); - y = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); +class CameraFlightAnimation extends Component { + + /** + * @private + */ + get type() { + return "CameraFlightAnimation"; } - const length = Math.sqrt(x * x + y * y + z * z); - return [ - x / length, - y / length, - z / length - ]; -} -/** - * @private - */ -function dot(p, vec3) { // Dot product of a normal in an array against a candidate decoding - return p[0] * vec3[0] + p[1] * vec3[1] + p[2] * vec3[2]; -} + /** + @constructor + @private + */ + constructor(owner, cfg = {}) { -const tempMat4$2 = math.mat4(); -const tempMat4b = math.mat4(); -const tempVec4a$a = math.vec4([0, 0, 0, 1]); -const tempVec4b$a = math.vec4([0, 0, 0, 1]); -const tempVec4c$7 = math.vec4([0, 0, 0, 1]); -const tempOBB3$2 = math.OBB3(); + super(owner, cfg); -const tempVec3a$H = math.vec3(); -const tempVec3b$8 = math.vec3(); -const tempVec3c$5 = math.vec3(); -const tempVec3d$2 = math.vec3(); -const tempVec3e$1 = math.vec3(); -const tempVec3f$1 = math.vec3(); -const tempVec3g$1 = math.vec3(); + this._look1 = math.vec3(); + this._eye1 = math.vec3(); + this._up1 = math.vec3(); + this._look2 = math.vec3(); + this._eye2 = math.vec3(); + this._up2 = math.vec3(); + this._orthoScale1 = 1; + this._orthoScale2 = 1; + this._flying = false; + this._flyEyeLookUp = false; + this._flyingEye = false; + this._flyingLook = false; + this._callback = null; + this._callbackScope = null; + this._time1 = null; + this._time2 = null; + this.easing = cfg.easing !== false; -/** - * @private - */ -class TrianglesBatchingLayer { + this.duration = cfg.duration; + this.fit = cfg.fit; + this.fitFOV = cfg.fitFOV; + this.trail = cfg.trail; + } /** - * @param model - * @param cfg.model - * @param cfg.autoNormals - * @param cfg.layerIndex - * @param cfg.positionsDecodeMatrix - * @param cfg.uvDecodeMatrix - * @param cfg.maxGeometryBatchSize - * @param cfg.origin - * @param cfg.scratchMemory - * @param cfg.textureSet - * @param cfg.solid + * Flies the {@link Camera} to a target. + * + * * When the target is a boundary, the {@link Camera} will fly towards the target and stop when the target fills most of the canvas. + * * When the target is an explicit {@link Camera} position, given as ````eye````, ````look```` and ````up````, then CameraFlightAnimation will interpolate the {@link Camera} to that target and stop there. + * + * @param {Object|Component} [params=Scene] Either a parameters object or a {@link Component} subtype that has + * an AABB. Defaults to the {@link Scene}, which causes the {@link Camera} to fit the Scene in view. + * @param {Number} [params.arc=0] Factor in range ````[0..1]```` indicating how much the {@link Camera#eye} position + * will swing away from its {@link Camera#look} position as it flies to the target. + * @param {Number|String|Component} [params.component] ID or instance of a component to fly to. Defaults to the entire {@link Scene}. + * @param {Number[]} [params.aabb] World-space axis-aligned bounding box (AABB) target to fly to. + * @param {Number[]} [params.eye] Position to fly the eye position to. + * @param {Number[]} [params.look] Position to fly the look position to. + * @param {Number[]} [params.up] Position to fly the up vector to. + * @param {String} [params.projection] Projection type to transition into as we fly. Can be any of the values of {@link Camera.projection}. + * @param {Boolean} [params.fit=true] Whether to fit the target to the view volume. Overrides {@link CameraFlightAnimation#fit}. + * @param {Number} [params.fitFOV] How much of field-of-view, in degrees, that a target {@link Entity} or its AABB should + * fill the canvas on arrival. Overrides {@link CameraFlightAnimation#fitFOV}. + * @param {Number} [params.duration] Flight duration in seconds. Overrides {@link CameraFlightAnimation#duration}. + * @param {Number} [params.orthoScale] Animate the Camera's orthographic scale to this target value. See {@link Ortho#scale}. + * @param {Function} [callback] Callback fired on arrival. + * @param {Object} [scope] Optional scope for callback. */ - constructor(cfg) { - - /** - * Owner model - * @type {VBOSceneModel} - */ - this.model = cfg.model; + flyTo(params, callback, scope) { - /** - * State sorting key. - * @type {string} - */ - this.sortId = "TrianglesBatchingLayer" - + (cfg.solid ? "-solid" : "-surface") - + (cfg.autoNormals ? "-autonormals" : "-normals") + params = params || this.scene; - // TODO: These two parts need to be IDs (ie. unique): + if (this._flying) { + this.stop(); + } - + (cfg.textureSet && cfg.textureSet.colorTexture ? "-colorTexture" : "") - + (cfg.textureSet && cfg.textureSet.metallicRoughnessTexture ? "-metallicRoughnessTexture" : ""); + this._flying = false; + this._flyingEye = false; + this._flyingLook = false; + this._flyingEyeLookUp = false; - /** - * Index of this TrianglesBatchingLayer in {@link VBOSceneModel#_layerList}. - * @type {Number} - */ - this.layerIndex = cfg.layerIndex; + this._callback = callback; + this._callbackScope = scope; - this._batchingRenderers = getBatchingRenderers$1(cfg.model.scene); - this._buffer = new TrianglesBatchingBuffer(cfg.maxGeometryBatchSize); - this._scratchMemory = cfg.scratchMemory; + const camera = this.scene.camera; + const flyToProjection = (!!params.projection) && (params.projection !== camera.projection); - this._state = new RenderState({ - origin: math.vec3(), - positionsBuf: null, - offsetsBuf: null, - normalsBuf: null, - colorsBuf: null, - uvBuf: null, - metallicRoughnessBuf: null, - flagsBuf: null, - flags2Buf: null, - indicesBuf: null, - edgeIndicesBuf: null, - positionsDecodeMatrix: math.mat4(), - uvDecodeMatrix: null, - textureSet: cfg.textureSet, - pbrSupported: false // Set in #finalize if we have enough to support quality rendering - }); + this._eye1[0] = camera.eye[0]; + this._eye1[1] = camera.eye[1]; + this._eye1[2] = camera.eye[2]; - // These counts are used to avoid unnecessary render passes - this._numPortions = 0; - this._numVisibleLayerPortions = 0; - this._numTransparentLayerPortions = 0; - this._numXRayedLayerPortions = 0; - this._numSelectedLayerPortions = 0; - this._numHighlightedLayerPortions = 0; - this._numClippableLayerPortions = 0; - this._numEdgesLayerPortions = 0; - this._numPickableLayerPortions = 0; - this._numCulledLayerPortions = 0; + this._look1[0] = camera.look[0]; + this._look1[1] = camera.look[1]; + this._look1[2] = camera.look[2]; - this._modelAABB = math.collapseAABB3(); // Model-space AABB - this._portions = []; + this._up1[0] = camera.up[0]; + this._up1[1] = camera.up[1]; + this._up1[2] = camera.up[2]; - this._numVerts = 0; + this._orthoScale1 = camera.ortho.scale; + this._orthoScale2 = params.orthoScale || this._orthoScale1; - this._finalized = false; + let aabb; + let eye; + let look; + let up; + let componentId; - if (cfg.positionsDecodeMatrix) { - this._state.positionsDecodeMatrix.set(cfg.positionsDecodeMatrix); - this._preCompressedPositionsExpected = true; - } else { - this._preCompressedPositionsExpected = false; - } + if (params.aabb) { + aabb = params.aabb; - if (cfg.uvDecodeMatrix) { - this._state.uvDecodeMatrix = math.mat3(cfg.uvDecodeMatrix); - this._preCompressedNormalsExpected = true; - } else { - this._preCompressedNormalsExpected = false; - } + } else if (params.length === 6) { + aabb = params; - if (cfg.origin) { - this._state.origin.set(cfg.origin); - } + } else if ((params.eye && params.look) || params.up) { + eye = params.eye; + look = params.look; + up = params.up; - /** - * The axis-aligned World-space boundary of this TrianglesBatchingLayer's positions. - * @type {*|Float64Array} - */ - this.aabb = math.collapseAABB3(); - - /** - * When true, this layer contains solid triangle meshes, otherwise this layer contains surface triangle meshes - * @type {boolean} - */ - this.solid = !!cfg.solid; - } + } else if (params.eye) { + eye = params.eye; - /** - * Tests if there is room for another portion in this TrianglesBatchingLayer. - * - * @param lenPositions Number of positions we'd like to create in the portion. - * @param lenIndices Number of indices we'd like to create in this portion. - * @returns {boolean} True if OK to create another portion. - */ - canCreatePortion(lenPositions, lenIndices) { - if (this._finalized) { - throw "Already finalized"; - } - return ((this._buffer.positions.length + lenPositions) < (this._buffer.maxVerts * 3) && (this._buffer.indices.length + lenIndices) < (this._buffer.maxIndices)); - } + } else if (params.look) { + look = params.look; - /** - * Creates a new portion within this TrianglesBatchingLayer, returns the new portion ID. - * - * Gives the portion the specified geometry, color and matrix. - * - * @param cfg.positions Flat float Local-space positions array. - * @param cfg.positionsCompressed Flat quantized positions array - decompressed with TrianglesBatchingLayer positionsDecodeMatrix - * @param [cfg.normals] Flat float normals array. - * @param [cfg.uv] Flat UVs array. - * @param [cfg.uvCompressed] - * @param [cfg.colors] Flat float colors array. - * @param [cfg.colorsCompressed] - * @param cfg.indices Flat int indices array. - * @param [cfg.edgeIndices] Flat int edges indices array. - * @param cfg.color Quantized RGB color [0..255,0..255,0..255,0..255] - * @param cfg.metallic Metalness factor [0..255] - * @param cfg.roughness Roughness factor [0..255] - * @param cfg.opacity Opacity [0..255] - * @param [cfg.meshMatrix] Flat float 4x4 matrix - * @param [cfg.worldMatrix] Flat float 4x4 matrix - * @param cfg.worldAABB Flat float AABB World-space AABB - * @param cfg.pickColor Quantized pick color - * @returns {number} Portion ID - */ - createPortion(cfg) { + } else { // Argument must be an instance or ID of a Component (subtype) - if (this._finalized) { - throw "Already finalized"; - } + let component = params; - const positions = cfg.positions; - const positionsCompressed = cfg.positionsCompressed; - const normals = cfg.normals; - const normalsCompressed = cfg.normalsCompressed; - const uv = cfg.uv; - const uvCompressed = cfg.uvCompressed; - const colors = cfg.colors; - const colorsCompressed = cfg.colorsCompressed; - const indices = cfg.indices; - const edgeIndices = cfg.edgeIndices; - const color = cfg.color; - const metallic = cfg.metallic; - const roughness = cfg.roughness; - const opacity = cfg.opacity; - const meshMatrix = cfg.meshMatrix; - const worldMatrix = cfg.worldMatrix; - const worldAABB = cfg.worldAABB; - const pickColor = cfg.pickColor; + if (utils.isNumeric(component) || utils.isString(component)) { - const scene = this.model.scene; - const buffer = this._buffer; - const positionsIndex = buffer.positions.length; - const vertsIndex = positionsIndex / 3; + componentId = component; + component = this.scene.components[componentId]; - let numVerts; + if (!component) { + this.error("Component not found: " + utils.inQuotes(componentId)); + if (callback) { + if (scope) { + callback.call(scope); + } else { + callback(); + } + } + return; + } + } + if (!flyToProjection) { + aabb = component.aabb || this.scene.aabb; + } + } + const poi = params.poi; - if (this._preCompressedPositionsExpected) { + if (aabb) { - if (!positionsCompressed) { - throw "positionsCompressed expected"; + if (aabb[3] < aabb[0] || aabb[4] < aabb[1] || aabb[5] < aabb[2]) { // Don't fly to an inverted boundary + return; } - numVerts = positionsCompressed.length / 3; - - for (let i = 0, len = positionsCompressed.length; i < len; i++) { - buffer.positions.push(positionsCompressed[i]); + if (aabb[3] === aabb[0] && aabb[4] === aabb[1] && aabb[5] === aabb[2]) { // Don't fly to an empty boundary + return; } - const bounds = geometryCompressionUtils.getPositionsBounds(positionsCompressed); + aabb = aabb.slice(); + const aabbCenter = math.getAABB3Center(aabb); - const min = geometryCompressionUtils.decompressPosition(bounds.min, this._state.positionsDecodeMatrix, []); - const max = geometryCompressionUtils.decompressPosition(bounds.max, this._state.positionsDecodeMatrix, []); + this._look2 = poi || aabbCenter; - worldAABB[0] = min[0]; - worldAABB[1] = min[1]; - worldAABB[2] = min[2]; - worldAABB[3] = max[0]; - worldAABB[4] = max[1]; - worldAABB[5] = max[2]; + const eyeLookVec = math.subVec3(this._eye1, this._look1, tempVec3$3); + const eyeLookVecNorm = math.normalizeVec3(eyeLookVec); + const diag = poi ? math.getAABB3DiagPoint(aabb, poi) : math.getAABB3Diag(aabb); + const fitFOV = params.fitFOV || this._fitFOV; + const sca = Math.abs(diag / Math.tan(fitFOV * math.DEGTORAD)); - if (worldMatrix) { - math.AABB3ToOBB3(worldAABB, tempOBB3$2); - math.transformOBB3(worldMatrix, tempOBB3$2); - math.OBB3ToAABB3(tempOBB3$2, worldAABB); - } + this._orthoScale2 = diag * 1.1; - } else { + this._eye2[0] = this._look2[0] + (eyeLookVecNorm[0] * sca); + this._eye2[1] = this._look2[1] + (eyeLookVecNorm[1] * sca); + this._eye2[2] = this._look2[2] + (eyeLookVecNorm[2] * sca); - if (!positions) { - throw "positions expected"; - } + this._up2[0] = this._up1[0]; + this._up2[1] = this._up1[1]; + this._up2[2] = this._up1[2]; - numVerts = positions.length / 3; + this._flyingEyeLookUp = true; - const lenPositions = positions.length; + } else if (eye || look || up) { - const positionsBase = buffer.positions.length; + this._flyingEyeLookUp = !!eye && !!look && !!up; + this._flyingEye = !!eye && !look; + this._flyingLook = !!look && !eye; - for (let i = 0, len = positions.length; i < len; i++) { - buffer.positions.push(positions[i]); + if (eye) { + this._eye2[0] = eye[0]; + this._eye2[1] = eye[1]; + this._eye2[2] = eye[2]; } - if (meshMatrix) { - - for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { + if (look) { + this._look2[0] = look[0]; + this._look2[1] = look[1]; + this._look2[2] = look[2]; + } - tempVec4a$a[0] = buffer.positions[i + 0]; - tempVec4a$a[1] = buffer.positions[i + 1]; - tempVec4a$a[2] = buffer.positions[i + 2]; + if (up) { + this._up2[0] = up[0]; + this._up2[1] = up[1]; + this._up2[2] = up[2]; + } + } - math.transformPoint4(meshMatrix, tempVec4a$a, tempVec4b$a); + if (flyToProjection) { - buffer.positions[i + 0] = tempVec4b$a[0]; - buffer.positions[i + 1] = tempVec4b$a[1]; - buffer.positions[i + 2] = tempVec4b$a[2]; + if (params.projection === "ortho" && camera.projection !== "ortho") { + this._projection2 = "ortho"; + this._projMatrix1 = camera.projMatrix.slice(); + this._projMatrix2 = camera.ortho.matrix.slice(); + camera.projection = "customProjection"; + } - math.expandAABB3Point3(this._modelAABB, tempVec4b$a); + if (params.projection === "perspective" && camera.projection !== "perspective") { + this._projection2 = "perspective"; + this._projMatrix1 = camera.projMatrix.slice(); + this._projMatrix2 = camera.perspective.matrix.slice(); + camera.projection = "customProjection"; + } + } else { + this._projection2 = null; + } - if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4b$a, tempVec4c$7); - math.expandAABB3Point3(worldAABB, tempVec4c$7); - } else { - math.expandAABB3Point3(worldAABB, tempVec4b$a); - } - } + this.fire("started", params, true); - } else { + this._time1 = Date.now(); + this._time2 = this._time1 + (params.duration ? params.duration * 1000 : this._duration); - for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { + this._flying = true; // False as soon as we stop - tempVec4a$a[0] = buffer.positions[i + 0]; - tempVec4a$a[1] = buffer.positions[i + 1]; - tempVec4a$a[2] = buffer.positions[i + 2]; + core.scheduleTask(this._update, this); + } - math.expandAABB3Point3(this._modelAABB, tempVec4a$a); + /** + * Jumps the {@link Scene}'s {@link Camera} to the given target. + * + * * When the target is a boundary, this CameraFlightAnimation will position the {@link Camera} at where the target fills most of the canvas. + * * When the target is an explicit {@link Camera} position, given as ````eye````, ````look```` and ````up```` vectors, then this CameraFlightAnimation will jump the {@link Camera} to that target. + * + * @param {*|Component} params Either a parameters object or a {@link Component} subtype that has a World-space AABB. + * @param {Number} [params.arc=0] Factor in range [0..1] indicating how much the {@link Camera#eye} will swing away from its {@link Camera#look} as it flies to the target. + * @param {Number|String|Component} [params.component] ID or instance of a component to fly to. + * @param {Number[]} [params.aabb] World-space axis-aligned bounding box (AABB) target to fly to. + * @param {Number[]} [params.eye] Position to fly the eye position to. + * @param {Number[]} [params.look] Position to fly the look position to. + * @param {Number[]} [params.up] Position to fly the up vector to. + * @param {String} [params.projection] Projection type to transition into. Can be any of the values of {@link Camera.projection}. + * @param {Number} [params.fitFOV] How much of field-of-view, in degrees, that a target {@link Entity} or its AABB should fill the canvas on arrival. Overrides {@link CameraFlightAnimation#fitFOV}. + * @param {Boolean} [params.fit] Whether to fit the target to the view volume. Overrides {@link CameraFlightAnimation#fit}. + */ + jumpTo(params) { + this._jumpTo(params); + } - if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4a$a, tempVec4b$a); - math.expandAABB3Point3(worldAABB, tempVec4b$a); - } else { - math.expandAABB3Point3(worldAABB, tempVec4a$a); - } - } - } - } + _jumpTo(params) { - if (this._state.origin) { - const origin = this._state.origin; - worldAABB[0] += origin[0]; - worldAABB[1] += origin[1]; - worldAABB[2] += origin[2]; - worldAABB[3] += origin[0]; - worldAABB[4] += origin[1]; - worldAABB[5] += origin[2]; + if (this._flying) { + this.stop(); } - math.expandAABB3(this.aabb, worldAABB); + const camera = this.scene.camera; - if (normalsCompressed && normalsCompressed.length > 0) { - for (let i = 0, len = normalsCompressed.length; i < len; i++) { - buffer.normals.push(normalsCompressed[i]); - } - } else if (normals && normals.length > 0) { - const worldNormalMatrix = tempMat4$2; - if (meshMatrix) { - math.inverseMat4(math.transposeMat4(meshMatrix, tempMat4b), worldNormalMatrix); // Note: order of inverse and transpose doesn't matter - } else { - math.identityMat4(worldNormalMatrix, worldNormalMatrix); - } - transformAndOctEncodeNormals(worldNormalMatrix, normals, normals.length, buffer.normals, buffer.normals.length); - } + var aabb; + var componentId; + var newEye; + var newLook; + var newUp; - if (colors) { - for (let i = 0, len = colors.length; i < len; i += 3) { - buffer.colors.push(colors[i] * 255); - buffer.colors.push(colors[i + 1] * 255); - buffer.colors.push(colors[i + 2] * 255); - buffer.colors.push(255); - } - } else if (colorsCompressed) { - for (let i = 0, len = colors.length; i < len; i += 3) { - buffer.colors.push(colors[i]); - buffer.colors.push(colors[i + 1]); - buffer.colors.push(colors[i + 2]); - buffer.colors.push(255); - } - } else if (color) { - const r = color[0]; // Color is pre-quantized by VBOSceneModel - const g = color[1]; - const b = color[2]; - const a = opacity; - const metallicValue = (metallic !== null && metallic !== undefined) ? metallic : 0; - const roughnessValue = (roughness !== null && roughness !== undefined) ? roughness : 255; - for (let i = 0; i < numVerts; i++) { - buffer.colors.push(r); - buffer.colors.push(g); - buffer.colors.push(b); - buffer.colors.push(a); - buffer.metallicRoughness.push(metallicValue); - buffer.metallicRoughness.push(roughnessValue); - } - } + if (params.aabb) { // Boundary3D + aabb = params.aabb; - if (uv && uv.length > 0) { - for (let i = 0, len = uv.length; i < len; i++) { - buffer.uv.push(uv[i]); - } - } else if (uvCompressed && uvCompressed.length > 0) { - for (let i = 0, len = uvCompressed.length; i < len; i++) { - buffer.uv.push(uvCompressed[i]); - } - } + } else if (params.length === 6) { // AABB + aabb = params; - if (indices) { - for (let i = 0, len = indices.length; i < len; i++) { - buffer.indices.push(indices[i] + vertsIndex); - } - } + } else if (params.eye || params.look || params.up) { // Camera pose + newEye = params.eye; + newLook = params.look; + newUp = params.up; - if (edgeIndices) { - for (let i = 0, len = edgeIndices.length; i < len; i++) { - buffer.edgeIndices.push(edgeIndices[i] + vertsIndex); - } - } + } else { // Argument must be an instance or ID of a Component (subtype) - { - const pickColorsBase = buffer.pickColors.length; - const lenPickColors = numVerts * 4; - for (let i = pickColorsBase, len = pickColorsBase + lenPickColors; i < len; i += 4) { - buffer.pickColors.push(pickColor[0]); - buffer.pickColors.push(pickColor[1]); - buffer.pickColors.push(pickColor[2]); - buffer.pickColors.push(pickColor[3]); - } - } + let component = params; - if (scene.entityOffsetsEnabled) { - for (let i = 0; i < numVerts; i++) { - buffer.offsets.push(0); - buffer.offsets.push(0); - buffer.offsets.push(0); + if (utils.isNumeric(component) || utils.isString(component)) { + componentId = component; + component = this.scene.components[componentId]; + if (!component) { + this.error("Component not found: " + utils.inQuotes(componentId)); + return; + } } + aabb = component.aabb || this.scene.aabb; } - const portionId = this._portions.length; + const poi = params.poi; - const portion = { - vertsBase: vertsIndex, - numVerts: numVerts - }; + if (aabb) { - if (scene.pickSurfacePrecisionEnabled) { - // Quantized in-memory positions are initialized in finalize() - if (indices) { - portion.indices = indices; - } - if (scene.entityOffsetsEnabled) { - portion.offset = new Float32Array(3); + if (aabb[3] <= aabb[0] || aabb[4] <= aabb[1] || aabb[5] <= aabb[2]) { // Don't fly to an empty boundary + return; } - } - - this._portions.push(portion); - this._numPortions++; + var diag = poi ? math.getAABB3DiagPoint(aabb, poi) : math.getAABB3Diag(aabb); - this.model.numPortions++; + newLook = poi || math.getAABB3Center(aabb, newLook); - this._numVerts += portion.numVerts; + if (this._trail) { + math.subVec3(camera.look, newLook, newLookEyeVec); + } else { + math.subVec3(camera.eye, camera.look, newLookEyeVec); + } - return portionId; - } + math.normalizeVec3(newLookEyeVec); + let dist; + const fit = (params.fit !== undefined) ? params.fit : this._fit; - /** - * Builds batch VBOs from appended geometries. - * No more portions can then be created. - */ - finalize() { + if (fit) { + dist = Math.abs((diag) / Math.tan((params.fitFOV || this._fitFOV) * math.DEGTORAD)); - if (this._finalized) { - this.model.error("Already finalized"); - return; - } + } else { + dist = math.lenVec3(math.subVec3(camera.eye, camera.look, tempVec3$3)); + } - const state = this._state; - const gl = this.model.scene.canvas.gl; - const buffer = this._buffer; + math.mulVec3Scalar(newLookEyeVec, dist); - if (buffer.positions.length > 0) { + camera.eye = math.addVec3(newLook, newLookEyeVec, tempVec3$3); + camera.look = newLook; - const quantizedPositions = (this._preCompressedPositionsExpected) - ? new Uint16Array(buffer.positions) - : quantizePositions(buffer.positions, this._modelAABB, state.positionsDecodeMatrix); // BOTTLENECK + this.scene.camera.ortho.scale = diag * 1.1; - state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, quantizedPositions.length, 3, gl.STATIC_DRAW); + } else if (newEye || newLook || newUp) { - if (this.model.scene.pickSurfacePrecisionEnabled) { - for (let i = 0, numPortions = this._portions.length; i < numPortions; i++) { - const portion = this._portions[i]; - const start = portion.vertsBase * 3; - const end = start + (portion.numVerts * 3); - portion.quantizedPositions = quantizedPositions.slice(start, end); - } + if (newEye) { + camera.eye = newEye; + } + if (newLook) { + camera.look = newLook; + } + if (newUp) { + camera.up = newUp; } } - if (buffer.normals.length > 0) { - const normals = new Int8Array(buffer.normals); - let normalized = true; // For oct encoded UInts - state.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, normals, buffer.normals.length, 3, gl.STATIC_DRAW, normalized); - } - - if (buffer.colors.length > 0) { - const colors = new Uint8Array(buffer.colors); - let normalized = false; - state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, buffer.colors.length, 4, gl.DYNAMIC_DRAW, normalized); + if (params.projection) { + camera.projection = params.projection; } + } - if (buffer.uv.length > 0) { - if (!state.uvDecodeMatrix) { - const bounds = geometryCompressionUtils.getUVBounds(buffer.uv); - const result = geometryCompressionUtils.compressUVs(buffer.uv, bounds.min, bounds.max); - const uv = result.quantized; - let notNormalized = false; - state.uvDecodeMatrix = math.mat3(result.decodeMatrix); - state.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uv, uv.length, 2, gl.STATIC_DRAW, notNormalized); - } else { - let notNormalized = false; - state.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, buffer.uv, buffer.uv.length, 2, gl.STATIC_DRAW, notNormalized); - } + _update() { + if (!this._flying) { + return; } + const time = Date.now(); + let t = (time - this._time1) / (this._time2 - this._time1); + const stopping = (t >= 1); - if (buffer.metallicRoughness.length > 0) { - const metallicRoughness = new Uint8Array(buffer.metallicRoughness); - let normalized = false; - state.metallicRoughnessBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, metallicRoughness, buffer.metallicRoughness.length, 2, gl.STATIC_DRAW, normalized); + if (t > 1) { + t = 1; } - if (buffer.positions.length > 0) { // Because we build flags arrays here, get their length from the positions array - const flagsLength = (buffer.positions.length / 3) * 4; - const flags = new Uint8Array(flagsLength); - const flags2 = new Uint8Array(flagsLength); - let notNormalized = false; - let normalized = true; - state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags, flags.length, 4, gl.DYNAMIC_DRAW, notNormalized); - state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags2, flags2.length, 4, gl.DYNAMIC_DRAW, normalized); - } + const tFlight = this.easing ? CameraFlightAnimation._ease(t, 0, 1, 1) : t; + const camera = this.scene.camera; - if (buffer.pickColors.length > 0) { - const pickColors = new Uint8Array(buffer.pickColors); - let normalized = false; - state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, pickColors, buffer.pickColors.length, 4, gl.STATIC_DRAW, normalized); - } + if (this._flyingEye || this._flyingLook) { - if (this.model.scene.entityOffsetsEnabled) { - if (buffer.offsets.length > 0) { - const offsets = new Float32Array(buffer.offsets); - state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, offsets, buffer.offsets.length, 3, gl.DYNAMIC_DRAW); + if (this._flyingEye) { + math.subVec3(camera.eye, camera.look, newLookEyeVec); + camera.eye = math.lerpVec3(tFlight, 0, 1, this._eye1, this._eye2, newEye); + camera.look = math.subVec3(newEye, newLookEyeVec, newLook); + } else if (this._flyingLook) { + camera.look = math.lerpVec3(tFlight, 0, 1, this._look1, this._look2, newLook); + camera.up = math.lerpVec3(tFlight, 0, 1, this._up1, this._up2, newUp); } - } - if (buffer.indices.length > 0) { - const indices = new Uint32Array(buffer.indices); - state.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, indices, buffer.indices.length, 1, gl.STATIC_DRAW); - } - if (buffer.edgeIndices.length > 0) { - const edgeIndices = new Uint32Array(buffer.edgeIndices); - state.edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, edgeIndices, buffer.edgeIndices.length, 1, gl.STATIC_DRAW); + } else if (this._flyingEyeLookUp) { + + camera.eye = math.lerpVec3(tFlight, 0, 1, this._eye1, this._eye2, newEye); + camera.look = math.lerpVec3(tFlight, 0, 1, this._look1, this._look2, newLook); + camera.up = math.lerpVec3(tFlight, 0, 1, this._up1, this._up2, newUp); } - this._state.pbrSupported - = !!state.metallicRoughnessBuf - && !!state.uvBuf - && !!state.normalsBuf - && !!state.textureSet - && !!state.textureSet.colorTexture - && !!state.textureSet.metallicRoughnessTexture; + if (this._projection2) { + const tProj = (this._projection2 === "ortho") ? CameraFlightAnimation._easeOutExpo(t, 0, 1, 1) : CameraFlightAnimation._easeInCubic(t, 0, 1, 1); + camera.customProjection.matrix = math.lerpMat4(tProj, 0, 1, this._projMatrix1, this._projMatrix2); - this._state.colorTextureSupported - = !!state.uvBuf - && !!state.normalsBuf - && !!state.textureSet - && !!state.textureSet.colorTexture; + } else { + camera.ortho.scale = this._orthoScale1 + (t * (this._orthoScale2 - this._orthoScale1)); + } - this._buffer = null; - this._finalized = true; + if (stopping) { + camera.ortho.scale = this._orthoScale2; + this.stop(); + return; + } + core.scheduleTask(this._update, this); // Keep flying } - isEmpty() { - return (!this._state.indicesBuf); + static _ease(t, b, c, d) { // Quadratic easing out - decelerating to zero velocity http://gizma.com/easing + t /= d; + return -c * t * (t - 2) + b; } - initFlags(portionId, flags, meshTransparent) { - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } - if (flags & ENTITY_FLAGS.EDGES) { - this._numEdgesLayerPortions++; - this.model.numEdgesLayerPortions++; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } - if (meshTransparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } - const deferred = true; - this._setFlags(portionId, flags, meshTransparent, deferred); - this._setFlags2(portionId, flags, deferred); + static _easeInCubic(t, b, c, d) { + t /= d; + return c * t * t * t + b; } - flushInitFlags() { - this._setDeferredFlags(); - this._setDeferredFlags2(); + static _easeOutExpo(t, b, c, d) { + return c * (-Math.pow(2, -10 * t / d) + 1) + b; } - setVisible(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; + /** + * Stops an earlier flyTo, fires arrival callback. + */ + stop() { + if (!this._flying) { + return; } - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } else { - this._numVisibleLayerPortions--; - this.model.numVisibleLayerPortions--; + this._flying = false; + this._time1 = null; + this._time2 = null; + if (this._projection2) { + this.scene.camera.projection = this._projection2; } - this._setFlags(portionId, flags, transparent); + const callback = this._callback; + if (callback) { + this._callback = null; + if (this._callbackScope) { + callback.call(this._callbackScope); + } else { + callback(); + } + } + this.fire("stopped", true, true); } - setHighlighted(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; + /** + * Cancels an earlier flyTo without calling the arrival callback. + */ + cancel() { + if (!this._flying) { + return; } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } else { - this._numHighlightedLayerPortions--; - this.model.numHighlightedLayerPortions--; + this._flying = false; + this._time1 = null; + this._time2 = null; + if (this._callback) { + this._callback = null; } - this._setFlags(portionId, flags, transparent); + this.fire("canceled", true, true); } - setXRayed(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } else { - this._numXRayedLayerPortions--; - this.model.numXRayedLayerPortions--; - } - this._setFlags(portionId, flags, transparent); + /** + * Sets the flight duration, in seconds, when calling {@link CameraFlightAnimation#flyTo}. + * + * Stops any flight currently in progress. + * + * default value is ````0.5````. + * + * @param {Number} value New duration value. + */ + set duration(value) { + this._duration = value ? (value * 1000.0) : 500; + this.stop(); } - setSelected(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } else { - this._numSelectedLayerPortions--; - this.model.numSelectedLayerPortions--; - } - this._setFlags(portionId, flags, transparent); + /** + * Gets the flight duration, in seconds, when calling {@link CameraFlightAnimation#flyTo}. + * + * default value is ````0.5````. + * + * @returns {Number} New duration value. + */ + get duration() { + return this._duration / 1000.0; } - setEdges(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.EDGES) { - this._numEdgesLayerPortions++; - this.model.numEdgesLayerPortions++; - } else { - this._numEdgesLayerPortions--; - this.model.numEdgesLayerPortions--; - } - this._setFlags(portionId, flags, transparent); + /** + * Sets if, when CameraFlightAnimation is flying to a boundary, it will always adjust the distance between the + * {@link Camera#eye} and {@link Camera#look} so as to ensure that the target boundary is always filling the view volume. + * + * When false, the eye will remain at its current distance from the look position. + * + * Default value is ````true````. + * + * @param {Boolean} value Set ````true```` to activate this behaviour. + */ + set fit(value) { + this._fit = value !== false; } - setClippable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } else { - this._numClippableLayerPortions--; - this.model.numClippableLayerPortions--; - } - this._setFlags2(portionId, flags); + /** + * Gets if, when CameraFlightAnimation is flying to a boundary, it will always adjust the distance between the + * {@link Camera#eye} and {@link Camera#look} so as to ensure that the target boundary is always filling the view volume. + * + * When false, the eye will remain at its current distance from the look position. + * + * Default value is ````true````. + * + * @returns {Boolean} value Set ````true```` to activate this behaviour. + */ + get fit() { + return this._fit; } - setCulled(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } else { - this._numCulledLayerPortions--; - this.model.numCulledLayerPortions--; - } - this._setFlags(portionId, flags, transparent); + /** + * Sets how much of the perspective field-of-view, in degrees, that a target {@link Entity#aabb} should + * fill the canvas when calling {@link CameraFlightAnimation#flyTo} or {@link CameraFlightAnimation#jumpTo}. + * + * Default value is ````45````. + * + * @param {Number} value New FOV value. + */ + set fitFOV(value) { + this._fitFOV = value || 45; } - setCollidable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } + /** + * Gets how much of the perspective field-of-view, in degrees, that a target {@link Entity#aabb} should + * fill the canvas when calling {@link CameraFlightAnimation#flyTo} or {@link CameraFlightAnimation#jumpTo}. + * + * Default value is ````45````. + * + * @returns {Number} Current FOV value. + */ + get fitFOV() { + return this._fitFOV; } - setPickable(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } else { - this._numPickableLayerPortions--; - this.model.numPickableLayerPortions--; - } - this._setFlags(portionId, flags, transparent); + /** + * Sets if this CameraFlightAnimation to point the {@link Camera} + * in the direction that it is travelling when flying to a target after calling {@link CameraFlightAnimation#flyTo}. + * + * Default value is ````true````. + * + * @param {Boolean} value Set ````true```` to activate trailing behaviour. + */ + set trail(value) { + this._trail = !!value; } - setColor(portionId, color) { - if (!this._finalized) { - throw "Not finalized"; - } - const portionsIdx = portionId; - const portion = this._portions[portionsIdx]; - const vertexBase = portion.vertsBase; - const numVerts = portion.numVerts; - const firstColor = vertexBase * 4; - const lenColor = numVerts * 4; - const tempArray = this._scratchMemory.getUInt8Array(lenColor); - const r = color[0]; - const g = color[1]; - const b = color[2]; - const a = color[3]; - for (let i = 0; i < lenColor; i += 4) { - tempArray[i + 0] = r; - tempArray[i + 1] = g; - tempArray[i + 2] = b; - tempArray[i + 3] = a; - } - if (this._state.colorsBuf) { - this._state.colorsBuf.setData(tempArray, firstColor, lenColor); - } + /** + * Gets if this CameraFlightAnimation points the {@link Camera} + * in the direction that it is travelling when flying to a target after calling {@link CameraFlightAnimation#flyTo}. + * + * Default value is ````true````. + * + * @returns {Boolean} True if trailing behaviour is active. + */ + get trail() { + return this._trail; } - setTransparent(portionId, flags, transparent) { - if (transparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } else { - this._numTransparentLayerPortions--; - this.model.numTransparentLayerPortions--; - } - this._setFlags(portionId, flags, transparent); + /** + * @private + */ + destroy() { + this.stop(); + super.destroy(); } +} - _setFlags(portionId, flags, transparent, deferred = false) { +/** + * @desc Animates the {@link Scene}'s's {@link Camera} along a {@link CameraPath}. + * + * ## Usage + * + * In the example below, we'll load a model using a {@link GLTFLoaderPlugin}, then animate a {@link Camera} + * through the frames in a {@link CameraPath}. + * + * * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#camera_CameraPathAnimation)] + * + * ````Javascript + * import {Viewer, GLTFLoaderPlugin, CameraPath, CameraPathAnimation} from "xeokit-sdk.es.js"; + * + * // Create a Viewer and arrange camera + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [124.86756896972656, -93.50288391113281, 173.2632598876953]; + * viewer.camera.look = [102.14186096191406, -90.24193572998047, 173.4224395751953]; + * viewer.camera.up = [0.23516440391540527, 0.9719591736793518, -0.0016466031083837152]; + * + * // Load model + * + * const gltfLoader = new GLTFLoaderPlugin(viewer); + * + * const model = gltfLoader.load({ + * id: "myModel", + * src: "./models/gltf/modern_office/scene.gltf", + * edges: true, + * edgeThreshold: 20, + * xrayed: false + * }); + * + * // Create a CameraPath + * + * var cameraPath = new CameraPath(viewer.scene, { + * frames: [ + * { + * t: 0, + * eye: [124.86, -93.50, 173.26], + * look: [102.14, -90.24, 173.42], + * up: [0.23, 0.97, -0.00] + * }, + * { + * t: 1, + * eye: [79.75, -85.98, 226.57], + * look: [99.24, -84.11, 238.56], + * up: [-0.14, 0.98, -0.09] + * }, + * // Rest of the frames omitted for brevity + * ] + * }); + * + * // Create a CameraPathAnimation to play our CameraPath + * + * var cameraPathAnimation = new CameraPathAnimation(viewer.scene, { + * cameraPath: cameraPath, + * playingRate: 0.2 // Playing 0.2 time units per second + * }); + * + * // Once model loaded, start playing after a couple of seconds delay + * + * model.on("loaded", function () { + * setTimeout(function () { + * cameraPathAnimation.play(0); // Play from the beginning of the CameraPath + * }, 2000); + * }); + * ```` + */ +class CameraPathAnimation extends Component { - if (!this._finalized) { - throw "Not finalized"; - } + /** + * Returns "CameraPathAnimation". + * + * @private + * @returns {string} "CameraPathAnimation" + */ + get type() { + return "CameraPathAnimation" + } - const portionsIdx = portionId; - const portion = this._portions[portionsIdx]; - const vertexBase = portion.vertsBase; - const numVerts = portion.numVerts; - const firstFlag = vertexBase * 4; - const lenFlags = numVerts * 4; + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this CameraPathAnimation as well. + * @param {*} [cfg] Configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {CameraPath} [cfg.eyeCurve] A {@link CameraPath} that defines the path of a {@link Camera}. + */ + constructor(owner, cfg = {}) { - const visible = !!(flags & ENTITY_FLAGS.VISIBLE); - const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); - const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); - const selected = !!(flags & ENTITY_FLAGS.SELECTED); - const edges = !!(flags & ENTITY_FLAGS.EDGES); - const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); - const culled = !!(flags & ENTITY_FLAGS.CULLED); + super(owner, cfg); - // Color + this._cameraFlightAnimation = new CameraFlightAnimation(this); + this._t = 0; + this.state = CameraPathAnimation.SCRUBBING; + this._playingFromT = 0; + this._playingToT = 0; + this._playingRate = cfg.playingRate || 1.0; + this._playingDir = 1.0; + this._lastTime = null; - let f0; - if (!visible || culled || xrayed - || (highlighted && !this.model.scene.highlightMaterial.glowThrough) - || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { - f0 = RENDER_PASSES.NOT_RENDERED; - } else { - if (transparent) { - f0 = RENDER_PASSES.COLOR_TRANSPARENT; - } else { - f0 = RENDER_PASSES.COLOR_OPAQUE; - } - } + this.cameraPath = cfg.cameraPath; - // Silhouette + this._tick = this.scene.on("tick", this._updateT, this); + } - let f1; - if (!visible || culled) { - f1 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f1 = RENDER_PASSES.SILHOUETTE_SELECTED; - } else if (highlighted) { - f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; - } else if (xrayed) { - f1 = RENDER_PASSES.SILHOUETTE_XRAYED; - } else { - f1 = RENDER_PASSES.NOT_RENDERED; + _updateT() { + const cameraPath = this._cameraPath; + if (!cameraPath) { + return; + } + let numFrames; + let t; + const time = performance.now(); + const elapsedSecs = (this._lastTime) ? (time - this._lastTime) * 0.001 : 0; + this._lastTime = time; + if (elapsedSecs === 0) { + return; + } + switch (this.state) { + case CameraPathAnimation.SCRUBBING: + return; + case CameraPathAnimation.PLAYING: + this._t += this._playingRate * elapsedSecs; + numFrames = this._cameraPath.frames.length; + if (numFrames === 0 || (this._playingDir < 0 && this._t <= 0) || (this._playingDir > 0 && this._t >= this._cameraPath.frames[numFrames - 1].t)) { + this.state = CameraPathAnimation.SCRUBBING; + this._t = this._cameraPath.frames[numFrames - 1].t; + this.fire("stopped"); + return; + } + cameraPath.loadFrame(this._t); + break; + case CameraPathAnimation.PLAYING_TO: + t = this._t + (this._playingRate * elapsedSecs * this._playingDir); + if ((this._playingDir < 0 && t <= this._playingToT) || (this._playingDir > 0 && t >= this._playingToT)) { + t = this._playingToT; + this.state = CameraPathAnimation.SCRUBBING; + this.fire("stopped"); + } + this._t = t; + cameraPath.loadFrame(this._t); + break; } + } - // Edges + /* + * @private + */ + _ease(t, b, c, d) { + t /= d; + return -c * t * (t - 2) + b; + } - let f2 = 0; - if (!visible || culled) { - f2 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f2 = RENDER_PASSES.EDGES_SELECTED; - } else if (highlighted) { - f2 = RENDER_PASSES.EDGES_HIGHLIGHTED; - } else if (xrayed) { - f2 = RENDER_PASSES.EDGES_XRAYED; - } else if (edges) { - if (transparent) { - f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT; - } else { - f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE; - } - } else { - f2 = RENDER_PASSES.NOT_RENDERED; - } - - // Pick - - let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; - - if (deferred) { - // Avoid zillions of individual WebGL bufferSubData calls - buffer them to apply in one shot - if (!this._deferredFlagValues) { - this._deferredFlagValues = new Uint8Array(this._numVerts * 4); - } - for (let i = firstFlag, len = (firstFlag + lenFlags); i < len; i += 4) { - this._deferredFlagValues[i + 0] = f0; - this._deferredFlagValues[i + 1] = f1; - this._deferredFlagValues[i + 2] = f2; - this._deferredFlagValues[i + 3] = f3; - } - } else if (this._state.flagsBuf) { - const tempArray = this._scratchMemory.getUInt8Array(lenFlags); - for (let i = 0; i < lenFlags; i += 4) { - tempArray[i + 0] = f0; // x - normal fill - tempArray[i + 1] = f1; // y - emphasis fill - tempArray[i + 2] = f2; // z - edges - tempArray[i + 3] = f3; // w - pick - } - this._state.flagsBuf.setData(tempArray, firstFlag, lenFlags); - } + /** + * Sets the {@link CameraPath} animated by this CameraPathAnimation. + * + @param {CameraPath} value The new CameraPath. + */ + set cameraPath(value) { + this._cameraPath = value; } - _setDeferredFlags() { - if (this._deferredFlagValues) { - this._state.flagsBuf.setData(this._deferredFlagValues); - this._deferredFlagValues = null; - } + /** + * Gets the {@link CameraPath} animated by this CameraPathAnimation. + * + @returns {CameraPath} The CameraPath. + */ + get cameraPath() { + return this._cameraPath; } - _setFlags2(portionId, flags, deferred = false) { - - if (!this._finalized) { - throw "Not finalized"; - } - - const portionsIdx = portionId; - const portion = this._portions[portionsIdx]; - const vertexBase = portion.vertsBase; - const numVerts = portion.numVerts; - const firstFlag = vertexBase * 4; - const lenFlags = numVerts * 4; - const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; - - if (deferred) { - if (!this._setDeferredFlag2Values) { - this._setDeferredFlag2Values = new Uint8Array(this._numVerts * 4); - } - for (let i = firstFlag, len = (firstFlag + lenFlags); i < len; i += 4) { - this._setDeferredFlag2Values[i] = clippable; - } - } else if (this._state.flags2Buf) { - const tempArray = this._scratchMemory.getUInt8Array(lenFlags); - for (let i = 0; i < lenFlags; i += 4) { - tempArray[i + 0] = clippable; - } - this._state.flags2Buf.setData(tempArray, firstFlag, lenFlags); - } + /** + * Sets the rate at which the CameraPathAnimation animates the {@link Camera} along the {@link CameraPath}. + * + * @param {Number} value The amount of progress per second. + */ + set rate(value) { + this._playingRate = value; } - _setDeferredFlags2() { - if (this._setDeferredFlag2Values) { - this._state.flags2Buf.setData(this._setDeferredFlag2Values); - this._setDeferredFlag2Values = null; - } + /** + * Gets the rate at which the CameraPathAnimation animates the {@link Camera} along the {@link CameraPath}. + * + * @returns {*|number} The current playing rate. + */ + get rate() { + return this._playingRate; } - setOffset(portionId, offset) { - if (!this._finalized) { - throw "Not finalized"; - } - if (!this.model.scene.entityOffsetsEnabled) { - this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled + /** + * Begins animating the {@link Camera} along CameraPathAnimation's {@link CameraPath} from the beginning. + */ + play() { + if (!this._cameraPath) { return; } - const portionsIdx = portionId; - const portion = this._portions[portionsIdx]; - const vertexBase = portion.vertsBase; - const numVerts = portion.numVerts; - const firstOffset = vertexBase * 3; - const lenOffsets = numVerts * 3; - const tempArray = this._scratchMemory.getFloat32Array(lenOffsets); - const x = offset[0]; - const y = offset[1]; - const z = offset[2]; - for (let i = 0; i < lenOffsets; i += 3) { - tempArray[i + 0] = x; - tempArray[i + 1] = y; - tempArray[i + 2] = z; - } - if (this._state.offsetsBuf) { - this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets); - } - if (this.model.scene.pickSurfacePrecisionEnabled) { - portion.offset[0] = offset[0]; - portion.offset[1] = offset[1]; - portion.offset[2] = offset[2]; - } + this._lastTime = null; + this.state = CameraPathAnimation.PLAYING; } - // ---------------------- COLOR RENDERING ----------------------------------- - - drawColorOpaque(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + /** + * Begins animating the {@link Camera} along CameraPathAnimation's {@link CameraPath} from the given time. + * + * @param {Number} t Time instant. + */ + playToT(t) { + const cameraPath = this._cameraPath; + if (!cameraPath) { return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (frameCtx.withSAO && this.model.saoEnabled) { - if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { - if (this._batchingRenderers.pbrRendererWithSAO) { - this._batchingRenderers.pbrRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { - if (this._batchingRenderers.colorTextureRendererWithSAO) { - this._batchingRenderers.colorTextureRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (this._state.normalsBuf) { - if (this._batchingRenderers.colorRendererWithSAO) { - this._batchingRenderers.colorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else { - if (this._batchingRenderers.flatColorRendererWithSAO) { - this._batchingRenderers.flatColorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } - } else { - if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { - if (this._batchingRenderers.pbrRenderer) { - this._batchingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { - if (this._batchingRenderers.colorTextureRenderer) { - this._batchingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (this._state.normalsBuf) { - if (this._batchingRenderers.colorRenderer) { - this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else { - if (this._batchingRenderers.flatColorRenderer) { - this._batchingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } - } - } - - _updateBackfaceCull(renderFlags, frameCtx) { - const backfaces = this.model.backfaces || (!this.solid) || renderFlags.sectioned; - if (frameCtx.backfaces !== backfaces) { - const gl = frameCtx.gl; - if (backfaces) { - gl.disable(gl.CULL_FACE); - } else { - gl.enable(gl.CULL_FACE); - } - frameCtx.backfaces = backfaces; - } + this._playingFromT = this._t; + this._playingToT = t; + this._playingDir = (this._playingToT - this._playingFromT) < 0 ? -1 : 1; + this._lastTime = null; + this.state = CameraPathAnimation.PLAYING_TO; } - drawColorTransparent(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { + /** + * Animates the {@link Camera} along CameraPathAnimation's {@link CameraPath} to the given frame. + * + * @param {Number} frameIdx Index of the frame to play to. + */ + playToFrame(frameIdx) { + const cameraPath = this._cameraPath; + if (!cameraPath) { return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { - if (this._batchingRenderers.pbrRenderer) { - this._batchingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { - if (this._batchingRenderers.colorTextureRenderer) { - this._batchingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } else if (this._state.normalsBuf) { - if (this._batchingRenderers.colorRenderer) { - this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } else { - if (this._batchingRenderers.flatColorRenderer) { - this._batchingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } - } - - // ---------------------- RENDERING SAO POST EFFECT TARGETS -------------- - - drawDepth(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + const frame = cameraPath.frames[frameIdx]; + if (!frame) { + this.error("playToFrame - frame index out of range: " + frameIdx); return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.depthRenderer) { - this._batchingRenderers.depthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses depth (eg SAO) does not apply to transparent objects - } + this.playToT(frame.t); } - drawNormals(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + /** + * Flies the {@link Camera} directly to the given frame on the CameraPathAnimation's {@link CameraPath}. + * + * @param {Number} frameIdx Index of the frame to play to. + * @param {Function} [ok] Callback to fire when playing is complete. + */ + flyToFrame(frameIdx, ok) { + const cameraPath = this._cameraPath; + if (!cameraPath) { return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.normalsRenderer) { - this._batchingRenderers.normalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses normals (eg SAO) does not apply to transparent objects - } - } - - // ---------------------- SILHOUETTE RENDERING ----------------------------------- - - drawSilhouetteXRayed(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + const frame = cameraPath.frames[frameIdx]; + if (!frame) { + this.error("flyToFrame - frame index out of range: " + frameIdx); return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.silhouetteRenderer) { - this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); - } + this.state = CameraPathAnimation.SCRUBBING; + this._cameraFlightAnimation.flyTo(frame, ok); } - drawSilhouetteHighlighted(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + /** + * Scrubs the {@link Camera} to the given time on the CameraPathAnimation's {@link CameraPath}. + * + * @param {Number} t Time instant. + */ + scrubToT(t) { + const cameraPath = this._cameraPath; + if (!cameraPath) { return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.silhouetteRenderer) { - this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); - } - } - - drawSilhouetteSelected(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { + const camera = this.scene.camera; + if (!camera) { return; } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.silhouetteRenderer) { - this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); - } + this._t = t; + cameraPath.loadFrame(this._t); + this.state = CameraPathAnimation.SCRUBBING; } - // ---------------------- EDGES RENDERING ----------------------------------- - - drawEdgesColorOpaque(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) { + /** + * Scrubs the {@link Camera} to the given frame on the CameraPathAnimation's {@link CameraPath}. + * + * @param {Number} frameIdx Index of the frame to scrub to. + */ + scrubToFrame(frameIdx) { + const cameraPath = this._cameraPath; + if (!cameraPath) { return; } - if (this._batchingRenderers.edgesColorRenderer) { - this._batchingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_OPAQUE); - } - } - - drawEdgesColorTransparent(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0 || this._numTransparentLayerPortions === 0) { + const camera = this.scene.camera; + if (!camera) { return; } - if (this._batchingRenderers.edgesColorRenderer) { - this._batchingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_TRANSPARENT); - } - } - - drawEdgesHighlighted(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + const frame = cameraPath.frames[frameIdx]; + if (!frame) { + this.error("playToFrame - frame index out of range: " + frameIdx); return; } - if (this._batchingRenderers.edgesRenderer) { - this._batchingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_HIGHLIGHTED); - } + cameraPath.loadFrame(this._t); + this.state = CameraPathAnimation.SCRUBBING; } - drawEdgesSelected(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { - return; - } - if (this._batchingRenderers.edgesRenderer) { - this._batchingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_SELECTED); - } + /** + * Stops playing this CameraPathAnimation. + */ + stop() { + this.state = CameraPathAnimation.SCRUBBING; + this.fire("stopped"); } - drawEdgesXRayed(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { - return; - } - if (this._batchingRenderers.edgesRenderer) { - this._batchingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_XRAYED); - } + destroy() { + super.destroy(); + this.scene.off(this._tick); } +} - // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- +CameraPathAnimation.STOPPED = 0; +CameraPathAnimation.SCRUBBING = 1; +CameraPathAnimation.PLAYING = 2; +CameraPathAnimation.PLAYING_TO = 3; - drawOcclusion(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.occlusionRenderer) { - this._batchingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } +const tempVec3$2 = math.vec3(); +const tempVec3b$8 = math.vec3(); +math.vec3(); +const zeroVec$1 = math.vec3([0, -1, 0]); +const tempQuat = math.vec4([0, 0, 0, 1]); - // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- +/** + * @desc A plane-shaped 3D object containing a bitmap image. + * + * Use ````ImagePlane```` to embed bitmap images in your scenes. + * + * As shown in the examples below, ````ImagePlane```` is useful for creating ground planes from satellite maps and embedding 2D plan + * view images in cross-section slicing planes. + * + * # Example 1: Create a ground plane from a satellite image + * + * In our first example, we'll load the Schependomlaan model, then use + * an ````ImagePlane```` to create a ground plane, which will contain + * a satellite image sourced from Google Maps. + * + * + * + * [](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_groundPlane) + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_groundPlane)] + * + * ````javascript + * import {Viewer, ImagePlane, XKTLoaderPlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [-8.31, 42.21, 54.30]; + * viewer.camera.look = [-0.86, 15.40, 14.90]; + * viewer.camera.up = [0.10, 0.83, -0.54]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * xktLoader.load({ // Load IFC model + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true, + * + * rotation: [0, 22, 0], // Rotate, position and scale the model to align it correctly with the ImagePlane + * position: [-8, 0, 15], + * scale: [1.1, 1.1, 1.1] + * }); + * + * new ImagePlane(viewer.scene, { + * src: "./images/schependomlaanSatMap.png", // Google satellite image; accepted file types are PNG and JPEG + * visible: true, // Show the ImagePlane + * gridVisible: true, // Show the grid - grid is only visible when ImagePlane is also visible + * size: 190, // Size of ImagePlane's longest edge + * position: [0, -1, 0], // World-space position of ImagePlane's center + * rotation: [0, 0, 0], // Euler angles for X, Y and Z + * opacity: 1.0, // Fully opaque + * collidable: false, // ImagePlane does not contribute to Scene boundary + * clippable: true, // ImagePlane can be clipped by SectionPlanes + * pickable: true // Allow the ground plane to be picked + * }); + * ```` + *
+ * + * # Example 2: Embed an image in a cross-section plane + * + * In our second example, we'll load the Schependomlaan model again, then slice it in half with + * a {@link SectionPlanesPlugin}, then use an ````ImagePlane```` to embed a 2D plan view image in the slicing plane. + * + * + * + * [](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_imageInSectionPlane) + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_imageInSectionPlane)] + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, SectionPlanesPlugin, ImagePlane} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [-9.11, 20.01, 5.13]; + * viewer.camera.look = [9.07, 0.77, -9.78]; + * viewer.camera.up = [0.47, 0.76, -0.38]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const sectionPlanes = new SectionPlanesPlugin(viewer, { + * overviewVisible: false + * }); + * + * model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/schependomlaan/schependomlaan.xkt", + * metaModelSrc: "./metaModels/schependomlaan/metaModel.json", + * edges: true, + * }); + * + * const sectionPlane = sectionPlanes.createSectionPlane({ + * id: "mySectionPlane", + * pos: [10.95, 1.95, -10.35], + * dir: [0.0, -1.0, 0.0] + * }); + * + * const imagePlane = new ImagePlane(viewer.scene, { + * src: "./images/schependomlaanPlanView.png", // Plan view image; accepted file types are PNG and JPEG + * visible: true, + * gridVisible: true, + * size: 23.95, + * position: sectionPlane.pos, + * dir: sectionPlane.dir, + * collidable: false, + * opacity: 0.75, + * clippable: false, // Don't allow ImagePlane to be clipped by the SectionPlane + * pickable: false // Don't allow ImagePlane to be picked + * }); + * ```` + */ +class ImagePlane extends Component { - drawShadow(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.shadowRenderer) { - this._batchingRenderers.shadowRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this ````ImagePlane```` as well. + * @param {*} [cfg] ````ImagePlane```` configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Boolean} [cfg.visible=true] Indicates whether or not this ````ImagePlane```` is visible. + * @param {Boolean} [cfg.gridVisible=true] Indicates whether or not the grid is visible. Grid is only visible when ````ImagePlane```` is also visible. + * @param {Number[]} [cfg.position=[0,0,0]] World-space position of the ````ImagePlane````. + * @param {Number[]} [cfg.size=1] World-space size of the longest edge of the ````ImagePlane````. Note that + * ````ImagePlane```` sets its aspect ratio to match its image. If we set a value of ````1000````, and the image + * has size ````400x300````, then the ````ImagePlane```` will then have size ````1000 x 750````. + * @param {Number[]} [cfg.rotation=[0,0,0]] Local rotation of the ````ImagePlane````, as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Modelling transform matrix for the ````ImagePlane````. Overrides the ````position````, ````size```, ````rotation```` and ````dir```` parameters. + * @param {Boolean} [cfg.collidable=true] Indicates if the ````ImagePlane```` is initially included in boundary calculations. + * @param {Boolean} [cfg.clippable=true] Indicates if the ````ImagePlane```` is initially clippable. + * @param {Boolean} [cfg.pickable=true] Indicates if the ````ImagePlane```` is initially pickable. + * @param {Number} [cfg.opacity=1.0] ````ImagePlane````'s initial opacity factor, multiplies by the rendered fragment alpha. + * @param {String} [cfg.src] URL of image. Accepted file types are PNG and JPEG. + * @param {HTMLImageElement} [cfg.image] An ````HTMLImageElement```` to source the image from. Overrides ````src````. + */ + constructor(owner, cfg = {}) { - //---- PICKING ---------------------------------------------------------------------------------------------------- + super(owner, cfg); - drawPickMesh(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.pickMeshRenderer) { - this._batchingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); - } - } + this._src = null; + this._image = null; + this._pos = math.vec3(); + this._origin = math.vec3(); + this._rtcPos = math.vec3(); + this._dir = math.vec3(); + this._size = 1.0; + this._imageSize = math.vec2(); - drawPickDepths(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._batchingRenderers.pickDepthRenderer) { - this._batchingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); - } - } + this._texture = new Texture(this); - drawPickNormals(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); + this._plane = new Mesh(this, { - //////////////////////////////////////////////////////////////////////////////////////////////////// - // TODO - // if (this._state.normalsBuf) { - // if (this._batchingRenderers.pickNormalsRenderer) { - // this._batchingRenderers.pickNormalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); - // } - //////////////////////////////////////////////////////////////////////////////////////////////////// - // } else { - if (this._batchingRenderers.pickNormalsFlatRenderer) { - this._batchingRenderers.pickNormalsFlatRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); - } - // } - } + geometry: new ReadableGeometry(this, buildPlaneGeometry({ + center: [0, 0, 0], + xSize: 1, + zSize: 1, + xSegments: 10, + zSegments: 10 + })), - //------------------------------------------------------------------------------------------------ + material: new PhongMaterial(this, { + diffuse: [0, 0, 0], + ambient: [0, 0, 0], + specular: [0, 0, 0], + diffuseMap: this._texture, + emissiveMap: this._texture, + backfaces: true + }), + clippable: cfg.clippable + }); - precisionRayPickSurface(portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldNormal) { + this._grid = new Mesh(this, { + geometry: new ReadableGeometry(this, buildGridGeometry({ + size: 1, + divisions: 10 + })), + material: new PhongMaterial(this, { + diffuse: [0.0, 0.0, 0.0], + ambient: [0.0, 0.0, 0.0], + emissive: [0.2, 0.8, 0.2] + }), + position: [0, 0.001, 0.0], + clippable: cfg.clippable + }); - if (!this.model.scene.pickSurfacePrecisionEnabled) { - return false; - } + this._node = new Node$1(this, { + rotation: [0, 0, 0], + position: [0, 0, 0], + scale: [1, 1, 1], + clippable: false, + children: [ + this._plane, + this._grid + ] + }); - const state = this._state; - const portion = this._portions[portionId]; + this._gridVisible = false; - if (!portion) { - this.model.error("portion not found: " + portionId); - return false; + this.visible = true; + this.gridVisible = cfg.gridVisible; + this.position = cfg.position; + this.rotation = cfg.rotation; + this.dir = cfg.dir; + this.size = cfg.size; + this.collidable = cfg.collidable; + this.clippable = cfg.clippable; + this.pickable = cfg.pickable; + this.opacity = cfg.opacity; + + if (cfg.image) { + this.image = cfg.image; + } else { + this.src = cfg.src; } + } - const positions = portion.quantizedPositions; - const indices = portion.indices; - const origin = state.origin; - const offset = portion.offset; + /** + * Sets if this ````ImagePlane```` is visible or not. + * + * Default value is ````true````. + * + * @param {Boolean} visible Set ````true```` to make this ````ImagePlane```` visible. + */ + set visible(visible) { + this._plane.visible = visible; + this._grid.visible = (this._gridVisible && visible); + } + + /** + * Gets if this ````ImagePlane```` is visible or not. + * + * Default value is ````true````. + * + * @returns {Boolean} Returns ````true```` if visible. + */ + get visible() { + return this._plane.visible; + } - const rtcRayOrigin = tempVec3a$H; - const rtcRayDir = tempVec3b$8; + /** + * Sets if this ````ImagePlane````'s grid is visible or not. + * + * Default value is ````false````. + * + * Grid is only visible when ````ImagePlane```` is also visible. + * + * @param {Boolean} visible Set ````true```` to make this ````ImagePlane````'s grid visible. + */ + set gridVisible(visible) { + visible = (visible !== false); + this._gridVisible = visible; + this._grid.visible = (this._gridVisible && this.visible); + } - rtcRayOrigin.set(origin ? math.subVec3(worldRayOrigin, origin, tempVec3c$5) : worldRayOrigin); // World -> RTC - rtcRayDir.set(worldRayDir); + /** + * Gets if this ````ImagePlane````'s grid is visible or not. + * + * Default value is ````false````. + * + * @returns {Boolean} Returns ````true```` if visible. + */ + get gridVisible() { + return this._gridVisible; + } - if (offset) { - math.subVec3(rtcRayOrigin, offset); + /** + * Sets an ````HTMLImageElement```` to source the image from. + * + * Sets {@link Texture#src} null. + * + * @type {HTMLImageElement} + */ + set image(image) { + this._image = image; + if (this._image) { + this._imageSize[0] = image.width; + this._imageSize[1] = image.height; + this._updatePlaneSizeFromImage(); + this._src = null; + this._texture.image = this._image; } + } - math.transformRay(this.model.worldNormalMatrix, rtcRayOrigin, rtcRayDir, rtcRayOrigin, rtcRayDir); // RTC -> local + /** + * Gets the ````HTMLImageElement```` the ````ImagePlane````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {HTMLImageElement} + */ + get image() { + return this._image; + } - const a = tempVec3d$2; - const b = tempVec3e$1; - const c = tempVec3f$1; + /** + * Sets an image file path that the ````ImagePlane````'s image is sourced from. + * + * Accepted file types are PNG and JPEG. + * + * Sets {@link Texture#image} null. + * + * @type {String} + */ + set src(src) { + this._src = src; + if (this._src) { + this._image = null; + const image = new Image(); + image.onload = () => { + this._texture.image = image; + this._imageSize[0] = image.width; + this._imageSize[1] = image.height; + this._updatePlaneSizeFromImage(); + }; + image.src = this._src; + } + } - let gotIntersect = false; - let closestDist = 0; - const closestIntersectPos = tempVec3g$1; + /** + * Gets the image file path that the ````ImagePlane````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {String} + */ + get src() { + return this._src; + } - for (let i = 0, len = indices.length; i < len; i += 3) { + /** + * Sets the World-space position of this ````ImagePlane````. + * + * Default value is ````[0, 0, 0]````. + * + * @param {Number[]} value New position. + */ + set position(value) { + this._pos.set(value || [0, 0, 0]); + worldToRTCPos(this._pos, this._origin, this._rtcPos); + this._node.origin = this._origin; + this._node.position = this._rtcPos; + } - const ia = indices[i] * 3; - const ib = indices[i + 1] * 3; - const ic = indices[i + 2] * 3; + /** + * Gets the World-space position of this ````ImagePlane````. + * + * Default value is ````[0, 0, 0]````. + * + * @returns {Number[]} Current position. + */ + get position() { + return this._pos; + } - a[0] = positions[ia]; - a[1] = positions[ia + 1]; - a[2] = positions[ia + 2]; + /** + * Sets the direction of this ````ImagePlane```` using Euler angles. + * + * Default value is ````[0, 0, 0]````. + * + * @param {Number[]} value Euler angles for ````X````, ````Y```` and ````Z```` axis rotations. + */ + set rotation(value) { + this._node.rotation = value; + } - b[0] = positions[ib]; - b[1] = positions[ib + 1]; - b[2] = positions[ib + 2]; + /** + * Gets the direction of this ````ImagePlane```` as Euler angles. + * + * @returns {Number[]} Euler angles for ````X````, ````Y```` and ````Z```` axis rotations. + */ + get rotation() { + return this._node.rotation; + } - c[0] = positions[ic]; - c[1] = positions[ic + 1]; - c[2] = positions[ic + 2]; + /** + * Sets the World-space size of the longest edge of the ````ImagePlane````. + * + * Note that ````ImagePlane```` sets its aspect ratio to match its image. If we set a value of ````1000````, and + * the image has size ````400x300````, then the ````ImagePlane```` will then have size ````1000 x 750````. + * + * Default value is ````1.0````. + * + * @param {Number} size New World-space size of the ````ImagePlane````. + */ + set size(size) { + this._size = (size === undefined || size === null) ? 1.0 : size; + if (this._image) { + this._updatePlaneSizeFromImage(); + } + } - math.decompressPosition(a, state.positionsDecodeMatrix); - math.decompressPosition(b, state.positionsDecodeMatrix); - math.decompressPosition(c, state.positionsDecodeMatrix); + /** + * Gets the World-space size of the longest edge of the ````ImagePlane````. + * + * Returns {Number} World-space size of the ````ImagePlane````. + */ + get size() { + return this._size; + } - if (math.rayTriangleIntersect(rtcRayOrigin, rtcRayDir, a, b, c, closestIntersectPos)) { + /** + * Sets the direction of this ````ImagePlane```` as a direction vector. + * + * Default value is ````[0, 0, -1]````. + * + * @param {Number[]} dir New direction vector. + */ + set dir(dir) { - math.transformPoint3(this.model.worldMatrix, closestIntersectPos, closestIntersectPos); + this._dir.set(dir || [0, 0, -1]); - if (offset) { - math.addVec3(closestIntersectPos, offset); - } + if (dir) { - if (origin) { - math.addVec3(closestIntersectPos, origin); - } + const origin = this.scene.center; + const negDir = [-this._dir[0], -this._dir[1], -this._dir[2]]; - const dist = Math.abs(math.lenVec3(math.subVec3(closestIntersectPos, worldRayOrigin, []))); + math.subVec3(origin, this.position, tempVec3$2); - if (!gotIntersect || dist > closestDist) { - closestDist = dist; - worldSurfacePos.set(closestIntersectPos); - if (worldNormal) { // Not that wasteful to eagerly compute - unlikely to hit >2 surfaces on most geometry - math.triangleNormal(a, b, c, worldNormal); - } - gotIntersect = true; - } - } - } + const dist = -math.dotVec3(negDir, tempVec3$2); - if (gotIntersect && worldNormal) { - math.transformVec3(this.model.worldNormalMatrix, worldNormal, worldNormal); - math.normalizeVec3(worldNormal); - } + math.normalizeVec3(negDir); + math.mulVec3Scalar(negDir, dist, tempVec3b$8); + math.vec3PairToQuaternion(zeroVec$1, dir, tempQuat); - return gotIntersect; + this._node.quaternion = tempQuat; + } } - // --------- - - destroy() { - const state = this._state; - if (state.positionsBuf) { - state.positionsBuf.destroy(); - state.positionsBuf = null; - } - if (state.offsetsBuf) { - state.offsetsBuf.destroy(); - state.offsetsBuf = null; - } - if (state.normalsBuf) { - state.normalsBuf.destroy(); - state.normalsBuf = null; - } - if (state.colorsBuf) { - state.colorsBuf.destroy(); - state.colorsBuf = null; - } - if (state.metallicRoughnessBuf) { - state.metallicRoughnessBuf.destroy(); - state.metallicRoughnessBuf = null; - } - if (state.flagsBuf) { - state.flagsBuf.destroy(); - state.flagsBuf = null; - } - if (state.flags2Buf) { - state.flags2Buf.destroy(); - state.flags2Buf = null; - } - if (state.pickColorsBuf) { - state.pickColorsBuf.destroy(); - state.pickColorsBuf = null; - } - if (state.indicesBuf) { - state.indicesBuf.destroy(); - state.indicessBuf = null; - } - if (state.edgeIndicesBuf) { - state.edgeIndicesBuf.destroy(); - state.edgeIndicessBuf = null; - } - state.destroy(); + /** + * Gets the direction of this ````ImagePlane```` as a direction vector. + * + * @returns {Number[]} value Current direction. + */ + get dir() { + return this._dir; } -} -const tempVec4$3 = math.vec4(); -const tempVec3a$G = math.vec3(); + /** + * Sets if this ````ImagePlane```` is included in boundary calculations. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set collidable(value) { + this._node.collidable = (value !== false); + } -/** - * @private - */ -class TrianglesInstancingColorRenderer { + /** + * Gets if this ````ImagePlane```` is included in boundary calculations. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get collidable() { + return this._node.collidable; + } - constructor(scene, withSAO) { - this._scene = scene; - this._withSAO = withSAO; - this._hash = this._getHash(); - this._allocate(); + /** + * Sets if this ````ImagePlane```` is clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set clippable(value) { + this._node.clippable = (value !== false); } - getValid() { - return this._hash === this._getHash(); - }; + /** + * Gets if this ````ImagePlane```` is clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get clippable() { + return this._node.clippable; + } - _getHash() { - const scene = this._scene; - return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); + /** + * Sets if this ````ImagePlane```` is pickable. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set pickable(value) { + this._node.pickable = (value !== false); } - drawLayer(frameCtx, instancingLayer, renderPass) { + /** + * Gets if this ````ImagePlane```` is pickable. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get pickable() { + return this._node.pickable; + } - const model = instancingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; - - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } - } - - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); - } - - gl.uniform1i(this._uRenderPass, renderPass); - - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); - - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); - - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$G); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); - this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); - this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aNormal.bindArrayBuffer(geometry.normalsBuf); - - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - frameCtx.drawElements++; - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } - - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + /** + * Sets the opacity factor for this ````ImagePlane````. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + set opacity(opacity) { + this._node.opacity = opacity; } - _allocate() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; + /** + * Gets this ````ImagePlane````'s opacity factor. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + get opacity() { + return this._node.opacity; + } - this._program = new Program(gl, this._buildShader()); + /** + * @destroy + */ + destroy() { + super.destroy(); + } - if (this._program.errors) { - this.errors = this._program.errors; - return; + _updatePlaneSizeFromImage() { + const size = this._size; + const width = this._imageSize[0]; + const height = this._imageSize[1]; + const aspect = height / width; + if (width > height) { + this._node.scale = [size, 1.0, size * aspect]; + } else { + this._node.scale = [size * aspect, 1.0, size]; } + } +} - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; - - const lights = lightsState.lights; - let light; +/** + * A positional light source that originates from a single point and spreads outward in all directions, with optional attenuation over distance. + * + * * Has a position in {@link PointLight#pos}, but no direction. + * * Defined in either *World* or *View* coordinate space. When in World-space, {@link PointLight#pos} is relative to + * the World coordinate system, and will appear to move as the {@link Camera} moves. When in View-space, + * {@link PointLight#pos} is relative to the View coordinate system, and will behave as if fixed to the viewer's head. + * * Has {@link PointLight#constantAttenuation}, {@link PointLight#linearAttenuation} and {@link PointLight#quadraticAttenuation} + * factors, which indicate how intensity attenuates over distance. + * * {@link AmbientLight}s, {@link PointLight}s and {@link PointLight}s are registered by their {@link Component#id} on {@link Scene#lights}. + * + * ## Usage + * + * In the example below we'll replace the {@link Scene}'s default light sources with three World-space PointLights. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#lights_PointLight_world)] + * + * ````javascript + * import {Viewer, Mesh, buildSphereGeometry, buildPlaneGeometry, + * ReadableGeometry, PhongMaterial, Texture, PointLight} from "xeokit-sdk.es.js"; + * + * // Create a Viewer and arrange the camera + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [0, 0, 5]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; + * + * // Replace the Scene's default lights with three custom world-space PointLights + * + * viewer.scene.clearLights(); + * + * new PointLight(viewer.scene,{ + * id: "keyLight", + * pos: [-80, 60, 80], + * color: [1.0, 0.3, 0.3], + * intensity: 1.0, + * space: "world" + * }); + * + * new PointLight(viewer.scene,{ + * id: "fillLight", + * pos: [80, 40, 40], + * color: [0.3, 1.0, 0.3], + * intensity: 1.0, + * space: "world" + * }); + * + * new PointLight(viewer.scene,{ + * id: "rimLight", + * pos: [-20, 80, -80], + * color: [0.6, 0.6, 0.6], + * intensity: 1.0, + * space: "world" + * }); + * + * // Create a sphere and ground plane + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ + * radius: 1.3 + * }), + * material: new PhongMaterial(viewer.scene, { + * diffuse: [0.7, 0.7, 0.7], + * specular: [1.0, 1.0, 1.0], + * emissive: [0, 0, 0], + * alpha: 1.0, + * ambient: [1, 1, 0], + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }) + * }) + * }); + * + * new Mesh(viewer.scene, { + * geometry: buildPlaneGeometry(ReadableGeometry, viewer.scene, { + * xSize: 30, + * zSize: 30 + * }), + * material: new PhongMaterial(viewer.scene, { + * diffuseMap: new Texture(viewer.scene, { + * src: "textures/diffuse/uvGrid2.jpg" + * }), + * backfaces: true + * }), + * position: [0, -2.1, 0] + * }); + * ```` + */ +class PointLight extends Light { - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - } - } + /** + @private + */ + get type() { + return "PointLight"; + } - this._uSectionPlanes = []; + /** + * @param {Component} owner Owner component. When destroyed, the owner will destroy this PointLight as well. + * @param {*} [cfg] The PointLight configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} [cfg.pos=[ 1.0, 1.0, 1.0 ]] Position, in either World or View space, depending on the value of the **space** parameter. + * @param {Number[]} [cfg.color=[0.7, 0.7, 0.8 ]] Color of this PointLight. + * @param {Number} [cfg.intensity=1.0] Intensity of this PointLight, as a factor in range ````[0..1]````. + * @param {Number} [cfg.constantAttenuation=0] Constant attenuation factor. + * @param {Number} [cfg.linearAttenuation=0] Linear attenuation factor. + * @param {Number} [cfg.quadraticAttenuation=0]Quadratic attenuation factor. + * @param {String} [cfg.space="view"]The coordinate system this PointLight is defined in - "view" or "world". + * @param {Boolean} [cfg.castsShadow=false] Flag which indicates if this PointLight casts a castsShadow. + */ + constructor(owner, cfg = {}) { - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + super(owner, cfg); - this._aPosition = program.getAttribute("position"); - this._aNormal = program.getAttribute("normal"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._aOffset = program.getAttribute("offset"); + const self = this; - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + this._shadowRenderBuf = null; + this._shadowViewMatrix = null; + this._shadowProjMatrix = null; + this._shadowViewMatrixDirty = true; + this._shadowProjMatrixDirty = true; - this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); - this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); - this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); + const camera = this.scene.camera; + const canvas = this.scene.canvas; - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); + this._onCameraViewMatrix = camera.on("viewMatrix", () => { + this._shadowViewMatrixDirty = true; + }); - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } - } + this._onCameraProjMatrix = camera.on("projMatrix", () => { + this._shadowProjMatrixDirty = true; + }); - _bindProgram(frameCtx) { + this._onCanvasBoundary = canvas.on("boundary", () => { + this._shadowProjMatrixDirty = true; + }); - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; - const lights = lightsState.lights; - const project = scene.camera.project; + this._state = new RenderState({ - this._program.bind(); + type: "point", + pos: math.vec3([1.0, 1.0, 1.0]), + color: math.vec3([0.7, 0.7, 0.8]), + intensity: 1.0, attenuation: [0.0, 0.0, 0.0], + space: cfg.space || "view", + castsShadow: false, - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + getShadowViewMatrix: () => { + if (self._shadowViewMatrixDirty) { + if (!self._shadowViewMatrix) { + self._shadowViewMatrix = math.identityMat4(); + } + const eye = self._state.pos; + const look = camera.look; + const up = camera.up; + math.lookAtMat4v(eye, look, up, self._shadowViewMatrix); + self._shadowViewMatrixDirty = false; + } + return self._shadowViewMatrix; + }, - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); - } + getShadowProjMatrix: () => { + if (self._shadowProjMatrixDirty) { // TODO: Set when canvas resizes + if (!self._shadowProjMatrix) { + self._shadowProjMatrix = math.identityMat4(); + } + const canvas = self.scene.canvas.canvas; + math.perspectiveMat4(70 * (Math.PI / 180.0), canvas.clientWidth / canvas.clientHeight, 0.1, 500.0, self._shadowProjMatrix); + self._shadowProjMatrixDirty = false; + } + return self._shadowProjMatrix; + }, - for (let i = 0, len = lights.length; i < len; i++) { - const light = lights[i]; - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + getShadowRenderBuf: () => { + if (!self._shadowRenderBuf) { + self._shadowRenderBuf = new RenderBuffer(self.scene.canvas.canvas, self.scene.canvas.gl, {size: [1024, 1024]}); // Super old mobile devices have a limit of 1024x1024 textures } + return self._shadowRenderBuf; } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } - } + }); - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$3[0] = viewportWidth; - tempVec4$3[1] = viewportHeight; - tempVec4$3[2] = sao.blendCutoff; - tempVec4$3[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$3); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); - } - } + this.pos = cfg.pos; + this.color = cfg.color; + this.intensity = cfg.intensity; + this.constantAttenuation = cfg.constantAttenuation; + this.linearAttenuation = cfg.linearAttenuation; + this.quadraticAttenuation = cfg.quadraticAttenuation; + this.castsShadow = cfg.castsShadow; - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + this.scene._lightCreated(this); } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + /** + * Sets the position of this PointLight. + * + * This will be either World- or View-space, depending on the value of {@link PointLight#space}. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * + * @param {Number[]} pos The position. + */ + set pos(pos) { + this._state.pos.set(pos || [1.0, 1.0, 1.0]); + this._shadowViewMatrixDirty = true; + this.glRedraw(); } - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - let i; - let len; - let light; - const src = []; - src.push("#version 300 es"); - src.push("// Instancing geometry drawing vertex shader"); + /** + * Gets the position of this PointLight. + * + * This will be either World- or View-space, depending on the value of {@link PointLight#space}. + * + * Default value is ````[1.0, 1.0, 1.0]````. + * + * @returns {Number[]} The position. + */ + get pos() { + return this._state.pos; + } - src.push("uniform int renderPass;"); + /** + * Sets the RGB color of this PointLight. + * + * Default value is ````[0.7, 0.7, 0.8]````. + * + * @param {Number[]} color The PointLight's RGB color. + */ + set color(color) { + this._state.color.set(color || [0.7, 0.7, 0.8]); + this.glRedraw(); + } - src.push("in vec3 position;"); - src.push("in vec2 normal;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + /** + * Gets the RGB color of this PointLight. + * + * Default value is ````[0.7, 0.7, 0.8]````. + * + * @returns {Number[]} The PointLight's RGB color. + */ + get color() { + return this._state.color; + } - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } + /** + * Sets the intensity of this PointLight. + * + * Default intensity is ````1.0```` for maximum intensity. + * + * @param {Number} intensity The PointLight's intensity + */ + set intensity(intensity) { + intensity = intensity !== undefined ? intensity : 1.0; + this._state.intensity = intensity; + this.glRedraw(); + } - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); + /** + * Gets the intensity of this PointLight. + * + * Default value is ````1.0```` for maximum intensity. + * + * @returns {Number} The PointLight's intensity. + */ + get intensity() { + return this._state.intensity; + } - src.push("in vec4 modelNormalMatrixCol0;"); - src.push("in vec4 modelNormalMatrixCol1;"); - src.push("in vec4 modelNormalMatrixCol2;"); + /** + * Sets the constant attenuation factor for this PointLight. + * + * Default value is ````0````. + * + * @param {Number} value The constant attenuation factor. + */ + set constantAttenuation(value) { + this._state.attenuation[0] = value || 0.0; + this.glRedraw(); + } - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); + /** + * Gets the constant attenuation factor for this PointLight. + * + * Default value is ````0````. + * + * @returns {Number} The constant attenuation factor. + */ + get constantAttenuation() { + return this._state.attenuation[0]; + } - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } + /** + * Sets the linear attenuation factor for this PointLight. + * + * Default value is ````0````. + * + * @param {Number} value The linear attenuation factor. + */ + set linearAttenuation(value) { + this._state.attenuation[1] = value || 0.0; + this.glRedraw(); + } - src.push("uniform vec4 lightAmbient;"); + /** + * Gets the linear attenuation factor for this PointLight. + * + * Default value is ````0````. + * + * @returns {Number} The linear attenuation factor. + */ + get linearAttenuation() { + return this._state.attenuation[1]; + } - for (i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); - } - } + /** + * Sets the quadratic attenuation factor for this PointLight. + * + * Default value is ````0````. + * + * @param {Number} value The quadratic attenuation factor. + */ + set quadraticAttenuation(value) { + this._state.attenuation[2] = value || 0.0; + this.glRedraw(); + } - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); + /** + * Gets the quadratic attenuation factor for this PointLight. + * + * Default value is ````0````. + * + * @returns {Number} The quadratic attenuation factor. + */ + get quadraticAttenuation() { + return this._state.attenuation[2]; + } - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); + /** + * Sets if this PointLight casts a shadow. + * + * Default value is ````false````. + * + * @param {Boolean} castsShadow Set ````true```` to cast shadows. + */ + set castsShadow(castsShadow) { + castsShadow = !!castsShadow; + if (this._state.castsShadow === castsShadow) { + return; } - src.push("out vec4 vColor;"); + this._state.castsShadow = castsShadow; + this._shadowViewMatrixDirty = true; + this.glRedraw(); + } - src.push("void main(void) {"); + /** + * Gets if this PointLight casts a shadow. + * + * Default value is ````false````. + * + * @returns {Boolean} ````true```` if this PointLight casts shadows. + */ + get castsShadow() { + return this._state.castsShadow; + } - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT + /** + * Destroys this PointLight. + */ + destroy() { - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + const camera = this.scene.camera; + const canvas = this.scene.canvas; + camera.off(this._onCameraViewMatrix); + camera.off(this._onCameraProjMatrix); + canvas.off(this._onCanvasBoundary); - src.push("} else {"); + super.destroy(); - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + this._state.destroy(); + if (this._shadowRenderBuf) { + this._shadowRenderBuf.destroy(); } + this.scene._lightDestroyed(this); + this.glRedraw(); + } +} - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); +function ensureImageSizePowerOfTwo(image) { + if (!isPowerOfTwo(image.width) || !isPowerOfTwo(image.height)) { + const canvas = document.createElement("canvas"); + canvas.width = nextHighestPowerOfTwo(image.width); + canvas.height = nextHighestPowerOfTwo(image.height); + const ctx = canvas.getContext("2d"); + ctx.drawImage(image, + 0, 0, image.width, image.height, + 0, 0, canvas.width, canvas.height); + image = canvas; + } + return image; +} - src.push("vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); - src.push("vec4 worldNormal = worldNormalMatrix * vec4(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2), 0.0);"); - src.push("vec3 viewNormal = normalize(vec4(viewNormalMatrix * worldNormal).xyz);"); +function isPowerOfTwo(x) { + return (x & (x - 1)) === 0; +} - src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); - src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); +function nextHighestPowerOfTwo(x) { + --x; + for (let i = 1; i < 32; i <<= 1) { + x = x | x >> i; + } + return x + 1; +} - src.push("float lambertian = 1.0;"); - for (i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - if (light.type === "dir") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); - } else { - src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else { - continue; - } - src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); - src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); - } +/** + * @desc A cube texture map. + */ +class CubeTexture extends Component { - src.push("vec3 rgb = (vec3(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0));"); - src.push("vColor = vec4((lightAmbient.rgb * lightAmbient.a * rgb) + (reflectedColor * rgb), float(color.a) / 255.0);"); + /** + @private + */ + get type() { + return "CubeTexture"; + } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for this CubeTexture, unique among all components in the parent scene, generated automatically when omitted. + * @param {String[]} [cfg.src=null] Paths to six image files to load into this CubeTexture. + * @param {Boolean} [cfg.flipY=false] Flips this CubeTexture's source data along its vertical axis when true. + * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. + */ + constructor(owner, cfg = {}) { - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } + super(owner, cfg); - src.push("gl_Position = clipPos;"); - src.push("}"); - src.push("}"); - return src; - } + const gl = this.scene.canvas.gl; - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Instancing geometry drawing fragment shader"); + this._state = new RenderState({ + texture: new Texture2D({gl, target: gl.TEXTURE_CUBE_MAP}), + flipY: this._checkFlipY(cfg.minFilter), + encoding: this._checkEncoding(cfg.encoding), + minFilter: LinearMipmapLinearFilter, + magFilter: LinearFilter, + wrapS: ClampToEdgeWrapping, + wrapT: ClampToEdgeWrapping, + mipmaps: true + }); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + this._src = cfg.src; + this._images = []; - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); - } + this._loadSrc(cfg.src); - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); + stats.memory.textures++; + } - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - src.push("}"); - } + _checkFlipY(value) { + return !!value; + } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + _checkEncoding(value) { + value = value || LinearEncoding; + if (value !== LinearEncoding && value !== sRGBEncoding) { + this.error("Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); + value = LinearEncoding; } + return value; + } - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - - if (this._withSAO) { - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" outColor = vec4(vColor.rgb * ambient, 1.0);"); - } else { - src.push(" outColor = vColor;"); + _webglContextRestored() { + this.scene.canvas.gl; + this._state.texture = null; + // if (this._images.length > 0) { + // this._state.texture = new xeokit.renderer.Texture2D(gl, gl.TEXTURE_CUBE_MAP); + // this._state.texture.setImage(this._images, this._state); + // this._state.texture.setProps(this._state); + // } else + if (this._src) { + this._loadSrc(this._src); } - src.push("}"); - return src; } - webglContextRestored() { - this._program = null; + _loadSrc(src) { + const self = this; + const gl = this.scene.canvas.gl; + this._images = []; + let loadFailed = false; + let numLoaded = 0; + for (let i = 0; i < src.length; i++) { + const image = new Image(); + image.onload = (function () { + let _image = image; + const index = i; + return function () { + if (loadFailed) { + return; + } + _image = ensureImageSizePowerOfTwo(_image); + self._images[index] = _image; + numLoaded++; + if (numLoaded === 6) { + let texture = self._state.texture; + if (!texture) { + texture = new Texture2D({gl, target: gl.TEXTURE_CUBE_MAP}); + self._state.texture = texture; + } + texture.setImage(self._images, self._state); + self.fire("loaded", self._src, false); + self.glRedraw(); + } + }; + })(); + image.onerror = function () { + loadFailed = true; + }; + image.src = src[i]; + } } + /** + * Destroys this CubeTexture + * + */ destroy() { - if (this._program) { - this._program.destroy(); + super.destroy(); + if (this._state.texture) { + this._state.texture.destroy(); } - this._program = null; + stats.memory.textures--; + this._state.destroy(); } } -const tempVec4$2 = math.vec4(); -const tempVec3a$F = math.vec3(); - /** - * @private + * @desc A reflection cube map. + * + * ## Usage + * + * ````javascript + * import {Viewer, Mesh, buildSphereGeometry, + * ReadableGeometry, MetallicMaterial, ReflectionMap} from "xeokit-sdk.es.js"; + * + * // Create a Viewer and arrange the camera + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [0, 0, 5]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; + * + * new ReflectionMap(viewer.scene, { + * src: [ + * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PX.png", + * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NX.png", + * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PY.png", + * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NY.png", + * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PZ.png", + * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NZ.png" + * ] + * }); + * + * // Create a sphere and ground plane + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ + * radius: 2.0 + * }), + * new MetallicMaterial(viewer.scene, { + * baseColor: [1, 1, 1], + * metallic: 1.0, + * roughness: 1.0 + * }) + * }); + * ```` */ -class TrianglesInstancingFlatColorRenderer { +class ReflectionMap extends CubeTexture { - constructor(scene, withSAO) { - this._scene = scene; - this._withSAO = withSAO; - this._hash = this._getHash(); - this._allocate(); + /** + @private + */ + get type() { + return "ReflectionMap"; } - getValid() { - return this._hash === this._getHash(); - }; + /** + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for this ReflectionMap, unique among all components in the parent scene, generated automatically when omitted. + * @param {String[]} [cfg.src=null] Paths to six image files to load into this ReflectionMap. + * @param {Boolean} [cfg.flipY=false] Flips this ReflectionMap's source data along its vertical axis when true. + * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this.scene._lightsState.addReflectionMap(this._state); + this.scene._reflectionMapCreated(this); + } - _getHash() { - const scene = this._scene; - return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); + /** + * Destroys this ReflectionMap. + */ + destroy() { + super.destroy(); + this.scene._reflectionMapDestroyed(this); } +} - drawLayer(frameCtx, instancingLayer, renderPass) { +/** + * @desc A **LightMap** specifies a cube texture light map. + * + * ## Usage + * + * ````javascript + * import {Viewer, Mesh, buildSphereGeometry, + * ReadableGeometry, MetallicMaterial, LightMap} from "xeokit-sdk.es.js"; + * + * // Create a Viewer and arrange the camera + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.scene.camera.eye = [0, 0, 5]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; + * + * new LightMap(viewer.scene, { + * src: [ + * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PX.png", + * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NX.png", + * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PY.png", + * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NY.png", + * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PZ.png", + * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NZ.png" + * ] + * }); + * + * // Create a sphere and ground plane + * + * new Mesh(viewer.scene, { + * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ + * radius: 2.0 + * }), + * new MetallicMaterial(viewer.scene, { + * baseColor: [1, 1, 1], + * metallic: 1.0, + * roughness: 1.0 + * }) + * }); + * ```` + */ +class LightMap extends CubeTexture { - const model = instancingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + /** + @private + */ + get type() { + return "LightMap"; + } - if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } - } + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for this LightMap, unique among all components in the parent scene, generated automatically when omitted. + * @param {String:Object} [cfg.meta] Optional map of user-defined metadata to attach to this LightMap. + * @param {String[]} [cfg.src=null] Paths to six image files to load into this LightMap. + * @param {Boolean} [cfg.flipY=false] Flips this LightMap's source data along its vertical axis when true. + * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this.scene._lightMapCreated(this); + } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); - } + destroy() { + super.destroy(); + this.scene._lightMapDestroyed(this); + } +} - gl.uniform1i(this._uRenderPass, renderPass); +/** + * A {@link Marker} with a billboarded and textured quad attached to it. + * + * * Extends {@link Marker} + * * Keeps the quad oriented towards the viewpoint + * * Auto-fits the quad to the texture + * * Has a world-space position + * * Can be configured to hide the quad whenever the position is occluded by some other object + * + * ## Usage + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#markers_SpriteMarker)] + * + * ```` javascript + * import {Viewer, SpriteMarker } from "./../dist/xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [0, 0, 25]; + * viewer.scene.camera.look = [0, 0, 0]; + * viewer.scene.camera.up = [0, 1, 0]; + * + * new SpriteMarker(viewer.scene, { + * worldPos: [-10, 0, 0], + * src: "../assets/textures/diffuse/uvGrid2_512x1024.jpg", + * size: 5, + * occludable: false + * }); + * + * new SpriteMarker(viewer.scene, { + * worldPos: [+10, 0, 0], + * src: "../assets/textures/diffuse/uvGrid2_1024x512.jpg", + * size: 4, + * occludable: false + * }); + *```` + */ +class SpriteMarker extends Marker { - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this SpriteMarker as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID for this SpriteMarker, unique among all components in the parent scene, generated automatically when omitted. + * @param {Entity} [cfg.entity] Entity to associate this Marker with. When the SpriteMarker has an Entity, then {@link Marker#visible} will always be ````false```` if {@link Entity#visible} is false. + * @param {Boolean} [cfg.occludable=false] Indicates whether or not this Marker is hidden (ie. {@link Marker#visible} is ````false```` whenever occluded by {@link Entity}s in the {@link Scene}. + * @param {Number[]} [cfg.worldPos=[0,0,0]] World-space 3D Marker position. + * @param {String} [cfg.src=null] Path to image file to load into this SpriteMarker. See the {@link SpriteMarker#src} property for more info. + * @param {HTMLImageElement} [cfg.image=null] HTML Image object to load into this SpriteMarker. See the {@link SpriteMarker#image} property for more info. + * @param {Boolean} [cfg.flipY=false] Flips this SpriteMarker's texture image along its vertical axis when true. + * @param {String} [cfg.encoding="linear"] Texture encoding format. See the {@link Texture#encoding} property for more info. + */ + constructor(owner, cfg = {}) { - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$F); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } + super(owner, { + entity: cfg.entity, + occludable: cfg.occludable, + worldPos: cfg.worldPos + }); - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); + this._occluded = false; + this._visible = true; + this._src = null; + this._image = null; + this._pos = math.vec3(); + this._origin = math.vec3(); + this._rtcPos = math.vec3(); + this._dir = math.vec3(); + this._size = 1.0; + this._imageSize = math.vec2(); - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + this._texture = new Texture(this, { + src: cfg.src + }); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + this._geometry = new ReadableGeometry(this, { + primitive: "triangles", + positions: [3, 3, 0, -3, 3, 0, -3, -3, 0, 3, -3, 0], + normals: [-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0], + uv: [1, -1, 0, -1, 0, 0, 1, 0], + indices: [0, 1, 2, 0, 2, 3] // Ensure these will be front-faces + }); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); + this._mesh = new Mesh(this, { + geometry: this._geometry, + material: new PhongMaterial(this, { + ambient: [0.9, 0.3, 0.9], + shininess: 30, + diffuseMap: this._texture, + backfaces: true + }), + scale: [1, 1, 1], // Note: by design, scale does not work with billboard + position: cfg.worldPos, + rotation: [90, 0, 0], + billboard: "spherical", + occluder: false // Don't occlude SpriteMarkers or Annotations + }); - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); + this.visible = true; + this.collidable = cfg.collidable; + this.clippable = cfg.clippable; + this.pickable = cfg.pickable; + this.opacity = cfg.opacity; + this.size = cfg.size; - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); + if (cfg.image) { + this.image = cfg.image; + } else { + this.src = cfg.src; } + } - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } + _setVisible(visible) { // Called by VisibilityTester and this._entity.on("destroyed"..) + this._occluded = (!visible); + this._mesh.visible = this._visible && (!this._occluded); + super._setVisible(visible); + } - geometry.indicesBuf.bind(); + /** + * Sets if this ````SpriteMarker```` is visible or not. + * + * Default value is ````true````. + * + * @param {Boolean} visible Set ````true```` to make this ````SpriteMarker```` visible. + */ + set visible(visible) { + this._visible = (visible === null || visible === undefined) ? true : visible; + this._mesh.visible = this._visible && (!this._occluded); + } - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + /** + * Gets if this ````SpriteMarker```` is visible or not. + * + * Default value is ````true````. + * + * @returns {Boolean} Returns ````true```` if visible. + */ + get visible() { + return this._visible; + } - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); + /** + * Sets an ````HTMLImageElement```` to source the image from. + * + * Sets {@link Texture#src} null. + * + * @type {HTMLImageElement} + */ + set image(image) { + this._image = image; + if (this._image) { + this._imageSize[0] = this._image.width; + this._imageSize[1] = this._image.height; + this._updatePlaneSizeFromImage(); + this._src = null; + this._texture.image = this._image; + } + } - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); + /** + * Gets the ````HTMLImageElement```` the ````SpriteMarker````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {HTMLImageElement} + */ + get image() { + return this._image; + } + + /** + * Sets an image file path that the ````SpriteMarker````'s image is sourced from. + * + * Accepted file types are PNG and JPEG. + * + * Sets {@link Texture#image} null. + * + * @type {String} + */ + set src(src) { + this._src = src; + if (this._src) { + this._image = null; + const image = new Image(); + image.onload = () => { + this._texture.image = image; + this._imageSize[0] = image.width; + this._imageSize[1] = image.height; + this._updatePlaneSizeFromImage(); + }; + image.src = this._src; } + } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); + /** + * Gets the image file path that the ````SpriteMarker````'s image is sourced from, if set. + * + * Returns null if not set. + * + * @type {String} + */ + get src() { + return this._src; + } + + /** + * Sets the World-space size of the longest edge of the ````SpriteMarker````. + * + * Note that ````SpriteMarker```` sets its aspect ratio to match its image. If we set a value of ````1000````, and + * the image has size ````400x300````, then the ````SpriteMarker```` will then have size ````1000 x 750````. + * + * Default value is ````1.0````. + * + * @param {Number} size New World-space size of the ````SpriteMarker````. + */ + set size(size) { + this._size = (size === undefined || size === null) ? 1.0 : size; + if (this._image) { + this._updatePlaneSizeFromImage(); } } - _allocate() { + /** + * Gets the World-space size of the longest edge of the ````SpriteMarker````. + * + * Returns {Number} World-space size of the ````SpriteMarker````. + */ + get size() { + return this._size; + } - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; + /** + * Sets if this ````SpriteMarker```` is included in boundary calculations. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set collidable(value) { + this._mesh.collidable = (value !== false); + } - this._program = new Program(gl, this._buildShader()); + /** + * Gets if this ````SpriteMarker```` is included in boundary calculations. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get collidable() { + return this._mesh.collidable; + } - if (this._program.errors) { - this.errors = this._program.errors; - return; + /** + * Sets if this ````SpriteMarker```` is clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set clippable(value) { + this._mesh.clippable = (value !== false); + } + + /** + * Gets if this ````SpriteMarker```` is clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get clippable() { + return this._mesh.clippable; + } + + /** + * Sets if this ````SpriteMarker```` is pickable. + * + * Default is ````true````. + * + * @type {Boolean} + */ + set pickable(value) { + this._mesh.pickable = (value !== false); + } + + /** + * Gets if this ````SpriteMarker```` is pickable. + * + * Default is ````true````. + * + * @type {Boolean} + */ + get pickable() { + return this._mesh.pickable; + } + + /** + * Sets the opacity factor for this ````SpriteMarker````. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + set opacity(opacity) { + this._mesh.opacity = opacity; + } + + /** + * Gets this ````SpriteMarker````'s opacity factor. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + get opacity() { + return this._mesh.opacity; + } + + _updatePlaneSizeFromImage() { + const halfSize = this._size * 0.5; + const width = this._imageSize[0]; + const height = this._imageSize[1]; + const aspect = height / width; + if (width > height) { + this._geometry.positions = [ + halfSize, halfSize * aspect, 0, + -halfSize, halfSize * aspect, 0, + -halfSize, -halfSize * aspect, 0, + halfSize, -halfSize * aspect, 0 + ]; + } else { + this._geometry.positions = [ + halfSize / aspect, halfSize, 0, + -halfSize / aspect, halfSize, 0, + -halfSize / aspect, -halfSize, 0, + halfSize / aspect, -halfSize, 0 + ]; } + } +} - const program = this._program; +/** + * @desc Saves and restores the state of a {@link Scene}'s {@link Camera}. + * + * ## See Also + * + * * {@link ModelMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s of a model within a {@link Scene}. + * * {@link ObjectsMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. + * + * ## Usage + * + * In the example below, we'll create a {@link Viewer} and use an {@link XKTLoaderPlugin} to load an ````.xkt```` model. When the model has loaded, we'll save a snapshot of the {@link Camera} state in an CameraMemento. Then we'll move the Camera, and then we'll restore its original state again from the CameraMemento. + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, CameraMemento} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * // Load a model + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/schependomlaan/schependomlaan.xkt" + * }); + * + * // Set camera + * viewer.camera.eye = [-2.56, 8.38, 8.27]; + * viewer.camera.look = [13.44, 3.31, -14.83]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * model.on("loaded", () => { + * + * // Model has loaded + * + * // Save memento of camera state + * const cameraMemento = new CameraMemento(); + * + * cameraMemento.saveCamera(viewer.scene); + * + * // Move the camera + * viewer.camera.eye = [45.3, 2.00, 5.13]; + * viewer.camera.look = [0.0, 5.5, 10.0]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * // Restore the camera state again + * objectsMemento.restoreCamera(viewer.scene); + * }); + * ```` + */ +class CameraMemento { - this._uRenderPass = program.getLocation("renderPass"); + /** + * Creates a CameraState. + * + * @param {Scene} [scene] When given, immediately saves the state of the given {@link Scene}'s {@link Camera}. + */ + constructor(scene) { - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + /** @private */ + this._eye = math.vec3(); - this._uWorldMatrix = program.getLocation("worldMatrix"); - - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); + /** @private */ + this._look = math.vec3(); - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; + /** @private */ + this._up = math.vec3(); - const lights = lightsState.lights; - let light; + /** @private */ + this._projection = {}; - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - } + if (scene) { + this.saveCamera(scene); } + } - this._uSectionPlanes = []; + /** + * Saves the state of the given {@link Scene}'s {@link Camera}. + * + * @param {Scene} scene The scene that contains the {@link Camera}. + */ + saveCamera(scene) { - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + const camera = scene.camera; + const project = camera.project; - this._aPosition = program.getAttribute("position"); - this._aColor = program.getAttribute("color"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._aOffset = program.getAttribute("offset"); + this._eye.set(camera.eye); + this._look.set(camera.look); + this._up.set(camera.up); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); + switch (camera.projection) { - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + case "perspective": + this._projection = { + projection: "perspective", + fov: project.fov, + fovAxis: project.fovAxis, + near: project.near, + far: project.far + }; + break; + + case "ortho": + this._projection = { + projection: "ortho", + scale: project.scale, + near: project.near, + far: project.far + }; + break; + + case "frustum": + this._projection = { + projection: "frustum", + left: project.left, + right: project.right, + top: project.top, + bottom: project.bottom, + near: project.near, + far: project.far + }; + break; + + case "custom": + this._projection = { + projection: "custom", + matrix: project.matrix.slice() + }; + break; } } - _bindProgram(frameCtx) { + /** + * Restores a {@link Scene}'s {@link Camera} to the state previously captured with {@link CameraMemento#saveCamera}. + * + * @param {Scene} scene The scene. + * @param {Function} [done] When this callback is given, will fly the {@link Camera} to the saved state then fire the callback. Otherwise will just jump the Camera to the saved state. + */ + restoreCamera(scene, done) { - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; - const lights = lightsState.lights; - const project = scene.camera.project; + const camera = scene.camera; + const savedProjection = this._projection; - this._program.bind(); + function restoreProjection() { - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + switch (savedProjection.type) { - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); - } + case "perspective": + camera.perspective.fov = savedProjection.fov; + camera.perspective.fovAxis = savedProjection.fovAxis; + camera.perspective.near = savedProjection.near; + camera.perspective.far = savedProjection.far; + break; - for (let i = 0, len = lights.length; i < len; i++) { - const light = lights[i]; - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); - } - } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } - } + case "ortho": + camera.ortho.scale = savedProjection.scale; + camera.ortho.near = savedProjection.near; + camera.ortho.far = savedProjection.far; + break; - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$2[0] = viewportWidth; - tempVec4$2[1] = viewportHeight; - tempVec4$2[2] = sao.blendCutoff; - tempVec4$2[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$2); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + case "frustum": + camera.frustum.left = savedProjection.left; + camera.frustum.right = savedProjection.right; + camera.frustum.top = savedProjection.top; + camera.frustum.bottom = savedProjection.bottom; + camera.frustum.near = savedProjection.near; + camera.frustum.far = savedProjection.far; + break; + + case "custom": + camera.customProjection.matrix = savedProjection.matrix; + break; } } - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + if (done) { + scene.viewer.cameraFlight.flyTo({ + eye: this._eye, + look: this._look, + up: this._up, + orthoScale: savedProjection.scale, + projection: savedProjection.projection + }, () => { + restoreProjection(); + done(); + }); + } else { + camera.eye = this._eye; + camera.look = this._look; + camera.up = this._up; + restoreProjection(); + camera.projection = savedProjection.projection; } } +} - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; - } - - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Instancing geometry flat-shading drawing vertex shader"); - - src.push("uniform int renderPass;"); +const color$1 = math.vec3(); - src.push("in vec3 position;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); +/** + * @desc Saves and restores a snapshot of the visual state of the {@link Entity}'s of a model within a {@link Scene}. + * + * ## Usage + * + * In the example below, we'll create a {@link Viewer} and use an {@link XKTLoaderPlugin} to load an ````.xkt```` model. When the model has loaded, we'll hide a couple of {@link Entity}s and save a snapshot of the visual states of all its Entitys in an ModelMemento. Then we'll show all the Entitys + * again, and then we'll restore the visual states of all the Entitys again from the ModelMemento, which will hide those two Entitys again. + * + * ## See Also + * + * * {@link CameraMemento} - Saves and restores the state of a {@link Scene}'s {@link Camera}. + * * {@link ObjectsMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, ModelMemento} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * // Load a model + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/schependomlaan/schependomlaan.xkt" + * }); + * + * model.on("loaded", () => { + * + * // Model has loaded + * + * // Hide a couple of objects + * viewer.scene.objects["0u4wgLe6n0ABVaiXyikbkA"].visible = false; + * viewer.scene.objects["3u4wgLe3n0AXVaiXyikbYO"].visible = false; + * + * // Save memento of all object states, which includes those two hidden objects + * const ModelMemento = new ModelMemento(); + * + * const metaModel = viewer.metaScene.metaModels + * ModelMemento.saveObjects(viewer.scene); + * + * // Show all objects + * viewer.scene.setObjectsVisible(viewer.scene.objectIds, true); + * + * // Restore the objects states again, which involves hiding those two objects again + * ModelMemento.restoreObjects(viewer.scene); + * }); + * ````` + * + * ## Masking Saved State + * + * We can optionally supply a mask to focus what state we save and restore. + * + * For example, to save and restore only the {@link Entity#visible} and {@link Entity#clippable} states: + * + * ````javascript + * ModelMemento.saveObjects(viewer.scene, { + * visible: true, + * clippable: true + * }); + * + * //... + * + * // Restore the objects states again + * ModelMemento.restoreObjects(viewer.scene); + * ```` + */ +class ModelMemento { - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } + /** + * Creates a ModelMemento. + * + * @param {MetaModel} [metaModel] When given, immediately saves the model's {@link Entity} states to this ModelMemento. + */ + constructor(metaModel) { - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); + /** @private */ + this.objectsVisible = []; - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } + /** @private */ + this.objectsEdges = []; - src.push("out vec4 vViewPosition;"); - src.push("out vec4 vColor;"); + /** @private */ + this.objectsXrayed = []; - src.push("void main(void) {"); + /** @private */ + this.objectsHighlighted = []; - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT + /** @private */ + this.objectsSelected = []; - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + /** @private */ + this.objectsClippable = []; - src.push("} else {"); + /** @private */ + this.objectsPickable = []; - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } + /** @private */ + this.objectsColorize = []; - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vViewPosition = viewPosition;"); - src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + /** @private */ + this.objectsOpacity = []; - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } + /** @private */ + this.numObjects = 0; - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + if (metaModel) { + const metaScene = metaModel.metaScene; + const scene = metaScene.scene; + this.saveObjects(scene, metaModel); } - - src.push("gl_Position = clipPos;"); - src.push("}"); - src.push("}"); - return src; } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - let i; - let len; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Instancing geometry flat-shading drawing fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + /** + * Saves a snapshot of the visual state of the {@link Entity}'s that represent objects within a model. + * + * @param {Scene} scene The scene. + * @param {MetaModel} metaModel Represents the model. Corresponds with an {@link Entity} that represents the model in the scene. + * @param {Object} [mask] Masks what state gets saved. Saves all state when not supplied. + * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. + * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. + * @param {boolean} [mask.edges] Saves {@link Entity#edges} values when ````true````. + * @param {boolean} [mask.xrayed] Saves {@link Entity#xrayed} values when ````true````. + * @param {boolean} [mask.highlighted] Saves {@link Entity#highlighted} values when ````true````. + * @param {boolean} [mask.selected] Saves {@link Entity#selected} values when ````true````. + * @param {boolean} [mask.clippable] Saves {@link Entity#clippable} values when ````true````. + * @param {boolean} [mask.pickable] Saves {@link Entity#pickable} values when ````true````. + * @param {boolean} [mask.colorize] Saves {@link Entity#colorize} values when ````true````. + * @param {boolean} [mask.opacity] Saves {@link Entity#opacity} values when ````true````. + */ + saveObjects(scene, metaModel, mask) { - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); + const rootMetaObject = metaModel.rootMetaObject; + if (!rootMetaObject) { + return; } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } + const objectIds = rootMetaObject.getObjectIDsInSubtree(); - src.push("uniform mat4 viewMatrix;"); + this.numObjects = 0; - src.push("uniform vec4 lightAmbient;"); + this._mask = mask ? utils.apply(mask, {}) : null; - for (i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { + const objects = scene.objects; + const visible = (!mask || mask.visible); + const edges = (!mask || mask.edges); + const xrayed = (!mask || mask.xrayed); + const highlighted = (!mask || mask.highlighted); + const selected = (!mask || mask.selected); + const clippable = (!mask || mask.clippable); + const pickable = (!mask || mask.pickable); + const colorize = (!mask || mask.colorize); + const opacity = (!mask || mask.opacity); + + for (var i = 0, len = objectIds.length; i < len; i++) { + const objectId = objectIds[i]; + const object = objects[objectId]; + if (!object) { continue; } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); + if (visible) { + this.objectsVisible[i] = object.visible; } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); + if (edges) { + this.objectsEdges[i] = object.edges; } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); + if (xrayed) { + this.objectsXrayed[i] = object.xrayed; } - } - - src.push("in vec4 vViewPosition;"); - src.push("in vec4 vColor;"); - - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + if (highlighted) { + this.objectsHighlighted[i] = object.highlighted; } - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - src.push("}"); - } - - src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); - src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); - - src.push("float lambertian = 1.0;"); - - src.push("vec3 xTangent = dFdx( vViewPosition.xyz );"); - src.push("vec3 yTangent = dFdy( vViewPosition.xyz );"); - src.push("vec3 viewNormal = normalize( cross( xTangent, yTangent ) );"); - - for (i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; + if (selected) { + this.objectsSelected[i] = object.selected; } - if (light.type === "dir") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); - } else { - src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else { - continue; + if (clippable) { + this.objectsClippable[i] = object.clippable; } - src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); - src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); + if (pickable) { + this.objectsPickable[i] = object.pickable; + } + if (colorize) { + const objectColor = object.colorize; + this.objectsColorize[i * 3 + 0] = objectColor[0]; + this.objectsColorize[i * 3 + 1] = objectColor[1]; + this.objectsColorize[i * 3 + 2] = objectColor[2]; + } + if (opacity) { + this.objectsOpacity[i] = object.opacity; + } + this.numObjects++; } + } - src.push("vec4 fragColor = vec4((lightAmbient.rgb * lightAmbient.a * vColor.rgb) + (reflectedColor * vColor.rgb), vColor.a);"); + /** + * Restores a {@link Scene}'s {@link Entity}'s to their state previously captured with {@link ModelMemento#saveObjects}. + * + * Assumes that the model has not been destroyed or modified since saving. + * + * @param {Scene} scene The scene that was given to {@link ModelMemento#saveObjects}. + * @param {MetaModel} metaModel The metamodel that was given to {@link ModelMemento#saveObjects}. + */ + restoreObjects(scene, metaModel) { - if (this._withSAO) { - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" outColor = vec4(fragColor.rgb * ambient, 1.0);"); - } else { - src.push(" outColor = fragColor;"); + const rootMetaObject = metaModel.rootMetaObject; + if (!rootMetaObject) { + return; } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } + const objectIds = rootMetaObject.getObjectIDsInSubtree(); - src.push("}"); - return src; - } + const mask = this._mask; - webglContextRestored() { - this._program = null; - } + const visible = (!mask || mask.visible); + const edges = (!mask || mask.edges); + const xrayed = (!mask || mask.xrayed); + const highlighted = (!mask || mask.highlighted); + const selected = (!mask || mask.selected); + const clippable = (!mask || mask.clippable); + const pickable = (!mask || mask.pickable); + const colorize = (!mask || mask.colorize); + const opacity = (!mask || mask.opacity); - destroy() { - if (this._program) { - this._program.destroy(); + const objects = scene.objects; + + for (var i = 0, len = objectIds.length; i < len; i++) { + const objectId = objectIds[i]; + const object = objects[objectId]; + if (!object) { + continue; + } + if (visible) { + object.visible = this.objectsVisible[i]; + } + if (edges) { + object.edges = this.objectsEdges[i]; + } + if (xrayed) { + object.xrayed = this.objectsXrayed[i]; + } + if (highlighted) { + object.highlighted = this.objectsHighlighted[i]; + } + if (selected) { + object.selected = this.objectsSelected[i]; + } + if (clippable) { + object.clippable = this.objectsClippable[i]; + } + if (pickable) { + object.pickable = this.objectsPickable[i]; + } + if (colorize) { + color$1[0] = this.objectsColorize[i * 3 + 0]; + color$1[1] = this.objectsColorize[i * 3 + 1]; + color$1[2] = this.objectsColorize[i * 3 + 2]; + object.colorize = color$1; + } + if (opacity) { + object.opacity = this.objectsOpacity[i]; + } } - this._program = null; } } -const tempVec3a$E = math.vec3(); +const color = math.vec3(); /** - * @private + * @desc Saves and restores a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. + * + * * An Entity represents an object when {@link Entity#isObject} is ````true````. + * * Each object-Entity is registered by {@link Entity#id} in {@link Scene#objects}. + * + * ## See Also + * + * * {@link CameraMemento} - Saves and restores the state of a {@link Scene}'s {@link Camera}. + * * {@link ModelMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s of a model within a {@link Scene}. + * + * ## Usage + * + * In the example below, we'll create a {@link Viewer} and use an {@link XKTLoaderPlugin} to load an ````.xkt```` model. When the model has loaded, we'll hide a couple of {@link Entity}s and save a snapshot of the visual states of all the Entitys in an ObjectsMemento. Then we'll show all the Entitys + * again, and then we'll restore the visual states of all the Entitys again from the ObjectsMemento, which will hide those two Entitys again. + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, ObjectsMemento} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * // Load a model + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/schependomlaan/schependomlaan.xkt" + * }); + * + * model.on("loaded", () => { + * + * // Model has loaded + * + * // Hide a couple of objects + * viewer.scene.objects["0u4wgLe6n0ABVaiXyikbkA"].visible = false; + * viewer.scene.objects["3u4wgLe3n0AXVaiXyikbYO"].visible = false; + * + * // Save memento of all object states, which includes those two hidden objects + * const objectsMemento = new ObjectsMemento(); + * + * objectsMemento.saveObjects(viewer.scene); + * + * // Show all objects + * viewer.scene.setObjectsVisible(viewer.scene.objectIds, true); + * + * // Restore the objects states again, which involves hiding those two objects again + * objectsMemento.restoreObjects(viewer.scene); + * }); + * ````` + * + * ## Masking Saved State + * + * We can optionally supply a mask to focus what state we save and restore. + * + * For example, to save and restore only the {@link Entity#visible} and {@link Entity#clippable} states: + * + * ````javascript + * objectsMemento.saveObjects(viewer.scene, { + * visible: true, + * clippable: true + * }); + * + * //... + * + * // Restore the objects states again + * objectsMemento.restoreObjects(viewer.scene); + * ```` */ -class TrianglesInstancingSilhouetteRenderer { +class ObjectsMemento { - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); - } + /** + * Creates an ObjectsMemento. + */ + constructor() { - getValid() { - return this._hash === this._getHash(); - }; + /** @private */ + this.objectsVisible = []; - _getHash() { - return this._scene._sectionPlanesState.getHash(); - } + /** @private */ + this.objectsEdges = []; - drawLayer(frameCtx, instancingLayer, renderPass) { + /** @private */ + this.objectsXrayed = []; - const model = instancingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + /** @private */ + this.objectsHighlighted = []; - if (!this._program) { - this._allocate(instancingLayer.model.scene); - if (this.errors) { - return; - } - } + /** @private */ + this.objectsSelected = []; - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); - } + /** @private */ + this.objectsClippable = []; - gl.uniform1i(this._uRenderPass, renderPass); + /** @private */ + this.objectsPickable = []; - if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { - const material = scene.xrayMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + /** @private */ + this.objectsColorize = []; - } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + /** @private */ + this.objectsHasColorize = []; - } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { - const material = scene.selectedMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + /** @private */ + this.objectsOpacity = []; - } else { - gl.uniform4fv(this._uColor, math.vec3([1, 1, 1])); - } + /** @private */ + this.numObjects = 0; + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + /** + * Saves a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. + * + * @param {Scene} scene The scene. + * @param {Object} [mask] Masks what state gets saved. Saves all state when not supplied. + * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. + * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. + * @param {boolean} [mask.edges] Saves {@link Entity#edges} values when ````true````. + * @param {boolean} [mask.xrayed] Saves {@link Entity#xrayed} values when ````true````. + * @param {boolean} [mask.highlighted] Saves {@link Entity#highlighted} values when ````true````. + * @param {boolean} [mask.selected] Saves {@link Entity#selected} values when ````true````. + * @param {boolean} [mask.clippable] Saves {@link Entity#clippable} values when ````true````. + * @param {boolean} [mask.pickable] Saves {@link Entity#pickable} values when ````true````. + * @param {boolean} [mask.colorize] Saves {@link Entity#colorize} values when ````true````. + * @param {boolean} [mask.opacity] Saves {@link Entity#opacity} values when ````true````. + */ + saveObjects(scene, mask) { - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$E); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + this.numObjects = 0; + + this._mask = mask ? utils.apply(mask, {}) : null; + + const objects = scene.objects; + const visible = (!mask || mask.visible); + const edges = (!mask || mask.edges); + const xrayed = (!mask || mask.xrayed); + const highlighted = (!mask || mask.highlighted); + const selected = (!mask || mask.selected); + const clippable = (!mask || mask.clippable); + const pickable = (!mask || mask.pickable); + const colorize = (!mask || mask.colorize); + const opacity = (!mask || mask.opacity); + + for (let objectId in objects) { + if (objects.hasOwnProperty(objectId)) { + const object = objects[objectId]; + const i = this.numObjects; + if (visible) { + this.objectsVisible[i] = object.visible; + } + if (edges) { + this.objectsEdges[i] = object.edges; + } + if (xrayed) { + this.objectsXrayed[i] = object.xrayed; + } + if (highlighted) { + this.objectsHighlighted[i] = object.highlighted; + } + if (selected) { + this.objectsSelected[i] = object.selected; + } + if (clippable) { + this.objectsClippable[i] = object.clippable; + } + if (pickable) { + this.objectsPickable[i] = object.pickable; + } + if (colorize) { + const objectColor = object.colorize; + if (objectColor) { + this.objectsColorize[i * 3 + 0] = objectColor[0]; + this.objectsColorize[i * 3 + 1] = objectColor[1]; + this.objectsColorize[i * 3 + 2] = objectColor[2]; + this.objectsHasColorize[i] = true; + } else { + this.objectsHasColorize[i] = false; } } + if (opacity) { + this.objectsOpacity[i] = object.opacity; + } + this.numObjects++; } } + } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + /** + * Restores a {@link Scene}'s {@link Entity}'s to their state previously captured with {@link ObjectsMemento#saveObjects}. + * @param {Scene} scene The scene. + */ + restoreObjects(scene) { - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + const mask = this._mask; - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + const visible = (!mask || mask.visible); + const edges = (!mask || mask.edges); + const xrayed = (!mask || mask.xrayed); + const highlighted = (!mask || mask.highlighted); + const selected = (!mask || mask.selected); + const clippable = (!mask || mask.clippable); + const pickable = (!mask || mask.pickable); + const colorize = (!mask || mask.colorize); + const opacity = (!mask || mask.opacity); - this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); - gl.vertexAttribDivisor(this._aFlags.location, 1); + var i = 0; - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } + const objects = scene.objects; - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); + for (let objectId in objects) { + if (objects.hasOwnProperty(objectId)) { + const object = objects[objectId]; + if (visible) { + object.visible = this.objectsVisible[i]; + } + if (edges) { + object.edges = this.objectsEdges[i]; + } + if (xrayed) { + object.xrayed = this.objectsXrayed[i]; + } + if (highlighted) { + object.highlighted = this.objectsHighlighted[i]; + } + if (selected) { + object.selected = this.objectsSelected[i]; + } + if (clippable) { + object.clippable = this.objectsClippable[i]; + } + if (pickable) { + object.pickable = this.objectsPickable[i]; + } + if (colorize ) { + if (this.objectsHasColorize[i]) { + color[0] = this.objectsColorize[i * 3 + 0]; + color[1] = this.objectsColorize[i * 3 + 1]; + color[2] = this.objectsColorize[i * 3 + 2]; + object.colorize = color; + } else { + object.colorize = null; + } + } + if (opacity) { + object.opacity = this.objectsOpacity[i]; + } + i++; + } } + } +} - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); +/** + * @desc A {@link Curve} along which a 3D position can be animated. + * + * * As shown in the diagram below, a CubicBezierCurve is defined by four control points. + * * You can sample a {@link CubicBezierCurve#point} and a {@link CubicBezierCurve#tangent} vector on a CubicBezierCurve for any given value of {@link CubicBezierCurve#t} in the range [0..1]. + * * When you set {@link CubicBezierCurve#t} on a CubicBezierCurve, its {@link CubicBezierCurve#point} and {@link CubicBezierCurve#tangent} properties will update accordingly. + * * To build a complex path, you can combine an unlimited combination of CubicBezierCurves, {@link QuadraticBezierCurve}s and {@link SplineCurve}s into a {@link Path}. + * + *
+ * + *
+ * [Cubic Bezier Curve from WikiPedia](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) + */ +class CubicBezierCurve extends Curve { - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this CubicBezierCurve as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {Number[]} [cfg.v0=[0,0,0]] The starting point. + * @param {Number[]} [cfg.v1=[0,0,0]] The first control point. + * @param {Number[]} [cfg.v2=[0,0,0]] The middle control point. + * @param {Number[]} [cfg.v3=[0,0,0]] The ending point. + * @param {Number} [cfg.t=0] Current position on this CubicBezierCurve, in range between 0..1. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this.v0 = cfg.v0; + this.v1 = cfg.v1; + this.v2 = cfg.v2; + this.v3 = cfg.v3; + this.t = cfg.t; + } - gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags2) { - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + /** + * Sets the starting point on this CubicBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @param {Number[]} value The starting point. + */ + set v0(value) { + this._v0 = value || math.vec3([0, 0, 0]); } - _allocate() { + /** + * Gets the starting point on this CubicBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @returns {Number[]} The starting point. + */ + get v0() { + return this._v0; + } - const scene = this._scene; - const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + /** + * Sets the first control point on this CubicBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @param {Number[]} value The first control point. + */ + set v1(value) { + this._v1 = value || math.vec3([0, 0, 0]); + } - this._program = new Program(gl, this._buildShader()); + /** + * Gets the first control point on this CubicBezierCurve. + * + * Fires a {@link CubicBezierCurve#v1:event} event on change. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @returns {Number[]} The first control point. + */ + get v1() { + return this._v1; + } - if (this._program.errors) { - this.errors = this._program.errors; - return; - } + /** + * Sets the second control point on this CubicBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @param {Number[]} value The second control point. + */ + set v2(value) { + this._v2 = value || math.vec3([0, 0, 0]); + } - const program = this._program; + /** + * Gets the second control point on this CubicBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @returns {Number[]} The second control point. + */ + get v2() { + return this._v2; + } - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uColor = program.getLocation("color"); - this._uSectionPlanes = []; + /** + * Sets the end point on this CubicBezierCurve. + * + * Fires a {@link CubicBezierCurve#v3:event} event on change. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @param {Number[]} value The end point. + */ + set v3(value) { + this.fire("v3", this._v3 = value || math.vec3([0, 0, 0])); + } - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + /** + * Gets the end point on this CubicBezierCurve. + * + * Fires a {@link CubicBezierCurve#v3:event} event on change. + * + * Default value is ````[0.0, 0.0, 0.0]```` + * + * @returns {Number[]} The end point. + */ + get v3() { + return this._v3; + } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + /** + * Sets the current position of progress along this CubicBezierCurve. + * + * Automatically clamps to range ````[0..1]````. + * + * @param {Number} value New progress time value. + */ + set t(value) { + value = value || 0; + this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); + } - if ( scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } + /** + * Gets the current position of progress along this CubicBezierCurve. + * + * @returns {Number} Current progress time value. + */ + get t() { + return this._t; } - _bindProgram() { + /** + * Returns point on this CubicBezierCurve at the given position. + * + * @param {Number} t Position to get point at. + * + * @returns {Number[]} The point at the given position. + */ + get point() { + return this.getPoint(this._t); + } - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; + /** + * Returns point on this CubicBezierCurve at the given position. + * + * @param {Number} t Position to get point at. + * + * @returns {Number[]} The point at the given position. + */ + getPoint(t) { - this._program.bind(); + var vector = math.vec3(); - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + vector[0] = math.b3(t, this._v0[0], this._v1[0], this._v2[0], this._v3[0]); + vector[1] = math.b3(t, this._v0[1], this._v1[1], this._v2[1], this._v3[1]); + vector[2] = math.b3(t, this._v0[2], this._v1[2], this._v2[2], this._v3[2]); - if ( scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + return vector; } - _buildShader() { + getJSON() { return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() + v0: this._v0, + v1: this._v1, + v2: this._v2, + v3: this._v3, + t: this._t }; } +} - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Instancing fill vertex shader"); - - src.push("uniform int renderPass;"); - - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); +/** + * @desc A complex curved path constructed from various {@link Curve} subtypes. + * + * * A Path can be constructed from these {@link Curve} subtypes: {@link SplineCurve}, {@link CubicBezierCurve} and {@link QuadraticBezierCurve}. + * * You can sample a {@link Path#point} and a {@link Curve#tangent} vector on a Path for any given value of {@link Path#t} in the range ````[0..1]````. + * * When you set {@link Path#t} on a Path, its {@link Path#point} and {@link Curve#tangent} properties will update accordingly. + */ +class Path extends Curve { - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); + /** + * @constructor + * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this SectionPlane as well. + * @param {*} [cfg] Path configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. + * @param {String []} [cfg.paths=[]] IDs or instances of {{#crossLink "path"}}{{/crossLink}} subtypes to add to this Path. + * @param {Number} [cfg.t=0] Current position on this Path, in range between 0..1. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this._cachedLengths = []; + this._dirty = true; + this._curves = []; // Array of child Curve components + this._t = 0; + this._dirtySubs = []; // Subscriptions to "dirty" events from child Curve components + this._destroyedSubs = []; // Subscriptions to "destroyed" events from child Curve components + this.curves = cfg.curves || []; // Add initial curves + this.t = cfg.t; // Set initial progress + } - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); + /** + * Adds a {@link Curve} to this Path. + * + * @param {Curve} curve The {@link Curve} to add. + */ + addCurve(curve) { + this._curves.push(curve); + this._dirty = true; + } - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } + /** + * Sets the {@link Curve}s in this Path. + * + * Default value is ````[]````. + * + * @param {{Array of Spline, Path, QuadraticBezierCurve or CubicBezierCurve}} value. + */ + set curves(value) { - src.push("uniform vec4 color;"); + value = value || []; - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); + var curve; + // Unsubscribe from events on old curves + var i; + var len; + for (i = 0, len = this._curves.length; i < len; i++) { + curve = this._curves[i]; + curve.off(this._dirtySubs[i]); + curve.off(this._destroyedSubs[i]); } - src.push("void main(void) {"); - - // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - - src.push(`if (int(flags.y) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + this._curves = []; + this._dirtySubs = []; + this._destroyedSubs = []; - src.push("} else {"); + var self = this; - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + function curveDirty() { + self._dirty = true; } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + function curveDestroyed() { + var id = this.id; + for (i = 0, len = self._curves.length; i < len; i++) { + if (self._curves[i].id === id) { + self._curves = self._curves.slice(i, i + 1); + self._dirtySubs = self._dirtySubs.slice(i, i + 1); + self._destroyedSubs = self._destroyedSubs.slice(i, i + 1); + self._dirty = true; + return; + } + } } - src.push("gl_Position = clipPos;"); - src.push("}"); - src.push("}"); - return src; - } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Instancing fill fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); + for (i = 0, len = value.length; i < len; i++) { + curve = value[i]; + if (utils.isNumeric(curve) || utils.isString(curve)) { + // ID given for curve - find the curve component + var id = curve; + curve = this.scene.components[id]; + if (!curve) { + this.error("Component not found: " + _inQuotes(id)); + continue; + } } - } - src.push("uniform vec4 color;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + + var type = curve.type; + + if (type !== "xeokit.SplineCurve" && + type !== "xeokit.Path" && + type !== "xeokit.CubicBezierCurve" && + type !== "xeokit.QuadraticBezierCurve") { + + this.error("Component " + _inQuotes(curve.id) + + " is not a xeokit.SplineCurve, xeokit.Path or xeokit.QuadraticBezierCurve"); + + continue; } - src.push("if (dist > 0.0) { discard; }"); - src.push("}"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + + this._curves.push(curve); + this._dirtySubs.push(curve.on("dirty", curveDirty)); + this._destroyedSubs.push(curve.once("destroyed", curveDestroyed)); } - src.push("outColor = color;"); - src.push("}"); - return src; - } - webglContextRestored() { - this._program = null; + this._dirty = true; } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + /** + * Gets the {@link Curve}s in this Path. + * + * @returns {{Array of Spline, Path, QuadraticBezierCurve or CubicBezierCurve}} the {@link Curve}s in this path. + */ + get curves() { + return this._curves; } -} - -const tempVec3a$D = math.vec3(); -const defaultColor$2 = new Float32Array([0,0,0,1]); - -/** - * @private - */ -class TrianglesInstancingEdgesRenderer { - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); + /** + * Sets the current point of progress along this Path. + * + * Automatically clamps to range ````[0..1]````. + * + * Default value is ````0````. + * + * @param {Number} value The current point of progress. + */ + set t(value) { + value = value || 0; + this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); } - getValid() { - return this._hash === this._getHash(); - }; - - _getHash() { - return this._scene._sectionPlanesState.getHash(); + /** + * Gets the current point of progress along this Path. + * + * Default value is ````0````. + * + * @returns {Number} The current point of progress. + */ + get t() { + return this._t; } - drawLayer(frameCtx, instancingLayer, renderPass) { + /** + * Gets point on this Path corresponding to the current value of {@link Path#t}. + * + * @returns {Number[]} The point. + */ + get point() { + return this.getPoint(this._t); + } - const model = instancingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + /** + * Length of this Path, which is the cumulative length of all {@link Curve}s currently in {@link Path#curves}. + * + * @return {Number} Length of this path. + */ + get length() { + var lens = this._getCurveLengths(); + return lens[lens.length - 1]; + } - if (!this._program) { - this._allocate(instancingLayer); - if (this.errors) { - return; + /** + * Gets a point on this Path corresponding to the given progress position. + * + * @param {Number} t Indicates point of progress along this curve, in the range [0..1]. + * @returns {Number[]} + */ + getPoint(t) { + var d = t * this.length; + var curveLengths = this._getCurveLengths(); + var i = 0, diff, curve; + while (i < curveLengths.length) { + if (curveLengths[i] >= d) { + diff = curveLengths[i] - d; + curve = this._curves[i]; + var u = 1 - diff / curve.length; + return curve.getPointAt(u); } + i++; } + return null; + } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + _getCurveLengths() { + if (!this._dirty) { + return this._cachedLengths; } + var lengths = []; + var sums = 0; + var i, il = this._curves.length; + for (i = 0; i < il; i++) { + sums += this._curves[i].length; + lengths.push(sums); - gl.uniform1i(this._uRenderPass, renderPass); + } + this._cachedLengths = lengths; + this._dirty = false; + return lengths; + } - if (renderPass === RENDER_PASSES.EDGES_XRAYED) { - const material = scene.xrayMaterial._state; - const edgeColor = material.edgeColor; - const edgeAlpha = material.edgeAlpha; - gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); - - } else if (renderPass === RENDER_PASSES.EDGES_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const edgeColor = material.edgeColor; - const edgeAlpha = material.edgeAlpha; - gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); - - } else if (renderPass === RENDER_PASSES.EDGES_SELECTED) { - const material = scene.selectedMaterial._state; - const edgeColor = material.edgeColor; - const edgeAlpha = material.edgeAlpha; - gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); - - } else { - gl.uniform4fv(this._uColor, defaultColor$2); - } - - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$D); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); - gl.vertexAttribDivisor(this._aFlags.location, 1); - } - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - geometry.edgeIndicesBuf.bind(); - - gl.drawElementsInstanced(gl.LINES, geometry.edgeIndicesBuf.numItems, geometry.edgeIndicesBuf.itemType, 0, state.numInstances); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } - - if (this._aFlags) { - gl.vertexAttribDivisor(this._aFlags.location, 0); + _getJSON() { + var curveIds = []; + for (var i = 0, len = this._curves.length; i < len; i++) { + curveIds.push(this._curves[i].id); } + return { + curves: curveIds, + t: this._t + }; + } - if (this._aFlags2) { - gl.vertexAttribDivisor(this._aFlags2.location, 0); + /** + * Destroys this Path. + */ + destroy() { + super.destroy(); + var i; + var len; + var curve; + for (i = 0, len = this._curves.length; i < len; i++) { + curve = this._curves[i]; + curve.off(this._dirtySubs[i]); + curve.off(this._destroyedSubs[i]); } } +} - _allocate() { - const scene = this._scene; - const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; +/** + * A **QuadraticBezierCurve** is a {@link Curve} along which a 3D position can be animated. + * + * * As shown in the diagram below, a QuadraticBezierCurve is defined by three control points + * * You can sample a {@link QuadraticBezierCurve#point} and a {@link Curve#tangent} vector on a QuadraticBezierCurve for any given value of {@link QuadraticBezierCurve#t} in the range ````[0..1]```` + * * When you set {@link QuadraticBezierCurve#t} on a QuadraticBezierCurve, its {@link QuadraticBezierCurve#point} and {@link Curve#tangent} will update accordingly. + * * To build a complex path, you can combine an unlimited combination of QuadraticBezierCurves, {@link CubicBezierCurve}s and {@link SplineCurve}s into a {@link Path}. + *
+ * + *
+ * *[Quadratic Bezier Curve from WikiPedia](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)* + */ +class QuadraticBezierCurve extends Curve { - this._program = new Program(gl, this._buildShader()); + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this MetallicMaterial as well. + * @param {*} [cfg] Configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {{#crossLink "Scene"}}Scene{{/crossLink}}, generated automatically when omitted. + * @param {Number[]} [cfg.v0=[0,0,0]] The starting point. + * @param {Number[]} [cfg.v1=[0,0,0]] The middle control point. + * @param {Number[]} [cfg.v2=[0,0,0]] The end point. + * @param {Number[]} [cfg.t=0] Current position on this QuadraticBezierCurve, in range between ````0..1````. + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + this.v0 = cfg.v0; + this.v1 = cfg.v1; + this.v2 = cfg.v2; + this.t = cfg.t; + } - if (this._program.errors) { - this.errors = this._program.errors; - return; - } + /** + * Sets the starting point on this QuadraticBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @param {Number[]} value New starting point. + */ + set v0(value) { + this._v0 = value || math.vec3([0, 0, 0]); + } - const program = this._program; + /** + * Gets the starting point on this QuadraticBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @returns {Number[]} The starting point. + */ + get v0() { + return this._v0; + } - this._uRenderPass = program.getLocation("renderPass"); - this._uColor = program.getLocation("color"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; + /** + * Sets the middle control point on this QuadraticBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @param {Number[]} value New middle control point. + */ + set v1(value) { + this._v1 = value || math.vec3([0, 0, 0]); + } - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + /** + * Gets the middle control point on this QuadraticBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @returns {Number[]} The middle control point. + */ + get v1() { + return this._v1; + } - this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + /** + * Sets the end point on this QuadraticBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @param {Number[]} value The new end point. + */ + set v2(value) { + this._v2 = value || math.vec3([0, 0, 0]); + } - if ( scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } + /** + * Gets the end point on this QuadraticBezierCurve. + * + * Default value is ````[0.0, 0.0, 0.0]````. + * + * @returns {Number[]} The end point. + */ + get v2() { + return this._v2; } - _bindProgram() { + /** + * Sets the progress along this QuadraticBezierCurve. + * + * Automatically clamps to range [0..1]. + * + * Default value is ````0````. + * + * @param {Number} value The new progress location. + */ + set t(value) { + value = value || 0; + this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); + } - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; + /** + * Gets the progress along this QuadraticBezierCurve. + * + * Default value is ````0````. + * + * @returns {Number} The current progress location. + */ + get t() { + return this._t; + } - this._program.bind(); + /** + Point on this QuadraticBezierCurve at position {@link QuadraticBezierCurve/t}. - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + @property point + @type {Number[]} + */ + get point() { + return this.getPoint(this._t); + } - if ( scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + /** + * Returns the point on this QuadraticBezierCurve at the given position. + * + * @param {Number} t Position to get point at. + * @returns {Number[]} The point. + */ + getPoint(t) { + var vector = math.vec3(); + vector[0] = math.b2(t, this._v0[0], this._v1[0], this._v2[0]); + vector[1] = math.b2(t, this._v0[1], this._v1[1], this._v2[1]); + vector[2] = math.b2(t, this._v0[2], this._v1[2], this._v2[2]); + return vector; } - _buildShader() { + getJSON() { return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() + v0: this._v0, + v1: this._v1, + v2: this._v2, + t: this._t }; } +} - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles instancing edges vertex shader"); - - src.push("uniform int renderPass;"); - src.push("uniform vec4 color;"); - src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } - - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } +/** + * @desc Abstract base class for buildable 3D scene model classes. + * + * Defines methods to build geometries, textures, meshes and entities within the model. + * + * Implementations: + * + * * {@link VBOSceneModel} - WebGL2-based model representation that stores geometry as vertex buffer objects (VBOs). + * + * @interface + * @abstract + */ +class SceneModel { - src.push("out vec4 vColor;"); + /** + * Returns the {@link Entity}s in this SceneModel. + * @returns {*|{}} + * @abstract + */ + get objects() { + } - src.push("void main(void) {"); + /** + * Gets the 3D World-space origin for this SceneModel. + * + * Each geometry or mesh origin, if supplied, is relative to this origin. + * + * Default value is ````[0,0,0]````. + * + * @type {Float64Array} + * @abstract + * @abstract + */ + get origin() { + } - // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - // renderPass = EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED + /** + * Gets the SceneModel's local translation. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + * @abstract + */ + get position() { + } - src.push(`if (int(flags.z) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + /** + * Gets the SceneModel's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + * @abstract + */ + get rotation() { + } - src.push("} else {"); - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); - } - src.push("gl_Position = clipPos;"); - src.push("vColor = vec4(color.r, color.g, color.b, color.a);"); - src.push("}"); - src.push("}"); - return src; + /** + * Gets the SceneModels's local rotation quaternion. + * + * Default value is ````[0,0,0,1]````. + * + * @type {Number[]} + * @abstract + */ + get quaternion() { } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry edges drawing fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); - } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } - } - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push("}"); - } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push("outColor = vColor;"); - src.push("}"); - return src; + /** + * Gets the SceneModel's local scale. + * + * Default value is ````[1,1,1]````. + * + * @type {Number[]} + * @abstract + */ + get scale() { } - webglContextRestored() { - this._program = null; + /** + * Gets the SceneModel's local modeling transform matrix. + * + * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. + * + * @type {Number[]} + * @abstract + */ + get matrix() { } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; + /** + * Gets the SceneModel's World matrix. + * + * @property worldMatrix + * @type {Number[]} + * @abstract + */ + get worldMatrix() { } -} -const tempVec3a$C = math.vec3(); + /** + * Gets the SceneModel's World normal matrix. + * + * @type {Number[]} + * @abstract + */ + get worldNormalMatrix() { + } -/** - * @private - */ -class TrianglesInstancingEdgesColorRenderer { + /** + * Called by private renderers in ./lib, returns the view matrix with which to + * render this SceneModel. The view matrix is the concatenation of the + * Camera view matrix with the Performance model's world (modeling) matrix. + * + * @private + * @abstract + */ + get viewMatrix() { + } - constructor(scene) { - this._scene = scene; - this._hash = this._getHash(); - this._allocate(); + /** + * Called by private renderers in ./lib, returns the view normal matrix with which to render this SceneModel. + * + * @private + * @abstract + */ + get viewNormalMatrix() { } - getValid() { - return this._hash === this._getHash(); - }; + /** + * Sets if backfaces are rendered for this SceneModel. + * + * Default is ````false````. + * + * @type {Boolean} + * @abstract + */ + get backfaces() { + } - _getHash() { - return this._scene._sectionPlanesState.getHash(); + /** + * Sets if backfaces are rendered for this SceneModel. + * + * Default is ````false````. + * + * When we set this ````true````, then backfaces are always rendered for this SceneModel. + * + * When we set this ````false````, then we allow the Viewer to decide whether to render backfaces. In this case, + * the Viewer will: + * + * * hide backfaces on watertight meshes, + * * show backfaces on open meshes, and + * * always show backfaces on meshes when we slice them open with {@link SectionPlane}s. + * + * @type {Boolean} + * @abstract + */ + set backfaces(backfaces) { } - drawLayer(frameCtx, instancingLayer, renderPass) { + /** + * Gets the list of {@link Entity}s within this SceneModel. + * + * @returns {Entity[]} + * @abstract + */ + get entityList() { + } - const model = instancingLayer.model; - const scene = model.scene; - const camera = scene.camera; - const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + /** + * Returns true to indicate that SceneModel is an {@link Entity}. + * @type {Boolean} + * @abstract + */ + get isEntity() { + } - if (!this._program) { - this._allocate(instancingLayer); - if (this.errors) { - return; - } - } + /** + * Returns ````true```` if this SceneModel represents a model. + * + * When ````true```` the SceneModel will be registered by {@link SceneModel#id} in + * {@link Scene#models} and may also have a {@link MetaObject} with matching {@link MetaObject#id}. + * + * @type {Boolean} + * @abstract + */ + get isModel() { + } - if (frameCtx.lastProgramId !== this._program.id) { - frameCtx.lastProgramId = this._program.id; - this._bindProgram(); - } + /** + * Returns ````false```` to indicate that SceneModel never represents an object. + * + * @type {Boolean} + * @abstract + */ + get isObject() { + } - gl.uniform1i(this._uRenderPass, renderPass); + /** + * Gets the SceneModel's World-space 3D axis-aligned bounding box. + * + * Represented by a six-element Float64Array containing the min/max extents of the + * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. + * + * @type {Number[]} + * @abstract + */ + get aabb() { + } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + /** + * The approximate number of triangle primitives in this SceneModel. + * + * @type {Number} + * @abstract + */ + get numTriangles() { + } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; - if (numSectionPlanes > 0) { - const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; - const renderFlags = model.renderFlags; - for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { - const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$C); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); - } - } - } - } + /** + * The approximate number of line primitives in this SceneModel. + * + * @type {Number} + * @abstract + */ + get numLines() { + } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); + /** + * The approximate number of point primitives in this SceneModel. + * + * @type {Number} + * @abstract + */ + get numPoints() { + } - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + /** + * Gets if any {@link Entity}s in this SceneModel are visible. + * + * The SceneModel is only rendered when {@link SceneModel#visible} is ````true```` and {@link SceneModel#culled} is ````false````. + * + * @type {Boolean} + * @abstract + */ + get visible() { + } - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + /** + * Sets if this SceneModel is visible. + * + * The SceneModel is only rendered when {@link SceneModel#visible} is ````true```` and {@link SceneModel#culled} is ````false````. + ** + * @type {Boolean} + * @abstract + */ + set visible(visible) { + } - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + /** + * Gets if any {@link Entity}s in this SceneModel are xrayed. + * + * @type {Boolean} + * @abstract + */ + get xrayed() { + } - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); + /** + * Sets if all {@link Entity}s in this SceneModel are xrayed. + * + * @type {Boolean} + * @abstract + */ + set xrayed(xrayed) { + } - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); - gl.vertexAttribDivisor(this._aFlags.location, 1); - } + /** + * Gets if any {@link Entity}s in this SceneModel are highlighted. + * + * @type {Boolean} + * @abstract + */ + get highlighted() { + } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } + /** + * Sets if all {@link Entity}s in this SceneModel are highlighted. + * + * @type {Boolean} + * @abstract + */ + set highlighted(highlighted) { + } - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } + /** + * Gets if any {@link Entity}s in this SceneModel are selected. + * + * @type {Boolean} + * @abstract + */ + get selected() { + } - geometry.edgeIndicesBuf.bind(); + /** + * Sets if all {@link Entity}s in this SceneModel are selected. + * + * @type {Boolean} + * @abstract + */ + set selected(selected) { + } - gl.drawElementsInstanced(gl.LINES, geometry.edgeIndicesBuf.numItems, geometry.edgeIndicesBuf.itemType, 0, state.numInstances); + /** + * Gets if any {@link Entity}s in this SceneModel have edges emphasised. + * + * @type {Boolean} + * @abstract + */ + get edges() { + } - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); + /** + * Sets if all {@link Entity}s in this SceneModel have edges emphasised. + * + * @type {Boolean} + * @abstract + */ + set edges(edges) { + } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + /** + * Gets if this SceneModel is culled from view. + * + * The SceneModel is only rendered when {@link SceneModel#visible} is true and {@link SceneModel#culled} is false. + * + * @type {Boolean} + * @abstract + */ + get culled() { + } - if (this._aFlags) { - gl.vertexAttribDivisor(this._aFlags.location, 0); - } + /** + * Sets if this SceneModel is culled from view. + * + * The SceneModel is only rendered when {@link SceneModel#visible} is true and {@link SceneModel#culled} is false. + * + * @type {Boolean} + * @abstract + */ + set culled(culled) { + } - if (this._aFlags2) { - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } + /** + * Gets if {@link Entity}s in this SceneModel are clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * @type {Boolean} + * @abstract + */ + get clippable() { } - _allocate() { - const scene = this._scene; - const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + /** + * Sets if {@link Entity}s in this SceneModel are clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * @type {Boolean} + * @abstract + */ + set clippable(clippable) { + } - this._program = new Program(gl, this._buildShader()); + /** + * Gets if this SceneModel is collidable. + * + * @type {Boolean} + * @abstract + */ + get collidable() { + } - if (this._program.errors) { - this.errors = this._program.errors; - return; - } + /** + * Sets if {@link Entity}s in this SceneModel are collidable. + * + * @type {Boolean} + * @abstract + */ + set collidable(collidable) { + } - const program = this._program; + /** + * Gets if this SceneModel is pickable. + * + * Picking is done via calls to {@link Scene#pick}. + * + * @type {Boolean} + * @abstract + */ + get pickable() { + } - this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; + /** + * Sets if {@link Entity}s in this SceneModel are pickable. + * + * Picking is done via calls to {@link Scene#pick}. + * + * @type {Boolean} + * @abstract + */ + set pickable(pickable) { + } - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { - this._uSectionPlanes.push({ - active: program.getLocation("sectionPlaneActive" + i), - pos: program.getLocation("sectionPlanePos" + i), - dir: program.getLocation("sectionPlaneDir" + i) - }); - } + /** + * Gets the RGB colorize color for this SceneModel. + * + * Each element of the color is in range ````[0..1]````. + * + * @type {Number[]} + * @abstract + */ + get colorize() { + } - this._aPosition = program.getAttribute("position"); - this._aColor = program.getAttribute("color"); - this._aOffset = program.getAttribute("offset"); - this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + /** + * Sets the RGB colorize color for this SceneModel. + * + * Multiplies by rendered fragment colors. + * + * Each element of the color is in range ````[0..1]````. + * + * @type {Number[]} + * @abstract + */ + set colorize(colorize) { + } - if ( scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } + /** + * Gets this SceneModel's opacity factor. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + * @abstract + */ + get opacity() { } - _bindProgram() { + /** + * Sets the opacity factor for this SceneModel. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + * @abstract + */ + set opacity(opacity) { + } - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; + /** + * Gets if this SceneModel casts a shadow. + * + * @type {Boolean} + * @abstract + */ + get castsShadow() { + } - this._program.bind(); + /** + * Sets if this SceneModel casts a shadow. + * + * @type {Boolean} + * @abstract + */ + set castsShadow(castsShadow) { + } - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + /** + * Sets if this SceneModel can have shadow cast upon it. + * + * @type {Boolean} + * @abstract + */ + get receivesShadow() { + } - if ( scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + /** + * Sets if this SceneModel can have shadow cast upon it. + * + * @type {Boolean} + * @abstract + */ + set receivesShadow(receivesShadow) { } - _buildShader() { - return { - vertex: this._buildVertexShader(), - fragment: this._buildFragmentShader() - }; + /** + * Gets if Scalable Ambient Obscurance (SAO) will apply to this SceneModel. + * + * SAO is configured by the Scene's {@link SAO} component. + * + * Only works when {@link SAO#enabled} is also true. + * + * @type {Boolean} + * @abstract + */ + get saoEnabled() { } - _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Triangles instancing edges vertex shader"); - - src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - src.push("in vec4 color;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 positionsDecodeMatrix;"); + /** + * Gets if physically-based rendering (PBR) is enabled for this SceneModel. + * + * Only works when {@link Scene#pbrEnabled} is also true. + * + * @type {Boolean} + * @abstract + */ + get pbrEnabled() { + } - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - src.push("bool isPerspectiveMatrix(mat4 m) {"); - src.push(" return (m[2][3] == - 1.0);"); - src.push("}"); - src.push("out float isPerspective;"); - } + /** + * Gets if color textures are enabled for this SceneModel. + * + * Only works when {@link Scene#colorTextureEnabled} is also true. + * + * @type {Boolean} + * @abstract + */ + get colorTextureEnabled() { + } - if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - } + /** + * Returns true to indicate that SceneModel is implements {@link Drawable}. + * + * @type {Boolean} + * @abstract + */ + get isDrawable() { + } - src.push("out vec4 vColor;"); + /** @private + * @abstract + */ + get isStateSortable() { + } - src.push("void main(void) {"); + /** + * Configures the appearance of xrayed {@link Entity}s within this SceneModel. + * + * This is the {@link Scene#xrayMaterial}. + * + * @type {EmphasisMaterial} + * @abstract + */ + get xrayMaterial() { + } - // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - // renderPass = EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED + /** + * Configures the appearance of highlighted {@link Entity}s within this SceneModel. + * + * This is the {@link Scene#highlightMaterial}. + * + * @type {EmphasisMaterial} + * @abstract + */ + get highlightMaterial() { + } - src.push(`if (int(flags.z) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + /** + * Configures the appearance of selected {@link Entity}s within this SceneModel. + * + * This is the {@link Scene#selectedMaterial}. + * + * @type {EmphasisMaterial} + * @abstract + */ + get selectedMaterial() { + } - src.push("} else {"); - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + /** + * Configures the appearance of edges of {@link Entity}s within this SceneModel. + * + * This is the {@link Scene#edgeMaterial}. + * + * @type {EdgeMaterial} + * @abstract + */ + get edgeMaterial() { + } + + /** + * Called by private renderers in ./lib, returns the picking view matrix with which to + * ray-pick on this SceneModel. + * + * @private + * @abstract + */ + getPickViewMatrix(pickViewMatrix) { + } + + /** + * Creates a reusable geometry within this SceneModel. + * + * We can then supply the geometry ID to {@link SceneModel#createMesh} when we want to create meshes that instance the geometry. + * + * @param {*} cfg Geometry properties. + * @param {String|Number} cfg.id Mandatory ID for the geometry, to refer to with {@link SceneModel#createMesh}. + * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. + * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. + * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. + * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. + * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. + * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. + * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. + * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. + * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````SceneModel```` constructor. + * @param {Number[]} [cfg.origin] Optional geometry origin, relative to {@link SceneModel#origin}. When this is given, then ````positions```` are assumed to be relative to this. + * @abstract + */ + createGeometry(cfg) { + } + + /** + * Creates a texture within this SceneModel. + * + * We can then supply the texture ID to {@link SceneModel#createTextureSet} when we want to create texture sets that use the texture. + * + * @param {*} cfg Texture properties. + * @param {String|Number} cfg.id Mandatory ID for the texture, to refer to with {@link VBOSceneModel#createTextureSet}. + * @param {String} [cfg.src] Image file for the texture. Assumed to be transcoded if not having a recognized image file + * extension (jpg, jpeg, png etc.). If transcoded, then assumes ````VBOSceneModel```` is configured with a {@link TextureTranscoder}. + * @param {ArrayBuffer[]} [cfg.buffers] Transcoded texture data. Assumes ````VBOSceneModel```` is + * configured with a {@link TextureTranscoder}. This parameter is given as an array of buffers so we can potentially support multi-image textures, such as cube maps. + * @param {HTMLImageElement} [cfg.image] HTML Image object to load into this texture. Overrides ````src```` and ````buffers````. Never transcoded. + * @param {Number} [cfg.minFilter=LinearMipmapLinearFilter] How the texture is sampled when a texel covers less than one pixel. + * Supported values are {@link LinearMipmapLinearFilter}, {@link LinearMipMapNearestFilter}, {@link NearestMipMapNearestFilter}, {@link NearestMipMapLinearFilter} and {@link LinearMipMapLinearFilter}. + * @param {Number} [cfg.magFilter=LinearFilter] How the texture is sampled when a texel covers more than one pixel. Supported values are {@link LinearFilter} and {@link NearestFilter}. + * @param {Number} [cfg.wrapS=RepeatWrapping] Wrap parameter for texture coordinate *S*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. + * @param {Number} [cfg.wrapT=RepeatWrapping] Wrap parameter for texture coordinate *T*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. + * @param {Number} [cfg.wrapR=RepeatWrapping] Wrap parameter for texture coordinate *R*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. + * @param {Boolean} [cfg.flipY=false] Flips this Texture's source data along its vertical axis when ````true````. + * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. + * @abstract + */ + createTexture(cfg) { + } + + /** + * Creates a texture set within this SceneModel. + * + * A texture set is a collection of textures that can be shared among meshes. We can then supply the texture set + * ID to {@link SceneModel#createMesh} when we want to create meshes that use the texture set. + * + * The textures can work as a texture atlas, where each mesh can have geometry UVs that index + * a different part of the textures. This allows us to minimize the number of textures in our models, which + * means faster rendering. + * + * @param {*} cfg Texture set properties. + * @param {String|Number} cfg.id Mandatory ID for the texture set, to refer to with {@link SceneModel#createMesh}. + * @param {*} [cfg.colorTextureId] ID of *RGBA* base color texture, with color in *RGB* and alpha in *A*. + * @param {*} [cfg.metallicRoughnessTextureId] ID of *RGBA* metal-roughness texture, with the metallic factor in *R*, and roughness factor in *G*. + * @param {*} [cfg.normalsTextureId] ID of *RGBA* normal map texture, with normal map vectors in *RGB*. + * @param {*} [cfg.emissiveTextureId] ID of *RGBA* emissive map texture, with emissive color in *RGB*. + * @param {*} [cfg.occlusionTextureId] ID of *RGBA* occlusion map texture, with occlusion factor in *R*. + * @abstract + */ + createTextureSet(cfg) { + } + + /** + * Creates a mesh within this SceneModel. + * + * A mesh can either define its own geometry or share it with other meshes. To define own geometry, provide the + * various geometry arrays to this method. To share a geometry, provide the ID of a geometry created earlier + * with {@link SceneModel#createGeometry}. + * + * Internally, SceneModel will batch all unique mesh geometries into the same arrays, which improves + * rendering performance. + * + * If you accompany the arrays with an ````origin````, then ````createMesh()```` will assume + * that the ````positions```` are in relative-to-center (RTC) coordinates, with ````origin```` being the origin of their + * RTC coordinate system. + * + * @param {object} cfg Object properties. + * @param {String} cfg.id Mandatory ID for the new mesh. Must not clash with any existing components within the {@link Scene}. + * @param {String|Number} [cfg.textureSetId] ID of a texture set previously created with {@link SceneModel#createTextureSet"}. + * @param {String|Number} [cfg.geometryId] ID of a geometry to instance, previously created with {@link SceneModel#createGeometry"}. Overrides all other geometry parameters given to this method. + * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. + * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. + * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. + * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. + * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. + * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. + * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. + * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. + * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````SceneModel```` constructor. + * @param {Number[]} [cfg.origin] Optional geometry origin, relative to {@link SceneModel#origin}. When this is given, then ````positions```` are assumed to be relative to this. + * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position of the mesh. + * @param {Number[]} [cfg.scale=[1,1,1]] Scale of the mesh. + * @param {Number[]} [cfg.rotation=[0,0,0]] Rotation of the mesh as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Mesh modelling transform matrix. Overrides the ````position````, ````scale```` and ````rotation```` parameters. + * @param {Number[]} [cfg.color=[1,1,1]] RGB color in range ````[0..1, 0..1, 0..1]````. Overridden by texture set ````colorTexture````. Overrides ````colors```` and ````colorsCompressed````. + * @param {Number} [cfg.opacity=1] Opacity in range ````[0..1]````. Overridden by texture set ````colorTexture````. + * @param {Number} [cfg.metallic=0] Metallic factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. + * @param {Number} [cfg.roughness=1] Roughness factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. + * @abstract + */ + createMesh(cfg) { + } + + /** + * Creates an {@link Entity} within this SceneModel, giving it one or more meshes previously created with {@link SceneModel#createMesh}. + * + * A mesh can only belong to one {@link Entity}, so you'll get an error if you try to reuse a mesh among multiple {@link Entity}s. + * + * @param {Object} cfg Entity configuration. + * @param {String} cfg.id Optional ID for the new Entity. Must not clash with any existing components within the {@link Scene}. + * @param {String[]} cfg.meshIds IDs of one or more meshes created previously with {@link SceneModel@createMesh}. + * @param {Boolean} [cfg.isObject] Set ````true```` if the {@link Entity} represents an object, in which case it will be registered by {@link Entity#id} in {@link Scene#objects} and can also have a corresponding {@link MetaObject} with matching {@link MetaObject#id}, registered by that ID in {@link MetaScene#metaObjects}. + * @param {Boolean} [cfg.visible=true] Indicates if the Entity is initially visible. + * @param {Boolean} [cfg.culled=false] Indicates if the Entity is initially culled from view. + * @param {Boolean} [cfg.pickable=true] Indicates if the Entity is initially pickable. + * @param {Boolean} [cfg.clippable=true] Indicates if the Entity is initially clippable. + * @param {Boolean} [cfg.collidable=true] Indicates if the Entity is initially included in boundary calculations. + * @param {Boolean} [cfg.castsShadow=true] Indicates if the Entity initially casts shadows. + * @param {Boolean} [cfg.receivesShadow=true] Indicates if the Entity initially receives shadows. + * @param {Boolean} [cfg.xrayed=false] Indicates if the Entity is initially xrayed. XRayed appearance is configured by {@link SceneModel#xrayMaterial}. + * @param {Boolean} [cfg.highlighted=false] Indicates if the Entity is initially highlighted. Highlighted appearance is configured by {@link SceneModel#highlightMaterial}. + * @param {Boolean} [cfg.selected=false] Indicates if the Entity is initially selected. Selected appearance is configured by {@link SceneModel#selectedMaterial}. + * @param {Boolean} [cfg.edges=false] Indicates if the Entity's edges are initially emphasized. Edges appearance is configured by {@link SceneModel#edgeMaterial}. + * @returns {Entity} + * @abstract + */ + createEntity(cfg) { + } + + /** + * Finalizes this SceneModel. + * + * Immediately creates the SceneModel's {@link Entity}s within the {@link Scene}. + * + * Once finalized, you can't add anything more to this SceneModel. + * @abstract + */ + finalize() { + } + + /** @private + * @abstract + */ + stateSortCompare(drawable1, drawable2) { + } + + /** @private + * @abstract + */ + drawColorOpaque(frameCtx) { + } + + /** @private + * @abstract + */ + drawColorTransparent(frameCtx) { + } + + /** @private + * @abstract + */ + drawDepth(frameCtx) { + } + + /** @private + * @abstract + */ + drawNormals(frameCtx) { + } + + /** @private + * @abstract + */ + drawSilhouetteXRayed(frameCtx) { + } + + /** @private + * @abstract + */ + drawSilhouetteHighlighted(frameCtx) { + } + + /** @private + * @abstract + */ + drawSilhouetteSelected(frameCtx) { + } + + /** @private + * @abstract + */ + drawEdgesColorOpaque(frameCtx) { + } + + /** @private + * @abstract + */ + drawEdgesColorTransparent(frameCtx) { + } + + /** @private + * @abstract + */ + drawEdgesXRayed(frameCtx) { + } + + /** @private + * @abstract + */ + drawEdgesHighlighted(frameCtx) { + } + + /** @private + * @abstract + */ + drawEdgesSelected(frameCtx) { + } + + /** + * @private + * @abstract + */ + drawOcclusion(frameCtx) { + } + + /** + * @private + * @abstract + */ + drawShadow(frameCtx) { + } + + /** @private + * @abstract + */ + drawPickMesh(frameCtx) { + } + + /** + * Called by VBOSceneModelMesh.drawPickDepths() + * @private + * @abstract + */ + drawPickDepths(frameCtx) { + } + + /** + * Called by VBOSceneModelMesh.drawPickNormals() + * @private + * @abstract + */ + drawPickNormals(frameCtx) { + } + + /** + * Destroys this SceneModel. + * @abstract + */ + destroy() { + } +} + +/** + * @private + * @implements Pickable + */ +class VBOSceneModelMesh { + + constructor(model, id, color, opacity, layer = null, portionId = 0) { + + /** + * The VBOSceneModel that contains this PerformanceModelMesh. + * + * A PerformanceModelMesh always belongs to exactly one VBOSceneModel. + * + * @property model + * @type {VBOSceneModel} + * @final + */ + this.model = model; + + /** + * The VBOSceneModelNode that contains this PerformanceModelMesh. + * + * A PerformanceModelMesh always belongs to exactly one VBOSceneModelNode. + * + * @property object + * @type {VBOSceneModelNode} + * @final + */ + this.object = null; + + /** + * The VBOSceneModelNode that contains this PerformanceModelMesh. + * + * A PerformanceModelMesh always belongs to exactly one VBOSceneModelNode. + * + * @property object + * @type {VBOSceneModelNode} + * @final + */ + this.parent = null; + + /** + * ID of this PerformanceModelMesh, unique within the xeokit.Scene. + * + * @property id + * @type {String} + * @final + */ + this.id = id; + + /** + * + * @type {Number} + * @private + */ + this.pickId = this.model.scene._renderer.getPickID(this); + + /** + * World-space 3D axis-aligned bounding box (AABB). + * + * Represented by a six-element Float64Array containing the min/max extents of the + * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. + * + * @property aabb + * @final + * @type {Float64Array} + */ + this.aabb = math.AABB3(); + + this._layer = layer; + this._portionId = portionId; + + this._color = [color[0], color[1], color[2], opacity]; // [0..255] + this._colorize = [color[0], color[1], color[2], opacity]; // [0..255] + this._colorizing = false; + + this._transparent = (opacity < 255); + + this.numTriangles = 0; + + /** + * 3D origin of the VBOSceneModelMesh's vertex positions, if they are in relative-to-center (RTC) coordinates. + * + * When this is defined, then the positions are RTC, which means that they are relative to this position. + * + * @property origin + * @type {Float64Array} + */ + this.origin = null; + } + + /** + * @private + */ + _finalize(entityFlags) { + this._layer.initFlags(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _finalize2() { + if (this._layer.flushInitFlags) { + this._layer.flushInitFlags(); } - src.push("gl_Position = clipPos;"); - // src.push("vColor = vec4(float(color.r-100.0) / 255.0, float(color.g-100.0) / 255.0, float(color.b-100.0) / 255.0, float(color.a) / 255.0);"); - src.push("vColor = vec4(float(color.r*0.5) / 255.0, float(color.g*0.5) / 255.0, float(color.b*0.5) / 255.0, float(color.a) / 255.0);"); - src.push("}"); - src.push("}"); - return src; } - _buildFragmentShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push("#version 300 es"); - src.push("// Batched geometry edges drawing fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); - src.push("precision highp float;"); - src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("in float isPerspective;"); - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + /** + * @private + */ + _setVisible(entityFlags) { + this._layer.setVisible(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _setColor(color) { + this._color[0] = color[0]; + this._color[1] = color[1]; + this._color[2] = color[2]; + if (!this._colorizing) { + this._layer.setColor(this._portionId, this._color, false); } - if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("uniform bool sectionPlaneActive" + i + ";"); - src.push("uniform vec3 sectionPlanePos" + i + ";"); - src.push("uniform vec3 sectionPlaneDir" + i + ";"); - } + } + + /** @private */ + _setColorize(colorize) { + const setOpacity = false; + if (colorize) { + this._colorize[0] = colorize[0]; + this._colorize[1] = colorize[1]; + this._colorize[2] = colorize[2]; + this._layer.setColor(this._portionId, this._colorize, setOpacity); + this._colorizing = true; + } else { + this._layer.setColor(this._portionId, this._color, setOpacity); + this._colorizing = false; } - src.push("in vec4 vColor;"); - src.push("out vec4 outColor;"); - src.push("void main(void) {"); - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - src.push(" if (dist > 0.0) { discard; }"); - src.push("}"); + } + + /** @private */ + _setOpacity(opacity, entityFlags) { + const newTransparent = (opacity < 255); + const lastTransparent = this._transparent; + const changingTransparency = (lastTransparent !== newTransparent); + this._color[3] = opacity; + this._colorize[3] = opacity; + this._transparent = newTransparent; + if (this._colorizing) { + this._layer.setColor(this._portionId, this._colorize); + } else { + this._layer.setColor(this._portionId, this._color); } - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + if (changingTransparency) { + this._layer.setTransparent(this._portionId, entityFlags, newTransparent); } - src.push("outColor = vColor;"); - src.push("}"); - return src; } - webglContextRestored() { - this._program = null; + /** + * @private + */ + _setOffset(offset) { + this._layer.setOffset(this._portionId, offset); } - destroy() { - if (this._program) { - this._program.destroy(); + /** + * @private + */ + _setHighlighted(entityFlags) { + this._layer.setHighlighted(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _setXRayed(entityFlags) { + this._layer.setXRayed(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _setSelected(entityFlags) { + this._layer.setSelected(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _setEdges(entityFlags) { + this._layer.setEdges(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _setClippable(entityFlags) { + this._layer.setClippable(this._portionId, entityFlags, this._transparent); + } + + /** + * @private + */ + _setCollidable(entityFlags) { + this._layer.setCollidable(this._portionId, entityFlags); + } + + /** + * @private + */ + _setPickable(flags) { + this._layer.setPickable(this._portionId, flags, this._transparent); + } + + /** + * @private + */ + _setCulled(flags) { + this._layer.setCulled(this._portionId, flags, this._transparent); + } + + /** @private */ + canPickTriangle() { + return false; + } + + /** @private */ + drawPickTriangles(renderFlags, frameCtx) { + // NOP + } + + /** @private */ + pickTriangleSurface(pickResult) { + // NOP + } + + /** @private */ + precisionRayPickSurface(worldRayOrigin, worldRayDir, worldSurfacePos, worldSurfaceNormal) { + return this._layer.precisionRayPickSurface ? this._layer.precisionRayPickSurface(this._portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldSurfaceNormal) : false; + } + + /** @private */ + canPickWorldPos() { + return true; + } + + /** @private */ + drawPickDepths(frameCtx) { + this.model.drawPickDepths(frameCtx); + } + + /** @private */ + drawPickNormals(frameCtx) { + this.model.drawPickNormals(frameCtx); + } + + /** + * @private + * @returns {VBOSceneModelNode} + */ + delegatePickedEntity() { + return this.parent; + } + + /** + * @private + */ + _destroy() { + this.model.scene._renderer.putPickID(this.pickId); + } +} + +/** + * Provides scratch memory for methods like TrianglesBatchingLayer setFlags() and setColors(), + * so they don't need to allocate temporary arrays that need garbage collection. + * + * @private + */ +class ScratchMemory { + + constructor() { + this._uint8Arrays = {}; + this._float32Arrays = {}; + } + + _clear() { + this._uint8Arrays = {}; + this._float32Arrays = {}; + } + + getUInt8Array(len) { + let uint8Array = this._uint8Arrays[len]; + if (!uint8Array) { + uint8Array = new Uint8Array(len); + this._uint8Arrays[len] = uint8Array; } - this._program = null; + return uint8Array; + } + + getFloat32Array(len) { + let float32Array = this._float32Arrays[len]; + if (!float32Array) { + float32Array = new Float32Array(len); + this._float32Arrays[len] = float32Array; + } + return float32Array; } } -const tempVec3a$B = math.vec3(); +const batchingLayerScratchMemory = new ScratchMemory(); + +let countUsers = 0; /** * @private */ -class TrianglesInstancingPickMeshRenderer { +function getScratchMemory() { + countUsers++; + return batchingLayerScratchMemory; +} - constructor(scene) { +/** + * @private + */ +function putScratchMemory() { + if (countUsers === 0) { + return; + } + countUsers--; + if (countUsers === 0) { + batchingLayerScratchMemory._clear(); + } +} + +/** + * @private + */ +const RENDER_PASSES = { + + // Skipped - suppress rendering + + NOT_RENDERED: 0, + + // Normal rendering - mutually exclusive modes + + COLOR_OPAQUE: 1, + COLOR_TRANSPARENT: 2, + + // Emphasis silhouette rendering - mutually exclusive modes + + SILHOUETTE_HIGHLIGHTED: 3, + SILHOUETTE_SELECTED: 4, + SILHOUETTE_XRAYED: 5, + + // Edges rendering - mutually exclusive modes + + EDGES_COLOR_OPAQUE: 6, + EDGES_COLOR_TRANSPARENT: 7, + EDGES_HIGHLIGHTED: 8, + EDGES_SELECTED: 9, + EDGES_XRAYED: 10, + + // Picking + + PICK: 11 +}; + +const tempVec4$7 = math.vec4(); +const tempVec3a$V = math.vec3(); + +/** + * @private + */ +class TrianglesBatchingColorRenderer { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); - this._allocate(); } @@ -49999,18 +53132,18 @@ class TrianglesInstancingPickMeshRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash(); + const scene = this._scene; + return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; - const scene = model.scene; + const scene = this._scene; const camera = scene.camera; + const model = batchingLayer.model; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { this._allocate(); @@ -50026,53 +53159,16 @@ class TrianglesInstancingPickMeshRenderer { gl.uniform1i(this._uRenderPass, renderPass); - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aPickColor.bindArrayBuffer(state.pickColorsBuf); - gl.vertexAttribDivisor(this._aPickColor.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - geometry.indicesBuf.bind(); + gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -50082,7 +53178,7 @@ class TrianglesInstancingPickMeshRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$B); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$V); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -50093,30 +53189,42 @@ class TrianglesInstancingPickMeshRenderer { } } - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - // Cleanup + this._aPosition.bindArrayBuffer(state.positionsBuf); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aPickColor.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aNormal) { + this._aNormal.bindArrayBuffer(state.normalsBuf); + } - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); + } + + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); + this._aOffset.bindArrayBuffer(state.offsetsBuf); } + + state.indicesBuf.bind(); + + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + + frameCtx.drawElements++; } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -50127,16 +53235,49 @@ class TrianglesInstancingPickMeshRenderer { const program = this._program; - this._uPickInvisible = program.getLocation("pickInvisible"); + this._uRenderPass = program.getLocation("renderPass"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); + this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; - for (let i = 0, len = clips.length; i < len; i++) { + const lights = lightsState.lights; + let light; + + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + + this._uSectionPlanes = []; + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -50144,15 +53285,17 @@ class TrianglesInstancingPickMeshRenderer { }); } - this._uRenderPass = program.getLocation("renderPass"); this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aPickColor = program.getAttribute("pickColor"); + this._aNormal = program.getAttribute("normal"); + this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + + if (this._withSAO) { + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); + } if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); @@ -50164,10 +53307,54 @@ class TrianglesInstancingPickMeshRenderer { const scene = this._scene; const gl = scene.canvas.gl; const program = this._program; + const lights = scene._lightsState.lights; + const project = scene.camera.project; program.bind(); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + + const light = lights[i]; + + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$7[0] = viewportWidth; + tempVec4$7[1] = viewportHeight; + tempVec4$7[2] = sao.blendCutoff; + tempVec4$7[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$7); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + } + } + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } _buildShader() { @@ -50180,28 +53367,31 @@ class TrianglesInstancingPickMeshRenderer { _buildVertexShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; const clipping = sectionPlanesState.sectionPlanes.length > 0; + let light; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry picking vertex shader"); - + src.push("// Triangles batching draw vertex shader"); + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } + src.push("in vec3 normal;"); + src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 pickColor;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } - src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 worldNormalMatrix;"); + src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); if (scene.logarithmicDepthBufferEnabled) { @@ -50213,42 +53403,109 @@ class TrianglesInstancingPickMeshRenderer { src.push("out float isPerspective;"); } + src.push("uniform vec4 lightAmbient;"); + + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + + src.push("vec3 octDecode(vec2 oct) {"); + src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); + src.push(" if (v.z < 0.0) {"); + src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); + src.push(" }"); + src.push(" return normalize(v);"); + src.push("}"); + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vPickColor;"); + src.push("out vec4 vColor;"); + src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - src.push(`if (int(flags.w) != renderPass) {`); + src.push(`if (int(flags.x) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + src.push("worldPosition.xyz = worldPosition.xyz + offset;"); } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); - src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); + src.push("vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); + + src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); + src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + + src.push("float lambertian = 1.0;"); + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); + } else { + src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } + src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); + src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); } + + src.push("vec3 rgb = (vec3(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0));"); + src.push("vColor = vec4((lightAmbient.rgb * lightAmbient.a * rgb) + (reflectedColor * rgb), float(color.a) / 255.0);"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } src.push("gl_Position = clipPos;"); src.push("}"); + src.push("}"); return src; } @@ -50259,8 +53516,7 @@ class TrianglesInstancingPickMeshRenderer { const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Batched geometry picking fragment shader"); - + src.push("// Triangles batching draw fragment shader"); src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -50268,39 +53524,71 @@ class TrianglesInstancingPickMeshRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); + } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vPickColor;"); + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); src.push("}"); } + if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push("outColor = vPickColor; "); + + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" outColor = vec4(vColor.rgb * ambient, 1.0);"); + } else { + src.push(" outColor = vColor;"); + } + src.push("}"); return src; } @@ -50317,15 +53605,17 @@ class TrianglesInstancingPickMeshRenderer { } } -const tempVec3a$A = math.vec3(); +const tempVec4$6 = math.vec4(); +const tempVec3a$U = math.vec3(); /** * @private */ -class TrianglesInstancingPickDepthRenderer { +class TrianglesBatchingFlatColorRenderer { - constructor(scene) { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -50335,20 +53625,21 @@ class TrianglesInstancingPickDepthRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash(); + const scene = this._scene; + return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; - const scene = model.scene; + const scene = this._scene; + const camera = scene.camera; + const model = batchingLayer.model; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(instancingLayer); + this._allocate(); if (this.errors) { return; } @@ -50356,104 +53647,67 @@ class TrianglesInstancingPickDepthRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx); } - const camera = scene.camera; - gl.uniform1i(this._uRenderPass, renderPass); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - - gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); - gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$A); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$U); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + this._aPosition.bindArrayBuffer(state.positionsBuf); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); + } - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } if (this._aFlags2) { this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); } if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - // Cleanup - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - - gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } + state.indicesBuf.bind(); - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; + const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -50465,11 +53719,43 @@ class TrianglesInstancingPickDepthRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); + + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; + + const lights = lightsState.lights; + let light; + + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -50482,23 +53768,73 @@ class TrianglesInstancingPickDepthRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPickZNear = program.getLocation("pickZNear"); - this._uPickZFar = program.getLocation("pickZFar"); + if (this._withSAO) { + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); + } if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { - this._program.bind(); + _bindProgram(frameCtx) { + + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + const lights = scene._lightsState.lights; + const project = scene.camera.project; + + program.bind(); + + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + + const light = lights[i]; + + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$6[0] = viewportWidth; + tempVec4$6[1] = viewportHeight; + tempVec4$6[2] = sao.blendCutoff; + tempVec4$6[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$6); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + } + } + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } _buildShader() { @@ -50514,25 +53850,21 @@ class TrianglesInstancingPickDepthRenderer { const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry depth vertex shader"); - + src.push("// Triangles batching flat-shading draw vertex shader"); src.push("uniform int renderPass;"); src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - - src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); @@ -50550,49 +53882,52 @@ class TrianglesInstancingPickDepthRenderer { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vViewPosition;"); + src.push("out vec4 vColor;"); + src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - src.push(`if (int(flags.w) != renderPass) {`); + src.push(`if (int(flags.x) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); - } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); + src.push("worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vViewPosition = viewPosition;"); + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vViewPosition = viewPosition;"); + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } src.push("gl_Position = clipPos;"); src.push("}"); + src.push("}"); return src; } _buildFragmentShader() { const scene = this._scene; + const lightsState = scene._lightsState; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Batched geometry depth fragment shader"); - - + src.push("// Triangles batching flat-shading draw fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -50607,45 +53942,132 @@ class TrianglesInstancingPickDepthRenderer { src.push("in float vFragDepth;"); } - src.push("uniform float pickZNear;"); - src.push("uniform float pickZFar;"); + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); + } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } + + src.push("uniform mat4 viewMatrix;"); + + src.push("uniform vec4 lightAmbient;"); + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + src.push("in vec4 vViewPosition;"); - src.push("vec4 packDepth(const in float depth) {"); - src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); - src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); - src.push(" vec4 res = fract(depth * bitShift);"); - src.push(" res -= res.xxyz * bitMask;"); - src.push(" return res;"); - src.push("}"); + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); src.push("}"); } + + src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); + src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + + src.push("float lambertian = 1.0;"); + + src.push("vec3 xTangent = dFdx( vViewPosition.xyz );"); + src.push("vec3 yTangent = dFdy( vViewPosition.xyz );"); + src.push("vec3 viewNormal = normalize( cross( xTangent, yTangent ) );"); + + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); + } else { + src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } + + src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); + src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); + } + + src.push("vec4 fragColor = vec4((lightAmbient.rgb * lightAmbient.a * vColor.rgb) + (reflectedColor * vColor.rgb), vColor.a);"); + + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" outColor = vec4(fragColor.rgb * ambient, 1.0);"); + } else { + src.push(" outColor = fragColor;"); + } + if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); - src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth + src.push("}"); return src; } @@ -50662,14 +54084,15 @@ class TrianglesInstancingPickDepthRenderer { } } -const tempVec3a$z = math.vec3(); +const defaultColor$4 = new Float32Array([1, 1, 1]); +const tempVec3a$T = math.vec3(); /** * @private */ -class TrianglesInstancingPickNormalsRenderer { +class TrianglesBatchingSilhouetteRenderer { - constructor(scene) { + constructor(scene, primitiveType) { this._scene = scene; this._hash = this._getHash(); this._allocate(); @@ -50683,18 +54106,17 @@ class TrianglesInstancingPickNormalsRenderer { return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; + const model = batchingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(instancingLayer); + this._allocate(); if (this.errors) { return; } @@ -50705,31 +54127,39 @@ class TrianglesInstancingPickNormalsRenderer { this._bindProgram(); } - // In practice, these binds will only happen once per frame - // because we pick normals on a single previously-picked mesh - gl.uniform1i(this._uRenderPass, renderPass); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + const material = scene.xrayMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + const material = scene.selectedMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } else { + gl.uniform4fv(this._uColor, defaultColor$4); } + const viewMat = (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMat); + + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -50739,7 +54169,7 @@ class TrianglesInstancingPickNormalsRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$z); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$T); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -50750,66 +54180,31 @@ class TrianglesInstancingPickNormalsRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); - this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); - this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aNormal.bindArrayBuffer(geometry.normalsBuf); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } + this._aPosition.bindArrayBuffer(state.positionsBuf); if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } + + state.indicesBuf.bind(); + + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -50821,17 +54216,14 @@ class TrianglesInstancingPickNormalsRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - + this._uColor = program.getLocation("color"); this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -50841,25 +54233,28 @@ class TrianglesInstancingPickNormalsRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aNormal = program.getAttribute("normal"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - - this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); - this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); - this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); - if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } _bindProgram() { + + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; + this._program.bind(); + + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } _buildShader() { @@ -50870,32 +54265,29 @@ class TrianglesInstancingPickNormalsRenderer { } _buildVertexShader() { + const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry normals vertex shader"); + src.push("// Triangles batching silhouette vertex shader"); src.push("uniform int renderPass;"); + src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec2 normal;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - src.push("in vec4 modelNormalMatrixCol0;"); - src.push("in vec4 modelNormalMatrixCol1;"); - src.push("in vec4 modelNormalMatrixCol2;"); - src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); + src.push("uniform vec4 color;"); + if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); @@ -50904,38 +54296,29 @@ class TrianglesInstancingPickNormalsRenderer { src.push("}"); src.push("out float isPerspective;"); } - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec3 vWorldNormal;"); + src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK + // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | SILHOUETTE_XRAYED + // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - src.push(`if (int(flags.w) != renderPass) {`); + src.push(`if (int(flags.y) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); - src.push(" vec3 worldNormal = vec3(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2));"); - src.push(" vWorldNormal = worldNormal;"); + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { - src.push(" vWorldPosition = worldPosition;"); + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { @@ -50951,13 +54334,13 @@ class TrianglesInstancingPickNormalsRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; + let i; + let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Batched geometry normals fragment shader"); - + src.push("// Triangles batching silhouette fragment shader"); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -50965,41 +54348,39 @@ class TrianglesInstancingPickNormalsRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } - if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec3 vWorldNormal;"); + src.push("uniform vec4 color;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { discard; }"); src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" outColor = vec4((vWorldNormal * 0.5) + 0.5, 1.0);"); + src.push("outColor = color;"); src.push("}"); return src; } @@ -51016,12 +54397,13 @@ class TrianglesInstancingPickNormalsRenderer { } } -const tempVec3a$y = math.vec3(); +const tempVec3a$S = math.vec3(); +const defaultColor$3 = new Float32Array([0,0,0,1]); /** * @private */ -class TrianglesInstancingOcclusionRenderer { +class TrianglesBatchingEdgesRenderer { constructor(scene) { this._scene = scene; @@ -51037,18 +54419,17 @@ class TrianglesInstancingOcclusionRenderer { return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; + const model = batchingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(); + this._allocate(batchingLayer); if (this.errors) { return; } @@ -51061,13 +54442,35 @@ class TrianglesInstancingOcclusionRenderer { gl.uniform1i(this._uRenderPass, renderPass); + if (renderPass === RENDER_PASSES.EDGES_XRAYED) { + const material = scene.xrayMaterial._state; + const edgeColor = material.edgeColor; + const edgeAlpha = material.edgeAlpha; + gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); + + } else if (renderPass === RENDER_PASSES.EDGES_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const edgeColor = material.edgeColor; + const edgeAlpha = material.edgeAlpha; + gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); + + } else if (renderPass === RENDER_PASSES.EDGES_SELECTED) { + const material = scene.selectedMaterial._state; + const edgeColor = material.edgeColor; + const edgeAlpha = material.edgeAlpha; + gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); + + } else { + gl.uniform4fv(this._uColor, defaultColor$3); + } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -51077,7 +54480,7 @@ class TrianglesInstancingOcclusionRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$y); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$S); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -51088,62 +54491,27 @@ class TrianglesInstancingOcclusionRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); - } - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + this._aPosition.bindArrayBuffer(state.positionsBuf); if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } if (this._aFlags2) { this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); } + state.edgeIndicesBuf.bind(); - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - // Cleanup - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - if (this._aColor) { - gl.vertexAttribDivisor(this._aColor.location, 0); - } - gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + gl.drawElements(gl.LINES, state.edgeIndicesBuf.numItems, state.edgeIndicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -51155,14 +54523,14 @@ class TrianglesInstancingOcclusionRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uColor = program.getLocation("color"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -51172,14 +54540,9 @@ class TrianglesInstancingOcclusionRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } @@ -51189,9 +54552,10 @@ class TrianglesInstancingOcclusionRenderer { const scene = this._scene; const gl = scene.canvas.gl; + const program = this._program; const project = scene.camera.project; - this._program.bind(); + program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); @@ -51213,60 +54577,68 @@ class TrianglesInstancingOcclusionRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; + src.push("#version 300 es"); - src.push("// Instancing occlusion vertex shader"); + src.push("// Batched geometry edges drawing vertex shader"); src.push("uniform int renderPass;"); + src.push("uniform vec4 color;"); + src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); + src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); + if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + src.push("out float vFragDepth;"); src.push("bool isPerspectiveMatrix(mat4 m) {"); src.push(" return (m[2][3] == - 1.0);"); src.push("}"); - src.push("in float isPerspective;"); + src.push("out float isPerspective;"); } + if (clipping) { - src.push("in vec4 vWorldPosition;"); - src.push("in vec4 vFlags2;"); + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } + + src.push("out vec4 vColor;"); src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED + // renderPass = EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); + src.push(`if (int(flags.z) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } + src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); + src.push("vColor = vec4(color.r, color.g, color.b, color.a);"); src.push("}"); src.push("}"); return src; @@ -51278,8 +54650,8 @@ class TrianglesInstancingOcclusionRenderer { const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing occlusion fragment shader"); - + src.push("// Batched geometry edges drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -51288,37 +54660,38 @@ class TrianglesInstancingOcclusionRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { - src.push("out float isPerspective;"); + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); + src.push("in float vFragDepth;"); } if (clipping) { - src.push("out vec4 vWorldPosition;"); - src.push("out vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { discard; }"); src.push("}"); } - src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push("outColor = vColor;"); src.push("}"); return src; } @@ -51335,12 +54708,12 @@ class TrianglesInstancingOcclusionRenderer { } } -const tempVec3a$x = math.vec3(); +const tempVec3a$R = math.vec3(); /** * @private */ -class TrianglesInstancingDepthRenderer { +class TrianglesBatchingEdgesColorRenderer { constructor(scene) { this._scene = scene; @@ -51356,18 +54729,17 @@ class TrianglesInstancingDepthRenderer { return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; + const model = batchingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(); + this._allocate(batchingLayer); if (this.errors) { return; } @@ -51380,13 +54752,13 @@ class TrianglesInstancingDepthRenderer { gl.uniform1i(this._uRenderPass, renderPass); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -51396,7 +54768,7 @@ class TrianglesInstancingDepthRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$x); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$R); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -51407,47 +54779,22 @@ class TrianglesInstancingDepthRenderer { } } - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aColor.bindArrayBuffer(state.colorsBuf); if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } if (this._aFlags2) { this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); } + state.edgeIndicesBuf.bind(); - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + gl.drawElements(gl.LINES, state.edgeIndicesBuf.numItems, state.edgeIndicesBuf.itemType, 0); } _allocate() { @@ -51465,12 +54812,10 @@ class TrianglesInstancingDepthRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -51482,12 +54827,10 @@ class TrianglesInstancingDepthRenderer { } this._aPosition = program.getAttribute("position"); + this._aColor = program.getAttribute("color"); this._aOffset = program.getAttribute("offset"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); @@ -51498,9 +54841,10 @@ class TrianglesInstancingDepthRenderer { const scene = this._scene; const gl = scene.canvas.gl; + const program = this._program; const project = scene.camera.project; - this._program.bind(); + program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); @@ -51523,22 +54867,23 @@ class TrianglesInstancingDepthRenderer { const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry depth drawing vertex shader"); + src.push("// Batched geometry edges drawing vertex shader"); src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + src.push("in vec4 color;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); + src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); + if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); @@ -51547,38 +54892,42 @@ class TrianglesInstancingDepthRenderer { src.push("}"); src.push("out float isPerspective;"); } + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec2 vHighPrecisionZW;"); + + src.push("out vec4 vColor;"); src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED + // renderPass = EDGES_COLOR_OPAQUE | EDGES_COLOR_TRANSPARENT - src.push(`if (int(flags.x) != renderPass) {`); + src.push(`if (int(flags.z) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } + src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - src.push("vHighPrecisionZW = gl_Position.zw;"); + //src.push("vColor = vec4(float(color.r-100.0) / 255.0, float(color.g-100.0) / 255.0, float(color.b-100.0) / 255.0, float(color.a) / 255.0);"); + src.push("vColor = vec4(float(color.r*0.5) / 255.0, float(color.g*0.5) / 255.0, float(color.b*0.5) / 255.0, float(color.a) / 255.0);"); src.push("}"); src.push("}"); return src; @@ -51587,15 +54936,17 @@ class TrianglesInstancingDepthRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; - let i; - let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry depth drawing fragment shader"); - + src.push("// Batched geometry edges drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); @@ -51604,32 +54955,31 @@ class TrianglesInstancingDepthRenderer { if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec2 vHighPrecisionZW;"); + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { discard; }"); src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push("float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;"); - src.push(" outColor = vec4(vec3(1.0 - fragCoordZ), 1.0); "); + src.push("outColor = vColor;"); src.push("}"); return src; } @@ -51646,12 +54996,12 @@ class TrianglesInstancingDepthRenderer { } } -const tempVec3a$w = math.vec3(); +const tempVec3a$Q = math.vec3(); /** * @private */ -class TrianglesInstancingNormalsRenderer { +class TrianglesBatchingPickMeshRenderer { constructor(scene) { this._scene = scene; @@ -51667,40 +55017,42 @@ class TrianglesInstancingNormalsRenderer { return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; + const model = batchingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(instancingLayer); - if (this.errors) { - return; - } + this._allocate(batchingLayer); } if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx); } gl.uniform1i(this._uRenderPass, renderPass); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -51710,7 +55062,7 @@ class TrianglesInstancingNormalsRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$w); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$Q); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -51721,59 +55073,35 @@ class TrianglesInstancingNormalsRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aNormal.bindArrayBuffer(geometry.normalsBuf); + this._aPosition.bindArrayBuffer(state.positionsBuf); if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } if (this._aFlags2) { this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); } - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); + if (this._aPickColor) { + this._aPickColor.bindArrayBuffer(state.pickColorsBuf); } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + state.indicesBuf.bind(); + + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -51785,16 +55113,15 @@ class TrianglesInstancingNormalsRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -51804,37 +55131,23 @@ class TrianglesInstancingNormalsRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aNormal = program.getAttribute("normal"); - this._aColor = program.getAttribute("color"); + this._aPickColor = program.getAttribute("pickColor"); this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - if (this._aFlags2) { - this._aFlags2 = program.getAttribute("flags2"); - } - - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - - if ( scene.logarithmicDepthBufferEnabled) { + if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { + _bindProgram(frameCtx) { const scene = this._scene; const gl = scene.canvas.gl; - const project = scene.camera.project; this._program.bind(); - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if ( scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); } _buildShader() { @@ -51846,30 +55159,29 @@ class TrianglesInstancingNormalsRenderer { _buildVertexShader() { const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry normals drawing vertex shader"); + src.push("// Batched geometry picking vertex shader"); + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec3 normal;"); - src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); + + src.push("in vec4 pickColor;"); + + src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); + if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); @@ -51878,47 +55190,40 @@ class TrianglesInstancingNormalsRenderer { src.push("}"); src.push("out float isPerspective;"); } - src.push("vec3 octDecode(vec2 oct) {"); - src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); - src.push(" if (v.z < 0.0) {"); - src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); - src.push(" }"); - src.push(" return normalize(v);"); - src.push("}"); + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec3 vViewNormal;"); + + src.push("out vec4 vPickColor;"); + src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); - src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); - src.push(" vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); - + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - src.push(" vViewNormal = viewNormal;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - src.push("}"); + src.push(" }"); src.push("}"); return src; } @@ -51929,7 +55234,7 @@ class TrianglesInstancingNormalsRenderer { const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry depth drawing fragment shader"); + src.push("// Batched geometry picking fragment shader"); src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); @@ -51946,34 +55251,31 @@ class TrianglesInstancingNormalsRenderer { if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec3 vViewNormal;"); - src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); - src.push(" return normalize( normal ) * 0.5 + 0.5;"); - src.push("}"); + src.push("in vec4 vPickColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); } - src.push("if (dist > 0.0) { discard; }"); - src.push("}"); + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); + src.push(" outColor = vPickColor; "); src.push("}"); return src; } @@ -51990,19 +55292,16 @@ class TrianglesInstancingNormalsRenderer { } } -const tempVec3a$v = math.vec3(); +const tempVec3a$P = math.vec3(); /** - * Renders InstancingLayer fragment depths to a shadow map. - * * @private */ -class TrianglesInstancingShadowRenderer { +class TrianglesBatchingPickDepthRenderer { constructor(scene) { this._scene = scene; this._hash = this._getHash(); - this._lastLightId = null; this._allocate(); } @@ -52014,61 +55313,48 @@ class TrianglesInstancingShadowRenderer { return this._scene._sectionPlanesState.getHash(); } - drawLayer( frameCtx, instancingLayer) { - const model = instancingLayer.model; + drawLayer(frameCtx, batchingLayer, renderPass) { + + const model = batchingLayer.model; const scene = model.scene; + const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { this._allocate(); - if (this.errors) { - return; - } } if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx, instancingLayer); + this._bindProgram(); } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + gl.uniform1i(this._uRenderPass, renderPass); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); + gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); + gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - // TODO: Section planes need to be set if RTC center has changed since last RTC center recorded on frameCtx - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; - const origin = instancingLayer._state.origin; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; if (sectionPlaneUniforms) { @@ -52077,7 +55363,7 @@ class TrianglesInstancingShadowRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$v); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$P); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -52088,65 +55374,75 @@ class TrianglesInstancingShadowRenderer { } } - geometry.indicesBuf.bind(); + //============================================================= + // TODO: Use drawElements count and offset to draw only one entity + //============================================================= - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); + this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + } + + state.indicesBuf.bind(); + + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { + const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + this._program = new Program(gl, this._buildShader()); + if (this._program.errors) { this.errors = this._program.errors; return; } + const program = this._program; + + this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uShadowViewMatrix = program.getLocation("shadowViewMatrix"); - this._uShadowProjMatrix = program.getLocation("shadowProjMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), dir: program.getLocation("sectionPlaneDir" + i) }); } + this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + this._uPickZNear = program.getLocation("pickZNear"); + this._uPickZFar = program.getLocation("pickZFar"); + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - _bindProgram(frameCtx, instancingLayer) { - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - program.bind(); - gl.uniformMatrix4fv(this._uShadowViewMatrix, false, frameCtx.shadowViewMatrix); - gl.uniformMatrix4fv(this._uShadowProjMatrix, false, frameCtx.shadowProjMatrix); - this._lastLightId = null; + _bindProgram() { + this._program.bind(); } _buildShader() { @@ -52157,60 +55453,85 @@ class TrianglesInstancingShadowRenderer { } _buildVertexShader() { + const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry shadow drawing vertex shader"); + src.push("// Triangles batching pick depth vertex shader"); + + + + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - src.push("uniform mat4 shadowViewMatrix;"); - src.push("uniform mat4 shadowProjMatrix;"); + + src.push("uniform bool pickInvisible;"); + + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); + } + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } + src.push("out vec4 vViewPosition;"); src.push("void main(void) {"); - src.push("bool visible = (float(flags.x) > 0.0);"); - src.push("bool transparent = ((float(color.a) / 255.0) < 1.0);"); - src.push(`if (!visible || transparent) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK + + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = shadowViewMatrix * worldPosition; "); - + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - src.push(" gl_Position = shadowProjMatrix * viewPosition;"); - src.push("}"); + src.push("vViewPosition = viewPosition;"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + } + src.push("gl_Position = clipPos;"); + src.push(" }"); src.push("}"); return src; } _buildFragmentShader() { + const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry depth drawing fragment shader"); + src.push("// Triangles batching pick depth fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -52218,41 +55539,52 @@ class TrianglesInstancingShadowRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + + src.push("uniform float pickZNear;"); + src.push("uniform float pickZFar;"); + if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec3 vViewNormal;"); - src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); - src.push(" return normalize( normal ) * 0.5 + 0.5;"); + src.push("in vec4 vViewPosition;"); + src.push("vec4 packDepth(const in float depth) {"); + src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); + src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); + src.push(" vec4 res = fract(depth * bitShift);"); + src.push(" res -= res.xxyz * bitMask;"); + src.push(" return res;"); src.push("}"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); } - src.push("if (dist > 0.0) { discard; }"); - src.push("}"); + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); + src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); + src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth src.push("}"); return src; } @@ -52269,21 +55601,15 @@ class TrianglesInstancingShadowRenderer { } } -const tempVec4$1 = math.vec4(); -const tempVec3a$u = math.vec3(); - -const TEXTURE_DECODE_FUNCS = {}; -TEXTURE_DECODE_FUNCS[LinearEncoding] = "linearToLinear"; -TEXTURE_DECODE_FUNCS[sRGBEncoding] = "sRGBToLinear"; +const tempVec3a$O = math.vec3(); /** * @private */ -class TrianglesInstancingPBRRenderer { +class TrianglesBatchingPickNormalsRenderer { - constructor(scene, withSAO) { + constructor(scene) { this._scene = scene; - this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -52293,48 +55619,47 @@ class TrianglesInstancingPBRRenderer { }; _getHash() { - const scene = this._scene; - return [scene.gammaOutput, scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { - - const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; - const scene = this._scene; + const model = batchingLayer.model; + const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const origin = state.origin; - const textureSet = state.textureSet; - const geometry = state.geometry; - const lightsState = scene._lightsState; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } + this._allocate(batchingLayer); } if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + this._bindProgram(); } gl.uniform1i(this._uRenderPass, renderPass); - - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far should be from projection matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -52344,7 +55669,7 @@ class TrianglesInstancingPBRRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$u); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$O); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -52355,123 +55680,39 @@ class TrianglesInstancingPBRRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - if (this._uUVDecodeMatrix) { - gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, geometry.uvDecodeMatrix); - } - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); - this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); - this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aNormal.bindArrayBuffer(geometry.normalsBuf); - - if (this._aUV) { - this._aUV.bindArrayBuffer(geometry.uvBuf); - } - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); - - this._aMetallicRoughness.bindArrayBuffer(state.metallicRoughnessBuf); - gl.vertexAttribDivisor(this._aMetallicRoughness.location, 1); + //============================================================= + // TODO: Use drawElements count and offset to draw only one entity + //============================================================= - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } + this._aPosition.bindArrayBuffer(state.positionsBuf); if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - if (lightsState.reflectionMaps.length > 0 && lightsState.reflectionMaps[0].texture && this._uReflectionMap) { - this._program.bindTexture(this._uReflectionMap, lightsState.reflectionMaps[0].texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; - } - - if (lightsState.lightMaps.length > 0 && lightsState.lightMaps[0].texture && this._uLightMap) { - this._program.bindTexture(this._uLightMap, lightsState.lightMaps[0].texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; + if (this._aNormal) { + this._aNormal.bindArrayBuffer(state.normalsBuf); } - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4$1[0] = viewportWidth; - tempVec4$1[1] = viewportHeight; - tempVec4$1[2] = sao.blendCutoff; - tempVec4$1[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4$1); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - frameCtx.bindTexture++; - } + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - if (textureSet) { - this._program.bindTexture(this._uBaseColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uMetallicRoughMap, textureSet.metallicRoughnessTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uEmissiveMap, textureSet.emissiveTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - this._program.bindTexture(this._uNormalMap, textureSet.normalsTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - frameCtx.drawElements++; - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); - gl.vertexAttribDivisor(this._aMetallicRoughness.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } + state.indicesBuf.bind(); - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -52483,58 +55724,11 @@ class TrianglesInstancingPBRRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - + this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - - this._uGammaFactor = program.getLocation("gammaFactor"); - - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; - - const lights = lightsState.lights; - let light; - - for (var i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - } - } - - if (lightsState.reflectionMaps.length > 0) { - this._uReflectionMap = "reflectionMap"; - } - - if (lightsState.lightMaps.length > 0) { - this._uLightMap = "lightMap"; - } - this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -52546,74 +55740,18 @@ class TrianglesInstancingPBRRenderer { } this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); this._aNormal = program.getAttribute("normal"); - this._aUV = program.getAttribute("uv"); - this._aColor = program.getAttribute("color"); - this._aMetallicRoughness = program.getAttribute("metallicRoughness"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aOffset = program.getAttribute("offset"); - - this._uBaseColorMap = "uBaseColorMap"; - this._uMetallicRoughMap = "uMetallicRoughMap"; - this._uEmissiveMap = "uEmissiveMap"; - this._uNormalMap = "uNormalMap"; - - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - - this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); - this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); - this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); - - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram(frameCtx) { - const scene = this._scene; - const gl = scene.canvas.gl; - const lightsState = scene._lightsState; - const lights = lightsState.lights; - const project = scene.camera.project; - + _bindProgram() { this._program.bind(); - - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); - } - - for (let i = 0, len = lights.length; i < len; i++) { - const light = lights[i]; - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); - } - } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } - } - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } - - if (this._uGammaFactor) { - gl.uniform1f(this._uGammaFactor, scene.gammaFactor); - } } _buildShader() { @@ -52624,47 +55762,25 @@ class TrianglesInstancingPBRRenderer { } _buildVertexShader() { - const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - const clippingCaps = sectionPlanesState.clippingCaps; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry quality drawing vertex shader"); - - + src.push("// Triangles batching pick normals vertex shader"); + src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - src.push("in vec3 normal;"); - src.push("in vec4 color;"); - src.push("in vec2 uv;"); - src.push("in vec2 metallicRoughness;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - - src.push("in vec4 modelNormalMatrixCol0;"); - src.push("in vec4 modelNormalMatrixCol1;"); - src.push("in vec4 modelNormalMatrixCol2;"); - + src.push("in vec3 normal;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 worldNormalMatrix;"); src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform mat3 uvDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); @@ -52673,7 +55789,6 @@ class TrianglesInstancingPBRRenderer { src.push("}"); src.push("out float isPerspective;"); } - src.push("vec3 octDecode(vec2 oct) {"); src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); src.push(" if (v.z < 0.0) {"); @@ -52681,90 +55796,48 @@ class TrianglesInstancingPBRRenderer { src.push(" }"); src.push(" return normalize(v);"); src.push("}"); - - src.push("out vec4 vViewPosition;"); - src.push("out vec3 vViewNormal;"); - src.push("out vec4 vColor;"); - src.push("out vec2 vUV;"); - src.push("out vec2 vMetallicRoughness;"); - - if (lightsState.lightMaps.length > 0) { - src.push("out vec3 vWorldNormal;"); - } - if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); - if (clippingCaps) { - src.push("out vec4 vClipPosition;"); - } } - + src.push("out vec3 vWorldNormal;"); + src.push("out vec4 outColor;"); src.push("void main(void) {"); - - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT - - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - - src.push("} else {"); - - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - - src.push("vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); - src.push("vec4 worldNormal = worldNormalMatrix * vec4(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2), 1.0);"); - src.push("vec3 viewNormal = vec4(viewNormalMatrix * worldNormal).xyz;"); - + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec3 worldNormal = octDecode(normal.xy); "); + src.push(" vWorldNormal = worldNormal;"); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); + } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } - - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - if (clippingCaps) { - src.push("vClipPosition = clipPos;"); - } - } - - src.push("vViewPosition = viewPosition;"); - src.push("vViewNormal = viewNormal;"); - src.push("vColor = color;"); - src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); - src.push("vMetallicRoughness = metallicRoughness;"); - - if (lightsState.lightMaps.length > 0) { - src.push("vWorldNormal = worldNormal.xyz;"); - } - src.push("gl_Position = clipPos;"); - src.push("}"); + src.push(" }"); src.push("}"); return src; } _buildFragmentShader() { - const scene = this._scene; - const gammaOutput = scene.gammaOutput; // If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is false. const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const clippingCaps = sectionPlanesState.clippingCaps; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry quality drawing fragment shader"); - - + src.push("// Triangles batching pick normals fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -52772,398 +55845,322 @@ class TrianglesInstancingPBRRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } - - src.push("uniform sampler2D uBaseColorMap;"); - src.push("uniform sampler2D uMetallicRoughMap;"); - src.push("uniform sampler2D uEmissiveMap;"); - src.push("uniform sampler2D uNormalMap;"); - - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); - - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); - - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); - } - - if (lightsState.reflectionMaps.length > 0) { - src.push("uniform samplerCube reflectionMap;"); - } - - if (lightsState.lightMaps.length > 0) { - src.push("uniform samplerCube lightMap;"); - } - - src.push("uniform vec4 lightAmbient;"); - - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - const light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); - } - } - - src.push("uniform float gammaFactor;"); - src.push("vec4 linearToLinear( in vec4 value ) {"); - src.push(" return value;"); - src.push("}"); - src.push("vec4 sRGBToLinear( in vec4 value ) {"); - src.push(" return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );"); - src.push("}"); - src.push("vec4 gammaToLinear( in vec4 value) {"); - src.push(" return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );"); - src.push("}"); - if (gammaOutput) { - src.push("vec4 linearToGamma( in vec4 value, in float gammaFactor ) {"); - src.push(" return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );"); - src.push("}"); - } - if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - if (clippingCaps) { - src.push("in vec4 vClipPosition;"); - } - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } + src.push("in vec3 vWorldNormal;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); + } + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" outColor = vec4((vWorldNormal * 0.5) + 0.5, 1.0);"); + src.push("}"); + return src; + } - src.push("in vec4 vViewPosition;"); - src.push("in vec3 vViewNormal;"); - src.push("in vec4 vColor;"); - src.push("in vec2 vUV;"); - src.push("in vec2 vMetallicRoughness;"); + webglContextRestored() { + this._program = null; + } - if (lightsState.lightMaps.length > 0) { - src.push("in vec3 vWorldNormal;"); + destroy() { + if (this._program) { + this._program.destroy(); } + this._program = null; + } +} - src.push("uniform mat4 viewMatrix;"); +const tempVec3a$N = math.vec3(); - // CONSTANT DEFINITIONS +/** + * @private + */ +class TrianglesBatchingOcclusionRenderer { - src.push("#define PI 3.14159265359"); - src.push("#define RECIPROCAL_PI 0.31830988618"); - src.push("#define RECIPROCAL_PI2 0.15915494"); - src.push("#define EPSILON 1e-6"); + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - src.push("#define saturate(a) clamp( a, 0.0, 1.0 )"); + getValid() { + return this._hash === this._getHash(); + }; - // UTILITY DEFINITIONS + _getHash() { + return this._scene._sectionPlanesState.getHash(); + } - src.push("vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {"); - src.push(" vec3 texel = texture( uNormalMap, uv ).xyz;"); - src.push(" if (texel.r == 0.0 && texel.g == 0.0 && texel.b == 0.0) {"); - src.push(" return normalize(surf_norm );"); - src.push(" }"); - src.push(" vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );"); - src.push(" vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );"); - src.push(" vec2 st0 = dFdx( uv.st );"); - src.push(" vec2 st1 = dFdy( uv.st );"); - src.push(" vec3 S = normalize( q0 * st1.t - q1 * st0.t );"); - src.push(" vec3 T = normalize( -q0 * st1.s + q1 * st0.s );"); - src.push(" vec3 N = normalize( surf_norm );"); - src.push(" vec3 mapN = texel.xyz * 2.0 - 1.0;"); - src.push(" mat3 tsn = mat3( S, T, N );"); - // src.push(" mapN *= 3.0;"); - src.push(" return normalize( tsn * mapN );"); - src.push("}"); + drawLayer(frameCtx, batchingLayer, renderPass) { - src.push("vec3 inverseTransformDirection(in vec3 dir, in mat4 matrix) {"); - src.push(" return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );"); - src.push("}"); + const model = batchingLayer.model; + const scene = model.scene; + const gl = scene.canvas.gl; + const state = batchingLayer._state; + const camera = scene.camera; + const origin = batchingLayer._state.origin; - // STRUCTURES + if (!this._program) { + this._allocate(batchingLayer); + if (this.errors) { + return; + } + } - src.push("struct IncidentLight {"); - src.push(" vec3 color;"); - src.push(" vec3 direction;"); - src.push("};"); + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - src.push("struct ReflectedLight {"); - src.push(" vec3 diffuse;"); - src.push(" vec3 specular;"); - src.push("};"); + gl.uniform1i(this._uRenderPass, renderPass); - src.push("struct Geometry {"); - src.push(" vec3 position;"); - src.push(" vec3 viewNormal;"); - src.push(" vec3 worldNormal;"); - src.push(" vec3 viewEyeDir;"); - src.push("};"); + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - src.push("struct Material {"); - src.push(" vec3 diffuseColor;"); - src.push(" float specularRoughness;"); - src.push(" vec3 specularColor;"); - src.push(" float shine;"); // Only used for Phong - src.push("};"); - - // IRRADIANCE EVALUATION - - src.push("float GGXRoughnessToBlinnExponent(const in float ggxRoughness) {"); - src.push(" float r = ggxRoughness + 0.0001;"); - src.push(" return (2.0 / (r * r) - 2.0);"); - src.push("}"); - - src.push("float getSpecularMIPLevel(const in float blinnShininessExponent, const in int maxMIPLevel) {"); - src.push(" float maxMIPLevelScalar = float( maxMIPLevel );"); - src.push(" float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( ( blinnShininessExponent * blinnShininessExponent ) + 1.0 );"); - src.push(" return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );"); - src.push("}"); - - if (lightsState.reflectionMaps.length > 0) { - src.push("vec3 getLightProbeIndirectRadiance(const in vec3 reflectVec, const in float blinnShininessExponent, const in int maxMIPLevel) {"); - src.push(" float mipLevel = 0.5 * getSpecularMIPLevel(blinnShininessExponent, maxMIPLevel);"); //TODO: a random factor - fix this - src.push(" vec3 envMapColor = " + TEXTURE_DECODE_FUNCS[lightsState.reflectionMaps[0].encoding] + "(texture(reflectionMap, reflectVec, mipLevel)).rgb;"); - src.push(" return envMapColor;"); - src.push("}"); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$N); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - // SPECULAR BRDF EVALUATION + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - src.push("vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) {"); - src.push(" float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );"); - src.push(" return ( 1.0 - specularColor ) * fresnel + specularColor;"); - src.push("}"); + this._aPosition.bindArrayBuffer(state.positionsBuf); - src.push("float G_GGX_Smith(const in float alpha, const in float dotNL, const in float dotNV) {"); - src.push(" float a2 = ( alpha * alpha );"); - src.push(" float gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); - src.push(" float gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); - src.push(" return 1.0 / ( gl * gv );"); - src.push("}"); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + } - src.push("float G_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) {"); - src.push(" float a2 = ( alpha * alpha );"); - src.push(" float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); - src.push(" float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); - src.push(" return 0.5 / max( gv + gl, EPSILON );"); - src.push("}"); + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); + } - src.push("float D_GGX(const in float alpha, const in float dotNH) {"); - src.push(" float a2 = ( alpha * alpha );"); - src.push(" float denom = ( dotNH * dotNH) * ( a2 - 1.0 ) + 1.0;"); - src.push(" return RECIPROCAL_PI * a2 / ( denom * denom);"); - src.push("}"); + this._aFlags.bindArrayBuffer(state.flagsBuf); - src.push("vec3 BRDF_Specular_GGX(const in IncidentLight incidentLight, const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); - src.push(" float alpha = ( roughness * roughness );"); - src.push(" vec3 halfDir = normalize( incidentLight.direction + geometry.viewEyeDir );"); - src.push(" float dotNL = saturate( dot( geometry.viewNormal, incidentLight.direction ) );"); - src.push(" float dotNV = saturate( dot( geometry.viewNormal, geometry.viewEyeDir ) );"); - src.push(" float dotNH = saturate( dot( geometry.viewNormal, halfDir ) );"); - src.push(" float dotLH = saturate( dot( incidentLight.direction, halfDir ) );"); - src.push(" vec3 F = F_Schlick( specularColor, dotLH );"); - src.push(" float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );"); - src.push(" float D = D_GGX( alpha, dotNH );"); - src.push(" return F * (G * D);"); - src.push("}"); + if (this._aFlags2) { // Won't be in shader when not clipping + this._aFlags2.bindArrayBuffer(state.flags2Buf); + } - src.push("vec3 BRDF_Specular_GGX_Environment(const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); - src.push(" float dotNV = saturate(dot(geometry.viewNormal, geometry.viewEyeDir));"); - src.push(" const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022);"); - src.push(" const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04);"); - src.push(" vec4 r = roughness * c0 + c1;"); - src.push(" float a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y;"); - src.push(" vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;"); - src.push(" return specularColor * AB.x + AB.y;"); - src.push("}"); + state.indicesBuf.bind(); - if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + } - src.push("void computePBRLightMapping(const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); + _allocate() { - if (lightsState.lightMaps.length > 0) { - src.push(" vec3 irradiance = " + TEXTURE_DECODE_FUNCS[lightsState.lightMaps[0].encoding] + "(texture(lightMap, geometry.worldNormal)).rgb;"); - src.push(" irradiance *= PI;"); - src.push(" vec3 diffuseBRDFContrib = (RECIPROCAL_PI * material.diffuseColor);"); - src.push(" reflectedLight.diffuse += irradiance * diffuseBRDFContrib;"); - } + const scene = this._scene; + const gl = scene.canvas.gl; - if (lightsState.reflectionMaps.length > 0) { - src.push(" vec3 reflectVec = reflect(geometry.viewEyeDir, geometry.viewNormal);"); - src.push(" reflectVec = inverseTransformDirection(reflectVec, viewMatrix);"); - src.push(" float blinnExpFromRoughness = GGXRoughnessToBlinnExponent(material.specularRoughness);"); - src.push(" vec3 radiance = getLightProbeIndirectRadiance(reflectVec, blinnExpFromRoughness, 8);"); - src.push(" vec3 specularBRDFContrib = BRDF_Specular_GGX_Environment(geometry, material.specularColor, material.specularRoughness);"); - src.push(" reflectedLight.specular += radiance * specularBRDFContrib;"); - } + this._program = new Program(gl, this._buildShader()); - src.push("}"); + if (this._program.errors) { + this.errors = this._program.errors; + return; } - // MAIN LIGHTING COMPUTATION FUNCTION - - src.push("void computePBRLighting(const in IncidentLight incidentLight, const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); - src.push(" float dotNL = saturate(dot(geometry.viewNormal, incidentLight.direction));"); - src.push(" vec3 irradiance = dotNL * incidentLight.color * PI;"); - src.push(" reflectedLight.diffuse += irradiance * (RECIPROCAL_PI * material.diffuseColor);"); - src.push(" reflectedLight.specular += irradiance * BRDF_Specular_GGX(incidentLight, geometry, material.specularColor, material.specularRoughness);"); - src.push("}"); - - src.push("out vec4 outColor;"); + const program = this._program; - src.push("void main(void) {"); + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; - if (clipping) { - src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); - src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); - } - if (clippingCaps) { - src.push(" if (dist > (0.002 * vClipPosition.w)) {"); - src.push(" discard;"); - src.push(" }"); - src.push(" if (dist > 0.0) { "); - src.push(" outColor=vec4(1.0, 0.0, 0.0, 1.0);"); - if (scene.logarithmicDepthBufferEnabled) { - src.push(" gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" return;"); - src.push("}"); - } else { - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); - src.push(" }"); - } - src.push("}"); + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - src.push("IncidentLight light;"); - src.push("Material material;"); - src.push("Geometry geometry;"); - src.push("ReflectedLight reflectedLight = ReflectedLight(vec3(0.0,0.0,0.0), vec3(0.0,0.0,0.0));"); + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - src.push("vec3 rgb = (vec3(float(vColor.r) / 255.0, float(vColor.g) / 255.0, float(vColor.b) / 255.0));"); - src.push("float opacity = float(vColor.a) / 255.0;"); + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } + } - src.push("vec3 baseColor = rgb;"); - src.push("float specularF0 = 1.0;"); - src.push("float metallic = float(vMetallicRoughness.r) / 255.0;"); - src.push("float roughness = float(vMetallicRoughness.g) / 255.0;"); - src.push("float dielectricSpecular = 0.16 * specularF0 * specularF0;"); + _bindProgram() { - src.push("vec4 baseColorTexel = sRGBToLinear(texture(uBaseColorMap, vUV));"); - src.push("baseColor *= baseColorTexel.rgb;"); - // src.push("opacity = baseColorTexel.a;"); + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - src.push("vec3 metalRoughTexel = texture(uMetallicRoughMap, vUV).rgb;"); - src.push("metallic *= metalRoughTexel.b;"); - src.push("roughness *= metalRoughTexel.g;"); + this._program.bind(); - src.push("vec3 viewNormal = perturbNormal2Arb( vViewPosition.xyz, normalize(vViewNormal), vUV );"); + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - src.push("material.diffuseColor = baseColor * (1.0 - dielectricSpecular) * (1.0 - metallic);"); - src.push("material.specularRoughness = clamp(roughness, 0.04, 1.0);"); - src.push("material.specularColor = mix(vec3(dielectricSpecular), baseColor, metallic);"); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } + } - src.push("geometry.position = vViewPosition.xyz;"); - src.push("geometry.viewNormal = -normalize(viewNormal);"); - src.push("geometry.viewEyeDir = normalize(vViewPosition.xyz);"); + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - if (lightsState.lightMaps.length > 0) { - src.push("geometry.worldNormal = normalize(vWorldNormal);"); + _buildVertexShader() { + const scene = this._scene; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push("#version 300 es"); + src.push("// Triangles batching occlusion vertex shader"); + + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { - src.push("computePBRLightMapping(geometry, material, reflectedLight);"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } - - for (let i = 0, len = lightsState.lights.length; i < len; i++) { - - const light = lightsState.lights[i]; - - if (light.type === "ambient") { - continue; - } - if (light.type === "dir") { - if (light.space === "view") { - src.push("light.direction = normalize(lightDir" + i + ");"); - } else { - src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("light.direction = normalize(lightPos" + i + " - vViewPosition.xyz);"); - } else { - src.push("light.direction = normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("light.direction = normalize(lightDir" + i + ");"); - } else { - src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else { - continue; - } - - src.push("light.color = lightColor" + i + ".rgb * lightColor" + i + ".a;"); // a is intensity - - src.push("computePBRLighting(light, geometry, material, reflectedLight);"); + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } + src.push("void main(void) {"); - src.push("vec3 emissiveColor = sRGBToLinear(texture(uEmissiveMap, vUV)).rgb;"); // TODO: correct gamma function + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE + // Only opaque objects can be occluders - src.push("vec3 outgoingLight = (lightAmbient.rgb * lightAmbient.a * baseColor * opacity * rgb) + (reflectedLight.diffuse) + (reflectedLight.specular) + emissiveColor;"); - src.push("vec4 fragColor;"); + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - if (this._withSAO) { - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" fragColor = vec4(outgoingLight.rgb * ambient, opacity);"); - } else { - src.push(" fragColor = vec4(outgoingLight.rgb, opacity);"); + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - if (gammaOutput) { - src.push("fragColor = linearToGamma(fragColor, gammaFactor);"); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + } + src.push("gl_Position = clipPos;"); + src.push(" }"); + src.push("}"); + return src; + } - src.push("outColor = fragColor;"); - + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push("#version 300 es"); + src.push("// Triangles batching occlusion fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); + } if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - + src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue src.push("}"); return src; } @@ -53180,17 +56177,17 @@ class TrianglesInstancingPBRRenderer { } } -const tempVec3a$t = math.vec3(); +const tempVec3a$M = math.vec3(); /** * @private */ -class TrianglesInstancingPickNormalsFlatRenderer { +class TrianglesBatchingDepthRenderer { constructor(scene) { this._scene = scene; - this._hash = this._getHash(); this._allocate(); + this._hash = this._getHash(); } getValid() { @@ -53201,18 +56198,17 @@ class TrianglesInstancingPickNormalsFlatRenderer { return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const model = instancingLayer.model; + const model = batchingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(instancingLayer); + this._allocate(); if (this.errors) { return; } @@ -53223,96 +56219,58 @@ class TrianglesInstancingPickNormalsFlatRenderer { this._bindProgram(); } - // In practice, these binds will only happen once per frame - // because we pick normals on a single previously-picked mesh - gl.uniform1i(this._uRenderPass, renderPass); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - - gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$t); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$M); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + this._aPosition.bindArrayBuffer(state.positionsBuf); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + } this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); if (this._aFlags2) { this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); } - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } + state.indicesBuf.bind(); - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -53324,15 +56282,13 @@ class TrianglesInstancingPickNormalsFlatRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -53345,17 +56301,25 @@ class TrianglesInstancingPickNormalsFlatRenderer { this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } _bindProgram() { + + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; + this._program.bind(); + + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } _buildShader() { @@ -53367,12 +56331,11 @@ class TrianglesInstancingPickNormalsFlatRenderer { _buildVertexShader() { const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry normals vertex shader"); - + src.push("// Triangles batching depth vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { @@ -53380,10 +56343,6 @@ class TrianglesInstancingPickNormalsFlatRenderer { } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); @@ -53397,31 +56356,35 @@ class TrianglesInstancingPickNormalsFlatRenderer { src.push("out float isPerspective;"); } if (clipping) { + src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vWorldPosition;"); + src.push("out vec2 vHighPrecisionZW;"); src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - src.push(`if (int(flags.w) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vWorldPosition = worldPosition;"); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); + } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - src.push("}"); + src.push("vHighPrecisionZW = gl_Position.zw;"); + src.push(" }"); src.push("}"); return src; } @@ -53429,26 +56392,20 @@ class TrianglesInstancingPickNormalsFlatRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clipping = (sectionPlanesState.sectionPlanes.length > 0); const src = []; src.push("#version 300 es"); - src.push("// Batched geometry normals fragment shader"); - - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("// Triangles batching depth fragment shader"); + src.push("precision highp float;"); src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } - src.push("in vec4 vWorldPosition;"); if (clipping) { + src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); @@ -53456,28 +56413,37 @@ class TrianglesInstancingPickNormalsFlatRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec3 vWorldNormal;"); + src.push("const float packUpScale = 256. / 255.;"); + src.push("const float unpackDownscale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unpackFactors = unpackDownscale / vec4( packFactors, 1. );"); + src.push("const float shiftRight8 = 1.0 / 256.;"); + + src.push("vec4 packDepthToRGBA( const in float v ) {"); + src.push(" vec4 r = vec4( fract( v * packFactors ), v );"); + src.push(" r.yzw -= r.xyz * shiftRight8;"); + src.push(" return r * packUpScale;"); + src.push("}"); + src.push("in vec2 vHighPrecisionZW;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); + src.push(" float dist = 0.0;"); for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); } - src.push("if (dist > 0.0) { discard; }"); - src.push("}"); + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" vec3 xTangent = dFdx( vWorldPosition.xyz );"); - src.push(" vec3 yTangent = dFdy( vWorldPosition.xyz );"); - src.push(" vec3 worldNormal = normalize( cross( xTangent, yTangent ) );"); - src.push(" outColor = vec4((worldNormal * 0.5) + 0.5, 1.0);"); + src.push("float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;"); + src.push(" outColor = vec4(vec3(1.0 - fragCoordZ), 1.0); "); src.push("}"); return src; } @@ -53491,20 +56457,19 @@ class TrianglesInstancingPickNormalsFlatRenderer { this._program.destroy(); } this._program = null; + stats.memory.programs--; } } -const tempVec4 = math.vec4(); -const tempVec3a$s = math.vec3(); +const tempVec3a$L = math.vec3(); /** * @private */ -class TrianglesInstancingColorTextureRenderer { +class TrianglesBatchingNormalsRenderer { - constructor(scene, withSAO) { + constructor(scene) { this._scene = scene; - this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -53514,24 +56479,20 @@ class TrianglesInstancingColorTextureRenderer { }; _getHash() { - const scene = this._scene; - return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { + drawLayer(frameCtx, batchingLayer, renderPass) { - const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; - const model = instancingLayer.model; + const model = batchingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = instancingLayer._state; - const geometry = state.geometry; - const origin = instancingLayer._state.origin; - const textureSet = state.textureSet; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; if (!this._program) { - this._allocate(); + this._allocate(batchingLayer); if (this.errors) { return; } @@ -53539,7 +56500,7 @@ class TrianglesInstancingColorTextureRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + this._bindProgram(batchingLayer); } gl.uniform1i(this._uRenderPass, renderPass); @@ -53553,7 +56514,7 @@ class TrianglesInstancingColorTextureRenderer { const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -53563,7 +56524,7 @@ class TrianglesInstancingColorTextureRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$s); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$L); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -53574,99 +56535,25 @@ class TrianglesInstancingColorTextureRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - if (this._uUVDecodeMatrix) { - gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, geometry.uvDecodeMatrix); - } - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); - this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); - this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aNormal.bindArrayBuffer(geometry.normalsBuf); - this._aUV.bindArrayBuffer(geometry.uvBuf); - - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aOffset.bindArrayBuffer(state.offsetsBuf); + this._aNormal.bindArrayBuffer(state.normalsBuf); + this._aColor.bindArrayBuffer(state.colorsBuf);// Needed for masking out transparent entities using alpha channel this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - if (this._aFlags2) { this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - geometry.indicesBuf.bind(); - - gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - - frameCtx.drawElements++; - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); - gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aColor.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - - if (this._aFlags2) { // Won't be in shader when not clipping - gl.vertexAttribDivisor(this._aFlags2.location, 0); - } - - if (this._aOffset) { - gl.vertexAttribDivisor(this._aOffset.location, 0); - } - - if (textureSet) { - if (textureSet.colorTexture) { - this._program.bindTexture(this._uColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); - frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; - } } + state.indicesBuf.bind(); - if (this._withSAO) { - const sao = scene.sao; - const saoEnabled = sao.possible; - if (saoEnabled) { - const viewportWidth = gl.drawingBufferWidth; - const viewportHeight = gl.drawingBufferHeight; - tempVec4[0] = viewportWidth; - tempVec4[1] = viewportHeight; - tempVec4[2] = sao.blendCutoff; - tempVec4[3] = sao.blendFactor; - gl.uniform4fv(this._uSAOParams, tempVec4); - this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); - } - } + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; - const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -53678,49 +56565,12 @@ class TrianglesInstancingColorTextureRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - - this._uLightAmbient = program.getLocation("lightAmbient"); - this._uLightColor = []; - this._uLightDir = []; - this._uLightPos = []; - this._uLightAttenuation = []; - - const lights = lightsState.lights; - let light; - - for (let i = 0, len = lights.length; i < len; i++) { - light = lights[i]; - switch (light.type) { - case "dir": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = null; - this._uLightDir[i] = program.getLocation("lightDir" + i); - break; - case "point": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = null; - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - case "spot": - this._uLightColor[i] = program.getLocation("lightColor" + i); - this._uLightPos[i] = program.getLocation("lightPos" + i); - this._uLightDir[i] = program.getLocation("lightDir" + i); - this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); - break; - } - } - this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -53732,64 +56582,31 @@ class TrianglesInstancingColorTextureRenderer { } this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); this._aNormal = program.getAttribute("normal"); this._aColor = program.getAttribute("color"); - this._aUV = program.getAttribute("uv"); this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); - this._aOffset = program.getAttribute("offset"); - - this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); - this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); - this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - - this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); - this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); - this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); - - this._uColorMap = "uColorMap"; - this._uOcclusionTexture = "uOcclusionTexture"; - this._uSAOParams = program.getLocation("uSAOParams"); + if (this._aFlags2) { // Won't be in shader when not clipping + this._aFlags2 = program.getAttribute("flags2"); + } - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram(frameCtx) { + _bindProgram() { const scene = this._scene; const gl = scene.canvas.gl; - const lightsState = scene._lightsState; - const lights = lightsState.lights; const project = scene.camera.project; this._program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - if (this._uLightAmbient) { - gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); - } - - for (let i = 0, len = lights.length; i < len; i++) { - const light = lights[i]; - if (this._uLightColor[i]) { - gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); - } - if (this._uLightPos[i]) { - gl.uniform3fv(this._uLightPos[i], light.pos); - if (this._uLightAttenuation[i]) { - gl.uniform1f(this._uLightAttenuation[i], light.attenuation); - } - } - if (this._uLightDir[i]) { - gl.uniform3fv(this._uLightDir[i], light.dir); - } - } - - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } @@ -53804,45 +56621,25 @@ class TrianglesInstancingColorTextureRenderer { _buildVertexShader() { const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const lightsState = scene._lightsState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; - let i; - let len; - let light; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry drawing vertex shader"); - + src.push("// Batched geometry normals vertex shader"); src.push("uniform int renderPass;"); - src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } src.push("in vec3 normal;"); src.push("in vec4 color;"); - src.push("in vec2 uv;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } - - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix - src.push("in vec4 modelMatrixCol1;"); - src.push("in vec4 modelMatrixCol2;"); - - src.push("in vec4 modelNormalMatrixCol0;"); - src.push("in vec4 modelNormalMatrixCol1;"); - src.push("in vec4 modelNormalMatrixCol2;"); - src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 worldNormalMatrix;"); src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform mat3 uvDecodeMatrix;"); - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); @@ -53851,27 +56648,6 @@ class TrianglesInstancingColorTextureRenderer { src.push("}"); src.push("out float isPerspective;"); } - - src.push("uniform vec4 lightAmbient;"); - - for (i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - src.push("uniform vec4 lightColor" + i + ";"); - if (light.type === "dir") { - src.push("uniform vec3 lightDir" + i + ";"); - } - if (light.type === "point") { - src.push("uniform vec3 lightPos" + i + ";"); - } - if (light.type === "spot") { - src.push("uniform vec3 lightPos" + i + ";"); - src.push("uniform vec3 lightDir" + i + ";"); - } - } - src.push("vec3 octDecode(vec2 oct) {"); src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); src.push(" if (v.z < 0.0) {"); @@ -53879,87 +56655,39 @@ class TrianglesInstancingColorTextureRenderer { src.push(" }"); src.push(" return normalize(v);"); src.push("}"); - if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vColor;"); - src.push("out vec2 vUV;"); - + src.push("out vec3 vViewNormal;"); src.push("void main(void) {"); // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - - src.push("} else {"); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - - src.push("vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); - src.push("vec4 worldNormal = worldNormalMatrix * vec4(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2), 0.0);"); - src.push("vec3 viewNormal = normalize(vec4(viewNormalMatrix * worldNormal).xyz);"); - - src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); - src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); - - src.push("float lambertian = 1.0;"); - for (i = 0, len = lightsState.lights.length; i < len; i++) { - light = lightsState.lights[i]; - if (light.type === "ambient") { - continue; - } - if (light.type === "dir") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "point") { - if (light.space === "view") { - src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); - } else { - src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); - } - } else if (light.type === "spot") { - if (light.space === "view") { - src.push("viewLightDir = normalize(lightDir" + i + ");"); - } else { - src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); - } - } else { - continue; - } - src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); - src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); + src.push(" vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - - src.push("vec3 rgb = (vec3(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0));"); - src.push("vColor = vec4((lightAmbient.rgb * lightAmbient.a * rgb) + (reflectedColor * rgb), float(color.a) / 255.0);"); - src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); - + src.push(" vViewNormal = viewNormal;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } - - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } - src.push("gl_Position = clipPos;"); - src.push("}"); + src.push(" }"); src.push("}"); return src; } @@ -53967,10 +56695,12 @@ class TrianglesInstancingColorTextureRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clipping = (sectionPlanesState.sectionPlanes.length > 0); const src = []; src.push("#version 300 es"); - src.push("// Instancing geometry drawing fragment shader"); + src.push("// Batched geometry normals fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); @@ -53979,76 +56709,45 @@ class TrianglesInstancingColorTextureRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } - src.push("uniform sampler2D uColorMap;"); - if (this._withSAO) { - src.push("uniform sampler2D uOcclusionTexture;"); - src.push("uniform vec4 uSAOParams;"); - - src.push("const float packUpscale = 256. / 255.;"); - src.push("const float unpackDownScale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); - - src.push("float unpackRGBToFloat( const in vec4 v ) {"); - src.push(" return dot( v, unPackFactors );"); - src.push("}"); - } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vColor;"); - src.push("in vec2 vUV;"); + src.push("in vec3 vViewNormal;"); + src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); + src.push(" return normalize( normal ) * 0.5 + 0.5;"); + src.push("}"); src.push("out vec4 outColor;"); - src.push("void main(void) {"); + src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); } - src.push(" if (dist > 0.0) { "); - src.push(" discard;"); + src.push(" if (dist > 0.0) { discard; }"); src.push(" }"); - src.push("}"); } - if (scene.logarithmicDepthBufferEnabled) { src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - - src.push("vec4 colorTexel = texture(uColorMap, vUV);"); - src.push("float opacity = vColor.a;"); - - // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top - // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - - if (this._withSAO) { - src.push(" float viewportWidth = uSAOParams[0];"); - src.push(" float viewportHeight = uSAOParams[1];"); - src.push(" float blendCutoff = uSAOParams[2];"); - src.push(" float blendFactor = uSAOParams[3];"); - src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" outColor = vec4(vColor.rgb * colorTexel.rgb * ambient, opacity);"); - } else { - src.push(" outColor = vec4(vColor.rgb * colorTexel.rgb, opacity);"); - } + src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); src.push("}"); return src; } @@ -54065,1387 +56764,1131 @@ class TrianglesInstancingColorTextureRenderer { } } +const tempVec3a$K = math.vec3(); + /** + * Renders BatchingLayer fragment depths to a shadow map. + * * @private */ -class TrianglesInstancingRenderers { +class TrianglesBatchingShadowRenderer { constructor(scene) { this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - _compile() { - if (this._colorRenderer && (!this._colorRenderer.getValid())) { - this._colorRenderer.destroy(); - this._colorRenderer = null; + getValid() { + return this._hash === this._getHash(); + }; + + _getHash() { + return this._scene._sectionPlanesState.getHash(); + } + + drawLayer(frameCtx, batchingLayer) { + const scene = this._scene; + const gl = scene.canvas.gl; + const state = batchingLayer._state; + if (!this._program) { + this._allocate(); } - if (this._colorRendererWithSAO && (!this._colorRendererWithSAO.getValid())) { - this._colorRendererWithSAO.destroy(); - this._colorRendererWithSAO = null; + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx); } - if (this._flatColorRenderer && (!this._flatColorRenderer.getValid())) { - this._flatColorRenderer.destroy(); - this._flatColorRenderer = null; + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + if (scene.logarithmicDepthBufferEnabled) { + gl.uniform1f(this._uZFar, scene.camera.project.far); } - if (this._flatColorRendererWithSAO && (!this._flatColorRendererWithSAO.getValid())) { - this._flatColorRendererWithSAO.destroy(); - this._flatColorRendererWithSAO = null; + this._aPosition.bindArrayBuffer(state.positionsBuf); + if (this._aColor) { // Needed for masking out transparent entities using alpha channel + this._aColor.bindArrayBuffer(state.colorsBuf); } - if (this._pbrRenderer && (!this._pbrRenderer.getValid())) { - this._pbrRenderer.destroy(); - this._pbrRenderer = null; - } - if (this._pbrRendererWithSAO && (!this._pbrRendererWithSAO.getValid())) { - this._pbrRendererWithSAO.destroy(); - this._pbrRendererWithSAO = null; - } - if (this._colorTextureRenderer && (!this._colorTextureRenderer.getValid())) { - this._colorTextureRenderer.destroy(); - this._colorTextureRenderer = null; - } - if (this._colorTextureRendererWithSAO && (!this._colorTextureRendererWithSAO.getValid())) { - this._colorTextureRendererWithSAO.destroy(); - this._colorTextureRendererWithSAO = null; - } - if (this._depthRenderer && (!this._depthRenderer.getValid())) { - this._depthRenderer.destroy(); - this._depthRenderer = null; - } - if (this._normalsRenderer && (!this._normalsRenderer.getValid())) { - this._normalsRenderer.destroy(); - this._normalsRenderer = null; - } - if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { - this._silhouetteRenderer.destroy(); - this._silhouetteRenderer = null; - } - if (this._edgesRenderer && (!this._edgesRenderer.getValid())) { - this._edgesRenderer.destroy(); - this._edgesRenderer = null; - } - if (this._edgesColorRenderer && (!this._edgesColorRenderer.getValid())) { - this._edgesColorRenderer.destroy(); - this._edgesColorRenderer = null; + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { - this._pickMeshRenderer.destroy(); - this._pickMeshRenderer = null; + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { - this._pickDepthRenderer.destroy(); - this._pickDepthRenderer = null; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - if (this._pickNormalsRenderer && this._pickNormalsRenderer.getValid() === false) { - this._pickNormalsRenderer.destroy(); - this._pickNormalsRenderer = null; + state.indicesBuf.bind(); + + // TODO: Section planes need to be set if RTC center has changed since last RTC center recorded on frameCtx + + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + const origin = batchingLayer._state.origin; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$K); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - if (this._pickNormalsFlatRenderer && (!this._pickNormalsFlatRenderer.getValid())) { - this._pickNormalsFlatRenderer.destroy(); - this._pickNormalsFlatRenderer = null; + + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + } + + _allocate() { + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; + this._program = new Program(gl, this._buildShader()); + if (this._program.errors) { + this.errors = this._program.errors; + return; } - if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { - this._occlusionRenderer.destroy(); - this._occlusionRenderer = null; + const program = this._program; + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uShadowViewMatrix = program.getLocation("shadowViewMatrix"); + this._uShadowProjMatrix = program.getLocation("shadowProjMatrix"); + if (scene.logarithmicDepthBufferEnabled) { + this._uZFar = program.getLocation("zFar"); } - if (this._shadowRenderer && (!this._shadowRenderer.getValid())) { - this._shadowRenderer.destroy(); - this._shadowRenderer = null; + this._uSectionPlanes = []; + const sectionPlanes = sectionPlanesState.sectionPlanes; + for (let i = 0, len = sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); } - get colorRenderer() { - if (!this._colorRenderer) { - this._colorRenderer = new TrianglesInstancingColorRenderer(this._scene, false); - } - return this._colorRenderer; + _bindProgram(frameCtx) { + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + program.bind(); + gl.uniformMatrix4fv(this._uShadowViewMatrix, false, frameCtx.shadowViewMatrix); + gl.uniformMatrix4fv(this._uShadowProjMatrix, false, frameCtx.shadowProjMatrix); + this._lastLightId = null; } - get colorRendererWithSAO() { - if (!this._colorRendererWithSAO) { - this._colorRendererWithSAO = new TrianglesInstancingColorRenderer(this._scene, true); - } - return this._colorRendererWithSAO; + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - get flatColorRenderer() { - if (!this._flatColorRenderer) { - this._flatColorRenderer = new TrianglesInstancingFlatColorRenderer(this._scene, false); - } - return this._flatColorRenderer; - } - get flatColorRendererWithSAO() { - if (!this._flatColorRendererWithSAO) { - this._flatColorRendererWithSAO = new TrianglesInstancingFlatColorRenderer(this._scene, true); + _buildVertexShader() { + const scene = this._scene; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push("#version 300 es"); + src.push("// Batched geometry shadow vertex shader"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - return this._flatColorRendererWithSAO; - } - - get pbrRenderer() { - if (!this._pbrRenderer) { - this._pbrRenderer = new TrianglesInstancingPBRRenderer(this._scene, false); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("uniform mat4 shadowViewMatrix;"); + src.push("uniform mat4 shadowProjMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - return this._pbrRenderer; - } - - get pbrRendererWithSAO() { - if (!this._pbrRendererWithSAO) { - this._pbrRendererWithSAO = new TrianglesInstancingPBRRenderer(this._scene, true); + src.push("out vec4 vViewPosition;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + src.push(" bool visible = (float(flags.x) > 0.0);"); + src.push(" bool transparent = ((float(color.a) / 255.0) < 1.0);"); + src.push(" if (!visible || transparent) {"); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); + src.push(" } else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - return this._pbrRendererWithSAO; - } - - get colorTextureRenderer() { - if (!this._colorTextureRenderer) { - this._colorTextureRenderer = new TrianglesInstancingColorTextureRenderer(this._scene, false); + src.push(" vec4 viewPosition = shadowViewMatrix * worldPosition; "); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - return this._colorTextureRenderer; + src.push(" vViewPosition = viewPosition;"); + src.push(" gl_Position = shadowProjMatrix * viewPosition;"); + src.push(" }"); + src.push("}"); + return src; } - get colorTextureRendererWithSAO() { - if (!this._colorTextureRendererWithSAO) { - this._colorTextureRendererWithSAO = new TrianglesInstancingColorTextureRenderer(this._scene, true); + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = (sectionPlanesState.sectionPlanes.length > 0); + const src = []; + src.push("#version 300 es"); + src.push("// Batched geometry shadow fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } } - return this._colorTextureRendererWithSAO; - } + src.push("in vec4 vViewPosition;"); - get silhouetteRenderer() { - if (!this._silhouetteRenderer) { - this._silhouetteRenderer = new TrianglesInstancingSilhouetteRenderer(this._scene); + src.push("vec4 encodeFloat( const in float v ) {"); + src.push(" const vec4 bitShift = vec4(256 * 256 * 256, 256 * 256, 256, 1.0);"); + src.push(" const vec4 bitMask = vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);"); + src.push(" vec4 comp = fract(v * bitShift);"); + src.push(" comp -= comp.xxyz * bitMask;"); + src.push(" return comp;"); + src.push("}"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } - return this._silhouetteRenderer; + src.push(" outColor = encodeFloat( gl_FragCoord.z); "); + src.push("}"); + return src; } - get depthRenderer() { - if (!this._depthRenderer) { - this._depthRenderer = new TrianglesInstancingDepthRenderer(this._scene); - } - return this._depthRenderer; + webglContextRestored() { + this._program = null; } - get normalsRenderer() { - if (!this._normalsRenderer) { - this._normalsRenderer = new TrianglesInstancingNormalsRenderer(this._scene); + destroy() { + if (this._program) { + this._program.destroy(); } - return this._normalsRenderer; + this._program = null; } +} - get edgesRenderer() { - if (!this._edgesRenderer) { - this._edgesRenderer = new TrianglesInstancingEdgesRenderer(this._scene); - } - return this._edgesRenderer; - } +const tempVec4$5 = math.vec4(); +const tempVec3a$J = math.vec3(); - get edgesColorRenderer() { - if (!this._edgesColorRenderer) { - this._edgesColorRenderer = new TrianglesInstancingEdgesColorRenderer(this._scene); - } - return this._edgesColorRenderer; - } +// const TEXTURE_DECODE_FUNCS = {}; +// TEXTURE_DECODE_FUNCS[LinearEncoding] = "linearToLinear"; +// TEXTURE_DECODE_FUNCS[sRGBEncoding] = "sRGBToLinear"; - get pickMeshRenderer() { - if (!this._pickMeshRenderer) { - this._pickMeshRenderer = new TrianglesInstancingPickMeshRenderer(this._scene); - } - return this._pickMeshRenderer; - } +/** + * @private + */ +class TrianglesBatchingPBRRenderer { - get pickNormalsRenderer() { - if (!this._pickNormalsRenderer) { - this._pickNormalsRenderer = new TrianglesInstancingPickNormalsRenderer(this._scene); - } - return this._pickNormalsRenderer; + constructor(scene, withSAO) { + this._scene = scene; + this._withSAO = withSAO; + this._hash = this._getHash(); + this._allocate(); } - get pickNormalsFlatRenderer() { - if (!this._pickNormalsFlatRenderer) { - this._pickNormalsFlatRenderer = new TrianglesInstancingPickNormalsFlatRenderer(this._scene); - } - return this._pickNormalsFlatRenderer; - } + getValid() { + return this._hash === this._getHash(); + }; - get pickDepthRenderer() { - if (!this._pickDepthRenderer) { - this._pickDepthRenderer = new TrianglesInstancingPickDepthRenderer(this._scene); - } - return this._pickDepthRenderer; + _getHash() { + const scene = this._scene; + return [scene.gammaOutput, scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } - get occlusionRenderer() { - if (!this._occlusionRenderer) { - this._occlusionRenderer = new TrianglesInstancingOcclusionRenderer(this._scene); - } - return this._occlusionRenderer; - } + drawLayer(frameCtx, batchingLayer, renderPass) { - get shadowRenderer() { - if (!this._shadowRenderer) { - this._shadowRenderer = new TrianglesInstancingShadowRenderer(this._scene); - } - return this._shadowRenderer; - } + const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; - _destroy() { - if (this._colorRenderer) { - this._colorRenderer.destroy(); - } - if (this._colorRendererWithSAO) { - this._colorRendererWithSAO.destroy(); - } - if (this._flatColorRenderer) { - this._flatColorRenderer.destroy(); - } - if (this._flatColorRendererWithSAO) { - this._flatColorRendererWithSAO.destroy(); - } - if (this._pbrRenderer) { - this._pbrRenderer.destroy(); - } - if (this._pbrRendererWithSAO) { - this._pbrRendererWithSAO.destroy(); - } - if (this._colorTextureRenderer) { - this._colorTextureRenderer.destroy(); - } - if (this._colorTextureRendererWithSAO) { - this._colorTextureRendererWithSAO.destroy(); + const scene = this._scene; + const camera = scene.camera; + const model = batchingLayer.model; + const gl = scene.canvas.gl; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; + const textureSet = state.textureSet; + const lightsState = scene._lightsState; + + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } } - if (this._depthRenderer) { - this._depthRenderer.destroy(); + + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx); } - if (this._normalsRenderer) { - this._normalsRenderer.destroy(); + + gl.uniform1i(this._uRenderPass, renderPass); + + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); + + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$J); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - if (this._silhouetteRenderer) { - this._silhouetteRenderer.destroy(); + + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, state.positionsDecodeMatrix); + + if (this._uUVDecodeMatrix) { + gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, state.uvDecodeMatrix); } - if (this._edgesRenderer) { - this._edgesRenderer.destroy(); + + this._aPosition.bindArrayBuffer(state.positionsBuf); + + if (this._aNormal) { + this._aNormal.bindArrayBuffer(state.normalsBuf); } - if (this._edgesColorRenderer) { - this._edgesColorRenderer.destroy(); + + if (this._aUV) { + this._aUV.bindArrayBuffer(state.uvBuf); } - if (this._pickMeshRenderer) { - this._pickMeshRenderer.destroy(); + + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); } - if (this._pickDepthRenderer) { - this._pickDepthRenderer.destroy(); + + if (this._aMetallicRoughness) { + this._aMetallicRoughness.bindArrayBuffer(state.metallicRoughnessBuf); } - if (this._pickNormalsRenderer) { - this._pickNormalsRenderer.destroy(); + + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - if (this._pickNormalsFlatRenderer) { - this._pickNormalsFlatRenderer.destroy(); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - if (this._occlusionRenderer) { - this._occlusionRenderer.destroy(); + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - if (this._shadowRenderer) { - this._shadowRenderer.destroy(); + + if (lightsState.reflectionMaps.length > 0 && lightsState.reflectionMaps[0].texture && this._uReflectionMap) { + this._program.bindTexture(this._uReflectionMap, lightsState.reflectionMaps[0].texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; } - } -} -const cachedRenderers$4 = {}; + if (lightsState.lightMaps.length > 0 && lightsState.lightMaps[0].texture && this._uLightMap) { + this._program.bindTexture(this._uLightMap, lightsState.lightMaps[0].texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; + } -/** - * @private - */ -function getInstancingRenderers$1(scene) { - const sceneId = scene.id; - let instancingRenderers = cachedRenderers$4[sceneId]; - if (!instancingRenderers) { - instancingRenderers = new TrianglesInstancingRenderers(scene); - cachedRenderers$4[sceneId] = instancingRenderers; - instancingRenderers._compile(); - scene.on("compile", () => { - instancingRenderers._compile(); - }); - scene.on("destroyed", () => { - delete cachedRenderers$4[sceneId]; - instancingRenderers._destroy(); - }); - } - return instancingRenderers; -} + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$5[0] = viewportWidth; + tempVec4$5[1] = viewportHeight; + tempVec4$5[2] = sao.blendCutoff; + tempVec4$5[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$5); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; + } + } -const tempUint8Vec4$2 = new Uint8Array(4); -const tempVec4a$9 = math.vec4([0, 0, 0, 1]); -const tempVec4b$9 = math.vec4([0, 0, 0, 1]); -const tempVec4c$6 = math.vec4([0, 0, 0, 1]); -const tempVec3fa$2 = new Float32Array(3); + this._program.bindTexture(this._uBaseColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uMetallicRoughMap, textureSet.metallicRoughnessTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uEmissiveMap, textureSet.emissiveTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uNormalMap, textureSet.normalsTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uAOMap, textureSet.occlusionTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; -const tempVec3a$r = math.vec3(); -const tempVec3b$7 = math.vec3(); -const tempVec3c$4 = math.vec3(); -const tempVec3d$1 = math.vec3(); -const tempVec3e = math.vec3(); -const tempVec3f = math.vec3(); -const tempVec3g = math.vec3(); + state.indicesBuf.bind(); -/** - * @private - */ -class TrianglesInstancingLayer { + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - /** - * @param cfg - * @param cfg.layerIndex - * @param cfg.model - * @param cfg.geometry - * @param cfg.textureSet - * @param cfg.origin - */ - constructor(cfg) { + frameCtx.drawElements++; + } - /** - * Owner model - * @type {VBOSceneModel} - */ - this.model = cfg.model; + _allocate() { - /** - * State sorting key. - * @type {string} - */ - this.sortId = "TrianglesInstancingLayer" + (cfg.solid ? "-solid" : "-surface") + (cfg.normals ? "-normals" : "-autoNormals"); + const scene = this._scene; + const gl = scene.canvas.gl; + const lightsState = scene._lightsState; - /** - * Index of this InstancingLayer in VBOSceneModel#_layerList - * @type {Number} - */ - this.layerIndex = cfg.layerIndex; + this._program = new Program(gl, this._buildShader()); - this._instancingRenderers = getInstancingRenderers$1(cfg.model.scene); + if (this._program.errors) { + this.errors = this._program.errors; + return; + } - this._aabb = math.collapseAABB3(); + const program = this._program; - const stateCfg = { - numInstances: 0, - obb: math.OBB3(), - origin: math.vec3(), - geometry: cfg.geometry, - textureSet: cfg.textureSet, - pbrSupported: false // Set in #finalize if we have enough to support quality rendering - }; + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - this._state = new RenderState(stateCfg); + this._uGammaFactor = program.getLocation("gammaFactor"); - // These counts are used to avoid unnecessary render passes - this._numPortions = 0; - this._numVisibleLayerPortions = 0; - this._numTransparentLayerPortions = 0; - this._numXRayedLayerPortions = 0; - this._numHighlightedLayerPortions = 0; - this._numSelectedLayerPortions = 0; - this._numClippableLayerPortions = 0; - this._numEdgesLayerPortions = 0; - this._numPickableLayerPortions = 0; - this._numCulledLayerPortions = 0; + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; - /** @private */ - this.numIndices = cfg.geometry.numIndices; + const lights = lightsState.lights; + let light; - // Vertex arrays - this._colors = []; - this._metallicRoughness = []; - this._pickColors = []; - this._offsets = []; + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } - // Modeling matrix per instance, array for each column - this._modelMatrixCol0 = []; - this._modelMatrixCol1 = []; - this._modelMatrixCol2 = []; + if (lightsState.reflectionMaps.length > 0) { + this._uReflectionMap = "reflectionMap"; + } - // Modeling normal matrix per instance, array for each column - this._modelNormalMatrixCol0 = []; - this._modelNormalMatrixCol1 = []; - this._modelNormalMatrixCol2 = []; + if (lightsState.lightMaps.length > 0) { + this._uLightMap = "lightMap"; + } - this._portions = []; + this._uSectionPlanes = []; - if (cfg.origin) { - this._state.origin.set(cfg.origin); + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - this._finalized = false; + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aNormal = program.getAttribute("normal"); + this._aUV = program.getAttribute("uv"); + this._aColor = program.getAttribute("color"); + this._aMetallicRoughness = program.getAttribute("metallicRoughness"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - /** - * The axis-aligned World-space boundary of this InstancingLayer's positions. - * @type {*|Float64Array} - */ - this.aabb = math.collapseAABB3(); + this._uBaseColorMap = "uBaseColorMap"; + this._uMetallicRoughMap = "uMetallicRoughMap"; + this._uEmissiveMap = "uEmissiveMap"; + this._uNormalMap = "uNormalMap"; + this._uAOMap = "uAOMap"; - /** - * When true, this layer contains solid triangle meshes, otherwise this layer contains surface triangle meshes - * @type {boolean} - */ - this.solid = !!cfg.solid; + if (this._withSAO) { + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); + } + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - /** - * Creates a new portion within this InstancingLayer, returns the new portion ID. - * - * The portion will instance this InstancingLayer's geometry. - * - * Gives the portion the specified color and matrix. - * - * @param cfg Portion params - * @param cfg.color Color [0..255,0..255,0..255] - * @param cfg.metallic Metalness factor [0..255] - * @param cfg.roughness Roughness factor [0..255] - * @param cfg.opacity Opacity [0..255]. - * @param cfg.meshMatrix Flat float 4x4 matrix. - * @param [cfg.worldMatrix] Flat float 4x4 matrix. - * @param cfg.worldAABB Flat float AABB. - * @param cfg.pickColor Quantized pick color - * @returns {number} Portion ID. - */ - createPortion(cfg) { + _bindProgram(frameCtx) { + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + const lightsState = scene._lightsState; + const lights = lightsState.lights; + const project = scene.camera.project; - const color = cfg.color; - const metallic = cfg.metallic; - const roughness = cfg.roughness; - const opacity = cfg.opacity; - const meshMatrix = cfg.meshMatrix; - const worldMatrix = cfg.worldMatrix; - const worldAABB = cfg.aabb; - const pickColor = cfg.pickColor; + program.bind(); - if (this._finalized) { - throw "Already finalized"; + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); } - // TODO: find AABB for portion by transforming the geometry local AABB by the given meshMatrix? + for (let i = 0, len = lights.length; i < len; i++) { - const r = color[0]; // Color is pre-quantized by VBOSceneModel - const g = color[1]; - const b = color[2]; - color[3]; + const light = lights[i]; - this._colors.push(r); - this._colors.push(g); - this._colors.push(b); - this._colors.push(opacity); + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } - this._metallicRoughness.push((metallic !== null && metallic !== undefined) ? metallic : 0); - this._metallicRoughness.push((roughness !== null && roughness !== undefined) ? roughness : 255); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } - if (this.model.scene.entityOffsetsEnabled) { - this._offsets.push(0); - this._offsets.push(0); - this._offsets.push(0); + if (this._uGammaFactor) { + gl.uniform1f(this._uGammaFactor, scene.gammaFactor); } + } - this._modelMatrixCol0.push(meshMatrix[0]); - this._modelMatrixCol0.push(meshMatrix[4]); - this._modelMatrixCol0.push(meshMatrix[8]); - this._modelMatrixCol0.push(meshMatrix[12]); + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - this._modelMatrixCol1.push(meshMatrix[1]); - this._modelMatrixCol1.push(meshMatrix[5]); - this._modelMatrixCol1.push(meshMatrix[9]); - this._modelMatrixCol1.push(meshMatrix[13]); + _buildVertexShader() { - this._modelMatrixCol2.push(meshMatrix[2]); - this._modelMatrixCol2.push(meshMatrix[6]); - this._modelMatrixCol2.push(meshMatrix[10]); - this._modelMatrixCol2.push(meshMatrix[14]); + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clippingCaps = sectionPlanesState.clippingCaps; - if (this._state.geometry.normalsBuf) { + const src = []; - // Note: order of inverse and transpose doesn't matter + src.push("#version 300 es"); + src.push("// Triangles batching quality draw vertex shader"); - let transposedMat = math.transposeMat4(meshMatrix, math.mat4()); // TODO: Use cached matrix - let normalMatrix = math.inverseMat4(transposedMat); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("precision highp usampler2D;"); + src.push("precision highp isampler2D;"); + src.push("precision highp sampler2D;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("precision mediump usampler2D;"); + src.push("precision mediump isampler2D;"); + src.push("precision mediump sampler2D;"); + src.push("#endif"); - this._modelNormalMatrixCol0.push(normalMatrix[0]); - this._modelNormalMatrixCol0.push(normalMatrix[4]); - this._modelNormalMatrixCol0.push(normalMatrix[8]); - this._modelNormalMatrixCol0.push(normalMatrix[12]); + src.push("uniform int renderPass;"); - this._modelNormalMatrixCol1.push(normalMatrix[1]); - this._modelNormalMatrixCol1.push(normalMatrix[5]); - this._modelNormalMatrixCol1.push(normalMatrix[9]); - this._modelNormalMatrixCol1.push(normalMatrix[13]); + src.push("in vec3 position;"); + src.push("in vec3 normal;"); + src.push("in vec4 color;"); + src.push("in vec2 uv;"); + src.push("in vec2 metallicRoughness;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - this._modelNormalMatrixCol2.push(normalMatrix[2]); - this._modelNormalMatrixCol2.push(normalMatrix[6]); - this._modelNormalMatrixCol2.push(normalMatrix[10]); - this._modelNormalMatrixCol2.push(normalMatrix[14]); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - // Per-vertex pick colors - - this._pickColors.push(pickColor[0]); - this._pickColors.push(pickColor[1]); - this._pickColors.push(pickColor[2]); - this._pickColors.push(pickColor[3]); - - // Expand AABB + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 worldNormalMatrix;"); - math.collapseAABB3(worldAABB); - const obb = this._state.geometry.obb; - const lenPositions = obb.length; - for (let i = 0; i < lenPositions; i += 4) { - tempVec4a$9[0] = obb[i + 0]; - tempVec4a$9[1] = obb[i + 1]; - tempVec4a$9[2] = obb[i + 2]; - math.transformPoint4(meshMatrix, tempVec4a$9, tempVec4b$9); - if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4b$9, tempVec4c$6); - math.expandAABB3Point3(worldAABB, tempVec4c$6); - } else { - math.expandAABB3Point3(worldAABB, tempVec4b$9); - } - } + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 viewNormalMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + src.push("uniform mat3 uvDecodeMatrix;"); - if (this._state.origin) { - const origin = this._state.origin; - worldAABB[0] += origin[0]; - worldAABB[1] += origin[1]; - worldAABB[2] += origin[2]; - worldAABB[3] += origin[0]; - worldAABB[4] += origin[1]; - worldAABB[5] += origin[2]; + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } - math.expandAABB3(this.aabb, worldAABB); - - this._state.numInstances++; + src.push("vec3 octDecode(vec2 oct) {"); + src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); + src.push(" if (v.z < 0.0) {"); + src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); + src.push(" }"); + src.push(" return normalize(v);"); + src.push("}"); - const portionId = this._portions.length; + src.push("out vec4 vViewPosition;"); + src.push("out vec3 vViewNormal;"); + src.push("out vec4 vColor;"); + src.push("out vec2 vUV;"); + src.push("out vec2 vMetallicRoughness;"); - const portion = {}; + if (lightsState.lightMaps.length > 0) { + src.push("out vec3 vWorldNormal;"); + } - if (this.model.scene.pickSurfacePrecisionEnabled) { - portion.matrix = meshMatrix.slice(); - portion.inverseMatrix = null; // Lazy-computed in precisionRayPickSurface - portion.normalMatrix = null; // Lazy-computed in precisionRayPickSurface + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + if (clippingCaps) { + src.push("out vec4 vClipPosition;"); + } } - this._portions.push(portion); + src.push("void main(void) {"); - this._numPortions++; - this.model.numPortions++; + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - return portionId; - } + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - finalize() { - if (this._finalized) { - throw "Already finalized"; - } - const state = this._state; - const geometry = state.geometry; - const textureSet = state.textureSet; - const gl = this.model.scene.canvas.gl; - const colorsLength = this._colors.length; - const flagsLength = colorsLength; - if (colorsLength > 0) { - let notNormalized = false; - this._state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._colors), this._colors.length, 4, gl.DYNAMIC_DRAW, notNormalized); - this._colors = []; // Release memory - } - if (this._metallicRoughness.length > 0) { - const metallicRoughness = new Uint8Array(this._metallicRoughness); - let normalized = false; - this._state.metallicRoughnessBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, metallicRoughness, this._metallicRoughness.length, 2, gl.STATIC_DRAW, normalized); + src.push("} else {"); + + src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push("worldPosition.xyz = worldPosition.xyz + offset;"); } - if (flagsLength > 0) { - // Because we only build flags arrays here, - // get their length from the colors array - let notNormalized = false; - let normalized = true; - this._state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, notNormalized); - this._state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, normalized); + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); + src.push("vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); + + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + src.push("vFragDepth = 1.0 + clipPos.w;"); } - if (this.model.scene.entityOffsetsEnabled) { - if (this._offsets.length > 0) { - const notNormalized = false; - this._state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._offsets), this._offsets.length, 3, gl.DYNAMIC_DRAW, notNormalized); - this._offsets = []; // Release memory + + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + if (clippingCaps) { + src.push("vClipPosition = clipPos;"); } } - if (this._modelMatrixCol0.length > 0) { - const normalized = false; - - this._state.modelMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol0), this._modelMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); - this._state.modelMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol1), this._modelMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); - this._state.modelMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol2), this._modelMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); - this._modelMatrixCol0 = []; - this._modelMatrixCol1 = []; - this._modelMatrixCol2 = []; + src.push("vViewPosition = viewPosition;"); + src.push("vViewNormal = viewNormal;"); + src.push("vColor = color;"); + src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); + src.push("vMetallicRoughness = metallicRoughness;"); - if (this._state.geometry.normalsBuf) { - this._state.modelNormalMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelNormalMatrixCol0), this._modelNormalMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); - this._state.modelNormalMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelNormalMatrixCol1), this._modelNormalMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); - this._state.modelNormalMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelNormalMatrixCol2), this._modelNormalMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); - this._modelNormalMatrixCol0 = []; - this._modelNormalMatrixCol1 = []; - this._modelNormalMatrixCol2 = []; - } - } - if (this._pickColors.length > 0) { - const normalized = false; - this._state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._pickColors), this._pickColors.length, 4, gl.STATIC_DRAW, normalized); - this._pickColors = []; // Release memory + if (lightsState.lightMaps.length > 0) { + src.push("vWorldNormal = worldNormal.xyz;"); } - this._state.pbrSupported - = !!state.metallicRoughnessBuf - && !!geometry.uvBuf - && !!geometry.normalsBuf - && !!textureSet - && !!textureSet.colorTexture - && !!textureSet.metallicRoughnessTexture; - - this._state.colorTextureSupported - = !!geometry.uvBuf - && !!geometry.normalsBuf - && !!textureSet - && !!textureSet.colorTexture; + src.push("gl_Position = clipPos;"); + src.push("}"); - this._finalized = true; + src.push("}"); + return src; } - // The following setters are called by VBOSceneModelMesh, in turn called by VBOSceneModelNode, only after the layer is finalized. - // It's important that these are called after finalize() in order to maintain integrity of counts like _numVisibleLayerPortions etc. + _buildFragmentShader() { - initFlags(portionId, flags, meshTransparent) { - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } - if (flags & ENTITY_FLAGS.EDGES) { - this._numEdgesLayerPortions++; - this.model.numEdgesLayerPortions++; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } - if (meshTransparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } - this._setFlags(portionId, flags, meshTransparent); - this._setFlags2(portionId, flags); - } + const scene = this._scene; + const gammaOutput = scene.gammaOutput; // If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is false. + const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clippingCaps = sectionPlanesState.clippingCaps; + const src = []; - setVisible(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } else { - this._numVisibleLayerPortions--; - this.model.numVisibleLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } + src.push('#version 300 es'); + src.push("// Triangles batching quality draw fragment shader"); - setHighlighted(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } else { - this._numHighlightedLayerPortions--; - this.model.numHighlightedLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); - setXRayed(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } else { - this._numXRayedLayerPortions--; - this.model.numXRayedLayerPortions--; + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - this._setFlags(portionId, flags, meshTransparent); - } - setSelected(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } else { - this._numSelectedLayerPortions--; - this.model.numSelectedLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } + src.push("uniform sampler2D uBaseColorMap;"); + src.push("uniform sampler2D uMetallicRoughMap;"); + src.push("uniform sampler2D uEmissiveMap;"); + src.push("uniform sampler2D uNormalMap;"); + src.push("uniform sampler2D uAOMap;"); - setEdges(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.EDGES) { - this._numEdgesLayerPortions++; - this.model.numEdgesLayerPortions++; - } else { - this._numEdgesLayerPortions--; - this.model.numEdgesLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } + src.push("in vec4 vViewPosition;"); + src.push("in vec3 vViewNormal;"); + src.push("in vec4 vColor;"); + src.push("in vec2 vUV;"); + src.push("in vec2 vMetallicRoughness;"); - setClippable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } else { - this._numClippableLayerPortions--; - this.model.numClippableLayerPortions--; + if (lightsState.lightMaps.length > 0) { + src.push("in vec3 vWorldNormal;"); } - this._setFlags2(portionId, flags); - } - setCollidable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } - } + src.push("uniform mat4 viewMatrix;"); - setPickable(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } else { - this._numPickableLayerPortions--; - this.model.numPickableLayerPortions--; + if (lightsState.reflectionMaps.length > 0) { + src.push("uniform samplerCube reflectionMap;"); } - this._setFlags2(portionId, flags, meshTransparent); - } - setCulled(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } else { - this._numCulledLayerPortions--; - this.model.numCulledLayerPortions--; + if (lightsState.lightMaps.length > 0) { + src.push("uniform samplerCube lightMap;"); } - this._setFlags(portionId, flags, meshTransparent); - } - setColor(portionId, color) { // RGBA color is normalized as ints - if (!this._finalized) { - throw "Not finalized"; - } - tempUint8Vec4$2[0] = color[0]; - tempUint8Vec4$2[1] = color[1]; - tempUint8Vec4$2[2] = color[2]; - tempUint8Vec4$2[3] = color[3]; - if (this._state.colorsBuf) { - this._state.colorsBuf.setData(tempUint8Vec4$2, portionId * 4, 4); - } - } + src.push("uniform vec4 lightAmbient;"); - setTransparent(portionId, flags, transparent) { - if (transparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } else { - this._numTransparentLayerPortions--; - this.model.numTransparentLayerPortions--; + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } } - this._setFlags(portionId, flags, transparent); - } - // setMatrix(portionId, matrix) { - // - // if (!this._finalized) { - // throw "Not finalized"; - // } - // - // var offset = portionId * 4; - // - // tempFloat32Vec4[0] = matrix[0]; - // tempFloat32Vec4[1] = matrix[4]; - // tempFloat32Vec4[2] = matrix[8]; - // tempFloat32Vec4[3] = matrix[12]; - // - // this._state.modelMatrixCol0Buf.setData(tempFloat32Vec4, offset, 4); - // - // tempFloat32Vec4[0] = matrix[1]; - // tempFloat32Vec4[1] = matrix[5]; - // tempFloat32Vec4[2] = matrix[9]; - // tempFloat32Vec4[3] = matrix[13]; - // - // this._state.modelMatrixCol1Buf.setData(tempFloat32Vec4, offset, 4); - // - // tempFloat32Vec4[0] = matrix[2]; - // tempFloat32Vec4[1] = matrix[6]; - // tempFloat32Vec4[2] = matrix[10]; - // tempFloat32Vec4[3] = matrix[14]; - // - // this._state.modelMatrixCol2Buf.setData(tempFloat32Vec4, offset, 4); - // } + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); - _setFlags(portionId, flags, meshTransparent) { + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); - if (!this._finalized) { - throw "Not finalized"; + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); } - const visible = !!(flags & ENTITY_FLAGS.VISIBLE); - const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); - const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); - const selected = !!(flags & ENTITY_FLAGS.SELECTED); - const edges = !!(flags & ENTITY_FLAGS.EDGES); - const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); - const culled = !!(flags & ENTITY_FLAGS.CULLED); + src.push("uniform float gammaFactor;"); + src.push("vec4 linearToLinear( in vec4 value ) {"); + src.push(" return value;"); + src.push("}"); + src.push("vec4 sRGBToLinear( in vec4 value ) {"); + src.push(" return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );"); + src.push("}"); + src.push("vec4 gammaToLinear( in vec4 value) {"); + src.push(" return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );"); + src.push("}"); - // Normal fill + if (gammaOutput) { + src.push("vec4 linearToGamma( in vec4 value, in float gammaFactor ) {"); + src.push(" return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );"); + src.push("}"); + } - let f0; - if (!visible || culled || xrayed - || (highlighted && !this.model.scene.highlightMaterial.glowThrough) - || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { - f0 = RENDER_PASSES.NOT_RENDERED; - } else { - if (meshTransparent) { - f0 = RENDER_PASSES.COLOR_TRANSPARENT; - } else { - f0 = RENDER_PASSES.COLOR_OPAQUE; + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + if (clippingCaps) { + src.push("in vec4 vClipPosition;"); + } + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - // Emphasis fill + // CONSTANT DEFINITIONS - let f1; - if (!visible || culled) { - f1 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f1 = RENDER_PASSES.SILHOUETTE_SELECTED; - } else if (highlighted) { - f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; - } else if (xrayed) { - f1 = RENDER_PASSES.SILHOUETTE_XRAYED; - } else { - f1 = RENDER_PASSES.NOT_RENDERED; - } + src.push("#define PI 3.14159265359"); + src.push("#define RECIPROCAL_PI 0.31830988618"); + src.push("#define RECIPROCAL_PI2 0.15915494"); + src.push("#define EPSILON 1e-6"); - // Edges + src.push("#define saturate(a) clamp( a, 0.0, 1.0 )"); - let f2 = 0; - if (!visible || culled) { - f2 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f2 = RENDER_PASSES.EDGES_SELECTED; - } else if (highlighted) { - f2 = RENDER_PASSES.EDGES_HIGHLIGHTED; - } else if (xrayed) { - f2 = RENDER_PASSES.EDGES_XRAYED; - } else if (edges) { - if (meshTransparent) { - f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT; - } else { - f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE; - } - } else { - f2 = RENDER_PASSES.NOT_RENDERED; - } + // UTILITY DEFINITIONS - // Pick + src.push("vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {"); + src.push(" vec3 texel = texture( uNormalMap, uv ).xyz;"); + src.push(" if (texel.x == 0.0 && texel.y == 0.0 && texel.z == 0.0) {"); + src.push(" return surf_norm;"); + src.push(" }"); + src.push(" vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );"); + src.push(" vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );"); + src.push(" vec2 st0 = dFdx( uv.st );"); + src.push(" vec2 st1 = dFdy( uv.st );"); + src.push(" vec3 S = normalize( q0 * st1.t - q1 * st0.t );"); + src.push(" vec3 T = normalize( -q0 * st1.s + q1 * st0.s );"); + src.push(" vec3 N = normalize( surf_norm );"); + src.push(" vec3 mapN = texel.xyz * 2.0 - 1.0;"); + src.push(" mat3 tsn = mat3( S, T, N );"); + //src.push(" mapN *= 3.0;"); + src.push(" return normalize( tsn * mapN );"); + src.push("}"); - let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; + src.push("vec3 inverseTransformDirection(in vec3 dir, in mat4 matrix) {"); + src.push(" return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );"); + src.push("}"); - tempUint8Vec4$2[0] = f0; // x - normal fill - tempUint8Vec4$2[1] = f1; // y - emphasis fill - tempUint8Vec4$2[2] = f2; // z - edges - tempUint8Vec4$2[3] = f3; // w - pick + // STRUCTURES - if (this._state.flagsBuf) { - this._state.flagsBuf.setData(tempUint8Vec4$2, portionId * 4, 4); - } - } + src.push("struct IncidentLight {"); + src.push(" vec3 color;"); + src.push(" vec3 direction;"); + src.push("};"); - _setFlags2(portionId, flags) { + src.push("struct ReflectedLight {"); + src.push(" vec3 diffuse;"); + src.push(" vec3 specular;"); + src.push("};"); - if (!this._finalized) { - throw "Not finalized"; - } + src.push("struct Geometry {"); + src.push(" vec3 position;"); + src.push(" vec3 viewNormal;"); + src.push(" vec3 worldNormal;"); + src.push(" vec3 viewEyeDir;"); + src.push("};"); - const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; - tempUint8Vec4$2[0] = clippable; + src.push("struct Material {"); + src.push(" vec3 diffuseColor;"); + src.push(" float specularRoughness;"); + src.push(" vec3 specularColor;"); + src.push(" float shine;"); // Only used for Phong + src.push("};"); - if (this._state.flags2Buf) { - this._state.flags2Buf.setData(tempUint8Vec4$2, portionId * 4, 4); - } - } + // IRRADIANCE EVALUATION - setOffset(portionId, offset) { - if (!this._finalized) { - throw "Not finalized"; - } - if (!this.model.scene.entityOffsetsEnabled) { - this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled - return; - } - tempVec3fa$2[0] = offset[0]; - tempVec3fa$2[1] = offset[1]; - tempVec3fa$2[2] = offset[2]; - if (this._state.offsetsBuf) { - this._state.offsetsBuf.setData(tempVec3fa$2, portionId * 3, 3); - } - } + src.push("float GGXRoughnessToBlinnExponent(const in float ggxRoughness) {"); + src.push(" float r = ggxRoughness + 0.0001;"); + src.push(" return (2.0 / (r * r) - 2.0);"); + src.push("}"); - // ---------------------- COLOR RENDERING ----------------------------------- + src.push("float getSpecularMIPLevel(const in float blinnShininessExponent, const in int maxMIPLevel) {"); + src.push(" float maxMIPLevelScalar = float( maxMIPLevel );"); + src.push(" float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( ( blinnShininessExponent * blinnShininessExponent ) + 1.0 );"); + src.push(" return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );"); + src.push("}"); - drawColorOpaque(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - const geometry = this._state.geometry; - if (frameCtx.withSAO && this.model.saoEnabled) { - if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { - if (this._instancingRenderers.pbrRendererWithSAO) { - this._instancingRenderers.pbrRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { - if (this._instancingRenderers.colorTextureRendererWithSAO) { - this._instancingRenderers.colorTextureRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (geometry.normalsBuf) { - if (this._instancingRenderers.colorRendererWithSAO) { - this._instancingRenderers.colorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else { - if (this._instancingRenderers.flatColorRendererWithSAO) { - this._instancingRenderers.flatColorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } - } else if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { - if (this._instancingRenderers.pbrRenderer) { - this._instancingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { - if (this._instancingRenderers.colorTextureRenderer) { - this._instancingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else if (geometry.normalsBuf) { - if (this._instancingRenderers.colorRenderer) { - this._instancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } else { - if (this._instancingRenderers.flatColorRenderer) { - this._instancingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } + if (lightsState.reflectionMaps.length > 0) { + src.push("vec3 getLightProbeIndirectRadiance(const in vec3 reflectVec, const in float blinnShininessExponent, const in int maxMIPLevel) {"); + src.push(" float mipLevel = 0.5 * getSpecularMIPLevel(blinnShininessExponent, maxMIPLevel);"); //TODO: a random factor - fix this + src.push(" vec3 envMapColor = sRGBToLinear(texture(reflectionMap, reflectVec, mipLevel)).rgb;"); + src.push(" return envMapColor;"); + src.push("}"); } - } - _updateBackfaceCull(renderFlags, frameCtx) { - const backfaces = this.model.backfaces || (!this.solid) || renderFlags.sectioned; - if (frameCtx.backfaces !== backfaces) { - const gl = frameCtx.gl; - if (backfaces) { - gl.disable(gl.CULL_FACE); - } else { - gl.enable(gl.CULL_FACE); - } - frameCtx.backfaces = backfaces; - } - } + // SPECULAR BRDF EVALUATION - drawColorTransparent(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { - if (this._instancingRenderers.pbrRenderer) { - this._instancingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { - if (this._instancingRenderers.colorTextureRenderer) { - this._instancingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } else if (this._state.normalsBuf) { - if (this._instancingRenderers.colorRenderer) { - this._instancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } else { - if (this._instancingRenderers.flatColorRenderer) { - this._instancingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } - } + src.push("vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) {"); + src.push(" float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );"); + src.push(" return ( 1.0 - specularColor ) * fresnel + specularColor;"); + src.push("}"); - // ---------------------- RENDERING SAO POST EFFECT TARGETS -------------- + src.push("float G_GGX_Smith(const in float alpha, const in float dotNL, const in float dotNV) {"); + src.push(" float a2 = ( alpha * alpha );"); + src.push(" float gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); + src.push(" float gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); + src.push(" return 1.0 / ( gl * gv );"); + src.push("}"); - drawDepth(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.depthRenderer) { - this._instancingRenderers.depthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses depth (eg SAO) does not apply to transparent objects - } - } + src.push("float G_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) {"); + src.push(" float a2 = ( alpha * alpha );"); + src.push(" float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); + src.push(" float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); + src.push(" return 0.5 / max( gv + gl, EPSILON );"); + src.push("}"); - drawNormals(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.normalsRenderer) { - this._instancingRenderers.normalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses normals (eg SAO) does not apply to transparent objects - } - } + src.push("float D_GGX(const in float alpha, const in float dotNH) {"); + src.push(" float a2 = ( alpha * alpha );"); + src.push(" float denom = ( dotNH * dotNH) * ( a2 - 1.0 ) + 1.0;"); + src.push(" return RECIPROCAL_PI * a2 / ( denom * denom);"); + src.push("}"); - // ---------------------- SILHOUETTE RENDERING ----------------------------------- + src.push("vec3 BRDF_Specular_GGX(const in IncidentLight incidentLight, const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); + src.push(" float alpha = ( roughness * roughness );"); + src.push(" vec3 halfDir = normalize( incidentLight.direction + geometry.viewEyeDir );"); + src.push(" float dotNL = saturate( dot( geometry.viewNormal, incidentLight.direction ) );"); + src.push(" float dotNV = saturate( dot( geometry.viewNormal, geometry.viewEyeDir ) );"); + src.push(" float dotNH = saturate( dot( geometry.viewNormal, halfDir ) );"); + src.push(" float dotLH = saturate( dot( incidentLight.direction, halfDir ) );"); + src.push(" vec3 F = F_Schlick( specularColor, dotLH );"); + src.push(" float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );"); + src.push(" float D = D_GGX( alpha, dotNH );"); + src.push(" return F * (G * D);"); + src.push("}"); - drawSilhouetteXRayed(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.silhouetteRenderer) { - this._instancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); - } - } + src.push("vec3 BRDF_Specular_GGX_Environment(const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); + src.push(" float dotNV = saturate(dot(geometry.viewNormal, geometry.viewEyeDir));"); + src.push(" const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022);"); + src.push(" const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04);"); + src.push(" vec4 r = roughness * c0 + c1;"); + src.push(" float a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y;"); + src.push(" vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;"); + src.push(" return specularColor * AB.x + AB.y;"); + src.push("}"); - drawSilhouetteHighlighted(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.silhouetteRenderer) { - this._instancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); + if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { + src.push("void computePBRLightMapping(const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); + if (lightsState.lightMaps.length > 0) { + src.push(" vec3 irradiance = sRGBToLinear(texture(lightMap, geometry.worldNormal)).rgb;"); + src.push(" irradiance *= PI;"); + src.push(" vec3 diffuseBRDFContrib = (RECIPROCAL_PI * material.diffuseColor);"); + src.push(" reflectedLight.diffuse += irradiance * diffuseBRDFContrib;"); + } + if (lightsState.reflectionMaps.length > 0) { + src.push(" vec3 reflectVec = reflect(geometry.viewEyeDir, geometry.viewNormal);"); + src.push(" reflectVec = inverseTransformDirection(reflectVec, viewMatrix);"); + src.push(" float blinnExpFromRoughness = GGXRoughnessToBlinnExponent(material.specularRoughness);"); + src.push(" vec3 radiance = getLightProbeIndirectRadiance(reflectVec, blinnExpFromRoughness, 8);"); + src.push(" vec3 specularBRDFContrib = BRDF_Specular_GGX_Environment(geometry, material.specularColor, material.specularRoughness);"); + src.push(" reflectedLight.specular += radiance * specularBRDFContrib;"); + } + src.push("}"); } - } - drawSilhouetteSelected(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.silhouetteRenderer) { - this._instancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); - } - } + // MAIN LIGHTING COMPUTATION FUNCTION - // ---------------------- EDGES RENDERING ----------------------------------- + src.push("void computePBRLighting(const in IncidentLight incidentLight, const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); + src.push(" float dotNL = saturate(dot(geometry.viewNormal, incidentLight.direction));"); + src.push(" vec3 irradiance = dotNL * incidentLight.color * PI;"); + src.push(" reflectedLight.diffuse += irradiance * (RECIPROCAL_PI * material.diffuseColor);"); + src.push(" reflectedLight.specular += irradiance * BRDF_Specular_GGX(incidentLight, geometry, material.specularColor, material.specularRoughness);"); + src.push("}"); - drawEdgesColorOpaque(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) { - return; - } - if (this._instancingRenderers.edgesColorRenderer) { - this._instancingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_OPAQUE); - } - } + src.push("out vec4 outColor;"); - drawEdgesColorTransparent(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) { - return; - } - if (this._instancingRenderers.edgesColorRenderer) { - this._instancingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_TRANSPARENT); - } - } + src.push("void main(void) {"); - drawEdgesXRayed(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { - return; - } - if (this._instancingRenderers.edgesRenderer) { - this._instancingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_XRAYED); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + if (clippingCaps) { + src.push(" if (dist > (0.002 * vClipPosition.w)) {"); + src.push(" discard;"); + src.push(" }"); + src.push(" if (dist > 0.0) { "); + src.push(" outColor=vec4(1.0, 0.0, 0.0, 1.0);"); + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" return;"); + src.push("}"); + } else { + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); + } + src.push("}"); } - } - drawEdgesHighlighted(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { - return; - } - if (this._instancingRenderers.edgesRenderer) { - this._instancingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_HIGHLIGHTED); - } - } + src.push("IncidentLight light;"); + src.push("Material material;"); + src.push("Geometry geometry;"); + src.push("ReflectedLight reflectedLight = ReflectedLight(vec3(0.0,0.0,0.0), vec3(0.0,0.0,0.0));"); - drawEdgesSelected(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { - return; - } - if (this._instancingRenderers.edgesRenderer) { - this._instancingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_SELECTED); - } - } + src.push("vec3 rgb = (vec3(float(vColor.r) / 255.0, float(vColor.g) / 255.0, float(vColor.b) / 255.0));"); + src.push("float opacity = float(vColor.a) / 255.0;"); - // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- + src.push("vec3 baseColor = rgb;"); + src.push("float specularF0 = 1.0;"); + src.push("float metallic = float(vMetallicRoughness.r) / 255.0;"); + src.push("float roughness = float(vMetallicRoughness.g) / 255.0;"); + src.push("float dielectricSpecular = 0.16 * specularF0 * specularF0;"); - drawOcclusion(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.occlusionRenderer) { - // Only opaque, filled objects can be occluders - this._instancingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } + src.push("vec4 baseColorTexel = sRGBToLinear(texture(uBaseColorMap, vUV));"); + src.push("baseColor *= baseColorTexel.rgb;"); + // src.push("opacity *= baseColorTexel.a;"); - // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- + src.push("vec3 metalRoughTexel = texture(uMetallicRoughMap, vUV).rgb;"); + src.push("metallic *= metalRoughTexel.b;"); + src.push("roughness *= metalRoughTexel.g;"); - drawShadow(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.shadowRenderer) { - this._instancingRenderers.shadowRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } + src.push("vec3 viewNormal = perturbNormal2Arb(vViewPosition.xyz, normalize(vViewNormal), vUV );"); - //---- PICKING ---------------------------------------------------------------------------------------------------- + src.push("material.diffuseColor = baseColor * (1.0 - dielectricSpecular) * (1.0 - metallic);"); + src.push("material.specularRoughness = clamp(roughness, 0.04, 1.0);"); + src.push("material.specularColor = mix(vec3(dielectricSpecular), baseColor, metallic);"); - drawPickMesh(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.pickMeshRenderer) { - this._instancingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); - } - } + src.push("geometry.position = vViewPosition.xyz;"); + src.push("geometry.viewNormal = -normalize(viewNormal);"); + src.push("geometry.viewEyeDir = normalize(vViewPosition.xyz);"); - drawPickDepths(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.pickDepthRenderer) { - this._instancingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + if (lightsState.lightMaps.length > 0) { + src.push("geometry.worldNormal = normalize(vWorldNormal);"); } - } - drawPickNormals(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - this._updateBackfaceCull(renderFlags, frameCtx); - if (this._instancingRenderers.pickNormalsRenderer) { - this._instancingRenderers.pickNormalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { + src.push("computePBRLightMapping(geometry, material, reflectedLight);"); } - } - //----------------------------------------------------------------------------------------- + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("light.direction = normalize(lightDir" + i + ");"); + } else { + src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("light.direction = normalize(lightPos" + i + " - vViewPosition.xyz);"); + } else { + src.push("light.direction = normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("light.direction = normalize(lightDir" + i + ");"); + } else { + src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } - precisionRayPickSurface(portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldNormal) { + src.push("light.color = lightColor" + i + ".rgb * lightColor" + i + ".a;"); // a is intensity - if (!this.model.scene.pickSurfacePrecisionEnabled) { - return false; + src.push("computePBRLighting(light, geometry, material, reflectedLight);"); } - const geometry = this._state.geometry; - const state = this._state; - const portion = this._portions[portionId]; - - if (!portion) { - this.model.error("portion not found: " + portionId); - return false; - } + src.push("vec3 emissiveColor = sRGBToLinear(texture(uEmissiveMap, vUV)).rgb;"); // TODO: correct gamma function + src.push("float aoFactor = texture(uAOMap, vUV).r;"); - if (!portion.inverseMatrix) { - portion.inverseMatrix = math.inverseMat4(portion.matrix, math.mat4()); - } + src.push("vec3 outgoingLight = (lightAmbient.rgb * lightAmbient.a * baseColor * opacity * rgb) + (reflectedLight.diffuse) + (reflectedLight.specular) + emissiveColor;"); + src.push("vec4 fragColor;"); - if (worldNormal && !portion.normalMatrix) { - portion.normalMatrix = math.transposeMat4(portion.inverseMatrix, math.mat4()); + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" fragColor = vec4(outgoingLight.rgb * ambient * aoFactor, opacity);"); + } else { + src.push(" fragColor = vec4(outgoingLight.rgb * aoFactor, opacity);"); } - const quantizedPositions = geometry.quantizedPositions; - const indices = geometry.indices; - const origin = state.origin; - const offset = portion.offset; - - const rtcRayOrigin = tempVec3a$r; - const rtcRayDir = tempVec3b$7; - - rtcRayOrigin.set(origin ? math.subVec3(worldRayOrigin, origin, tempVec3c$4) : worldRayOrigin); // World -> RTC - rtcRayDir.set(worldRayDir); - - if (offset) { - math.subVec3(rtcRayOrigin, offset); + if (gammaOutput) { + src.push("fragColor = linearToGamma(fragColor, gammaFactor);"); } - math.transformRay(this.model.worldNormalMatrix, rtcRayOrigin, rtcRayDir, rtcRayOrigin, rtcRayDir); - - math.transformRay(portion.inverseMatrix, rtcRayOrigin, rtcRayDir, rtcRayOrigin, rtcRayDir); - - const a = tempVec3d$1; - const b = tempVec3e; - const c = tempVec3f; - - let gotIntersect = false; - let closestDist = 0; - const closestIntersectPos = tempVec3g; - - for (let i = 0, len = indices.length; i < len; i += 3) { - - const ia = indices[i + 0] * 3; - const ib = indices[i + 1] * 3; - const ic = indices[i + 2] * 3; - - a[0] = quantizedPositions[ia]; - a[1] = quantizedPositions[ia + 1]; - a[2] = quantizedPositions[ia + 2]; - - b[0] = quantizedPositions[ib]; - b[1] = quantizedPositions[ib + 1]; - b[2] = quantizedPositions[ib + 2]; - - c[0] = quantizedPositions[ic]; - c[1] = quantizedPositions[ic + 1]; - c[2] = quantizedPositions[ic + 2]; - - math.decompressPosition(a, state.positionsDecodeMatrix); - math.decompressPosition(b, state.positionsDecodeMatrix); - math.decompressPosition(c, state.positionsDecodeMatrix); - - if (math.rayTriangleIntersect(rtcRayOrigin, rtcRayDir, a, b, c, closestIntersectPos)) { - - math.transformPoint3(portion.matrix, closestIntersectPos, closestIntersectPos); - - math.transformPoint3(this.model.worldMatrix, closestIntersectPos, closestIntersectPos); - - if (offset) { - math.addVec3(closestIntersectPos, offset); - } - - if (origin) { - math.addVec3(closestIntersectPos, origin); - } - - const dist = Math.abs(math.lenVec3(math.subVec3(closestIntersectPos, worldRayOrigin, []))); + src.push("outColor = fragColor;"); - if (!gotIntersect || dist > closestDist) { - closestDist = dist; - worldSurfacePos.set(closestIntersectPos); - if (worldNormal) { // Not that wasteful to eagerly compute - unlikely to hit >2 surfaces on most geometry - math.triangleNormal(a, b, c, worldNormal); - } - gotIntersect = true; - } - } + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - if (gotIntersect && worldNormal) { - math.transformVec3(portion.normalMatrix, worldNormal, worldNormal); - math.transformVec3(this.model.worldNormalMatrix, worldNormal, worldNormal); - math.normalizeVec3(worldNormal); - } + src.push("}"); + return src; + } - return gotIntersect; + webglContextRestored() { + this._program = null; } destroy() { - const state = this._state; - if (state.colorsBuf) { - state.colorsBuf.destroy(); - state.colorsBuf = null; - } - if (state.metallicRoughnessBuf) { - state.metallicRoughnessBuf.destroy(); - state.metallicRoughnessBuf = null; - } - if (state.flagsBuf) { - state.flagsBuf.destroy(); - state.flagsBuf = null; - } - if (state.flags2Buf) { - state.flags2Buf.destroy(); - state.flags2Buf = null; - } - if (state.offsetsBuf) { - state.offsetsBuf.destroy(); - state.offsetsBuf = null; - } - if (state.modelMatrixCol0Buf) { - state.modelMatrixCol0Buf.destroy(); - state.modelMatrixCol0Buf = null; - } - if (state.modelMatrixCol1Buf) { - state.modelMatrixCol1Buf.destroy(); - state.modelMatrixCol1Buf = null; - } - if (state.modelMatrixCol2Buf) { - state.modelMatrixCol2Buf.destroy(); - state.modelMatrixCol2Buf = null; - } - if (state.modelNormalMatrixCol0Buf) { - state.modelNormalMatrixCol0Buf.destroy(); - state.modelNormalMatrixCol0Buf = null; - } - if (state.modelNormalMatrixCol1Buf) { - state.modelNormalMatrixCol1Buf.destroy(); - state.modelNormalMatrixCol1Buf = null; - } - if (state.modelNormalMatrixCol2Buf) { - state.modelNormalMatrixCol2Buf.destroy(); - state.modelNormalMatrixCol2Buf = null; - } - if (state.pickColorsBuf) { - state.pickColorsBuf.destroy(); - state.pickColorsBuf = null; + if (this._program) { + this._program.destroy(); } - state.destroy(); + this._program = null; } } -const tempVec3a$q = math.vec3(); +const tempVec3a$I = math.vec3(); /** * @private */ -class LinesBatchingColorRenderer { +class TrianglesBatchingPickNormalsFlatRenderer { constructor(scene) { this._scene = scene; @@ -55463,32 +57906,37 @@ class LinesBatchingColorRenderer { drawLayer(frameCtx, batchingLayer, renderPass) { - const scene = this._scene; - const camera = scene.camera; const model = batchingLayer.model; + const scene = model.scene; + const camera = scene.camera; const gl = scene.canvas.gl; const state = batchingLayer._state; const origin = batchingLayer._state.origin; - batchingLayer.geometry; if (!this._program) { - this._allocate(); - if (this.errors) { - return; - } + this._allocate(batchingLayer); } if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + this._bindProgram(); } gl.uniform1i(this._uRenderPass, renderPass); + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.lineWidth(scene.linesMaterial.lineWidth); + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far should be from projection matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { @@ -55497,29 +57945,31 @@ class LinesBatchingColorRenderer { const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$q); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$I); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - + //============================================================= + // TODO: Use drawElements count and offset to draw only one entity + //============================================================= + + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } if (this._aFlags) { @@ -55530,15 +57980,9 @@ class LinesBatchingColorRenderer { this._aFlags2.bindArrayBuffer(state.flags2Buf); } - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } - state.indicesBuf.bind(); - gl.drawElements(gl.LINES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - - frameCtx.drawElements++; + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } _allocate() { @@ -55556,11 +58000,11 @@ class LinesBatchingColorRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -55573,7 +58017,6 @@ class LinesBatchingColorRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); @@ -55582,21 +58025,8 @@ class LinesBatchingColorRenderer { } } - _bindProgram(frameCtx) { - - const scene = this._scene; - const gl = scene.canvas.gl; - const program = this._program; - const project = scene.camera.project; - - program.bind(); - - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + _bindProgram() { + this._program.bind(); } _buildShader() { @@ -55608,19 +58038,19 @@ class LinesBatchingColorRenderer { _buildVertexShader() { const scene = this._scene; - const sectionPlanesState = scene._sectionPlanesState; - const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Lines batching color vertex shader"); + src.push("#version 300 es"); + src.push("// Triangles batching pick flat normals vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); @@ -55628,34 +58058,37 @@ class LinesBatchingColorRenderer { if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } + src.push("out vec4 vWorldPosition;"); if (clipping) { - src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vColor;"); src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { - src.push("worldPosition.xyz = worldPosition.xyz + offset;"); + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vWorldPosition = worldPosition;"); if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + src.push(" vFlags2 = flags2;"); } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - src.push("}"); + src.push(" }"); src.push("}"); return src; } @@ -55665,8 +58098,9 @@ class LinesBatchingColorRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Lines batching color fragment shader"); + src.push("#version 300 es"); + src.push("// Triangles batching pick flat normals fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -55675,37 +58109,40 @@ class LinesBatchingColorRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + src.push("in vec4 vWorldPosition;"); if (clipping) { - src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { - src.push("if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push("}"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); } - src.push(" if (dist > 0.0) { discard; }"); - src.push("}"); + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } - src.push(" outColor = vColor;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push(" vec3 xTangent = dFdx( vWorldPosition.xyz );"); + src.push(" vec3 yTangent = dFdy( vWorldPosition.xyz );"); + src.push(" vec3 worldNormal = normalize( cross( xTangent, yTangent ) );"); + src.push(" outColor = vec4((worldNormal * 0.5) + 0.5, 1.0);"); src.push("}"); return src; } @@ -55722,16 +58159,17 @@ class LinesBatchingColorRenderer { } } -const defaultColor$1 = new Float32Array([1, 1, 1]); -const tempVec3a$p = math.vec3(); +const tempVec4$4 = math.vec4(); +const tempVec3a$H = math.vec3(); /** * @private */ -class LinesBatchingSilhouetteRenderer { +class TrianglesBatchingColorTextureRenderer { - constructor(scene, primitiveType) { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -55741,18 +58179,21 @@ class LinesBatchingSilhouetteRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash(); + const scene = this._scene; + return [scene.gammaOutput, scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } drawLayer(frameCtx, batchingLayer, renderPass) { - const model = batchingLayer.model; - const scene = model.scene; + const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; + + const scene = this._scene; const camera = scene.camera; + const model = batchingLayer.model; const gl = scene.canvas.gl; const state = batchingLayer._state; const origin = batchingLayer._state.origin; - batchingLayer.geometry; + const textureSet = state.textureSet; if (!this._program) { this._allocate(); @@ -55763,40 +58204,14 @@ class LinesBatchingSilhouetteRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx); } gl.uniform1i(this._uRenderPass, renderPass); - if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { - const material = scene.xrayMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { - const material = scene.selectedMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else { - gl.uniform4fv(this._uColor, defaultColor$1); - } - - const viewMat = (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix; - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMat); - + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.lineWidth(scene.linesMaterial.lineWidth); - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; @@ -55810,7 +58225,7 @@ class LinesBatchingSilhouetteRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$p); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$H); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -55821,12 +58236,20 @@ class LinesBatchingSilhouetteRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, state.positionsDecodeMatrix); + + if (this._uUVDecodeMatrix) { + gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, state.uvDecodeMatrix); + } this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); + if (this._aUV) { + this._aUV.bindArrayBuffer(state.uvBuf); + } + + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); } if (this._aFlags) { @@ -55837,15 +58260,46 @@ class LinesBatchingSilhouetteRenderer { this._aFlags2.bindArrayBuffer(state.flags2Buf); } + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + } + + if (textureSet) { + if (textureSet.colorTexture) { + this._program.bindTexture(this._uColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + } + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$4[0] = viewportWidth; + tempVec4$4[1] = viewportHeight; + tempVec4$4[2] = sao.blendCutoff; + tempVec4$4[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$4); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; + } + } + state.indicesBuf.bind(); - gl.drawElements(gl.LINES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + gl.drawElements(gl.TRIANGLES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); + + frameCtx.drawElements++; } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; + const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -55858,10 +58312,45 @@ class LinesBatchingSilhouetteRenderer { this._uRenderPass = program.getLocation("renderPass"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uColor = program.getLocation("color"); + + this._uGammaFactor = program.getLocation("gammaFactor"); + + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; + + const lights = lightsState.lights; + let light; + + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -55874,28 +58363,63 @@ class LinesBatchingSilhouetteRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); + this._aUV = program.getAttribute("uv"); + this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._uColorMap = "uColorMap"; + + if (this._withSAO) { + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); + } + if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { - + _bindProgram(frameCtx) { const scene = this._scene; const gl = scene.canvas.gl; + const program = this._program; + const lightsState = scene._lightsState; + const lights = lightsState.lights; const project = scene.camera.project; - this._program.bind(); + program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + const light = lights[i]; + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + if (scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } + + if (this._uGammaFactor) { + gl.uniform1f(this._uGammaFactor, scene.gammaFactor); + } } _buildShader() { @@ -55910,56 +58434,73 @@ class LinesBatchingSilhouetteRenderer { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const src = []; - src.push('#version 300 es'); - src.push("// Lines batching silhouette vertex shader"); + src.push("#version 300 es"); + src.push("// Triangles batching color texture vertex shader"); src.push("uniform int renderPass;"); src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec2 uv;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform vec4 color;"); + src.push("uniform mat3 uvDecodeMatrix;"); if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } + src.push("out vec4 vViewPosition;"); + src.push("out vec4 vColor;"); + src.push("out vec2 vUV;"); src.push("void main(void) {"); - // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | SILHOUETTE_XRAYED - // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - src.push(`if (int(flags.y) != renderPass) {`); + src.push(`if (int(flags.x) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { - src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + src.push("worldPosition.xyz = worldPosition.xyz + offset;"); } src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } + src.push("vViewPosition = viewPosition;"); + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + } + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } src.push("gl_Position = clipPos;"); src.push("}"); @@ -55968,13 +58509,14 @@ class LinesBatchingSilhouetteRenderer { } _buildFragmentShader() { - const scene = this._scene; + const gammaOutput = scene.gammaOutput; // If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is false. + const lightsState = scene._lightsState; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Lines batching silhouette fragment shader"); + src.push("#version 300 es"); + src.push("// Triangles batching color texture fragment shader"); src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); @@ -55983,10 +58525,41 @@ class LinesBatchingSilhouetteRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + src.push("uniform sampler2D uColorMap;"); + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); + } + src.push("uniform float gammaFactor;"); + src.push("vec4 linearToLinear( in vec4 value ) {"); + src.push(" return value;"); + src.push("}"); + src.push("vec4 sRGBToLinear( in vec4 value ) {"); + src.push(" return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );"); + src.push("}"); + src.push("vec4 gammaToLinear( in vec4 value) {"); + src.push(" return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );"); + src.push("}"); + if (gammaOutput) { + src.push("vec4 linearToGamma( in vec4 value, in float gammaFactor ) {"); + src.push(" return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );"); + src.push("}"); + } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); @@ -55996,9 +58569,33 @@ class LinesBatchingSilhouetteRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("uniform vec4 color;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform vec4 lightAmbient;"); + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + + src.push("in vec4 vViewPosition;"); + src.push("in vec4 vColor;"); + src.push("in vec2 vUV;"); src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); @@ -56008,13 +58605,83 @@ class LinesBatchingSilhouetteRenderer { src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push(" if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); src.push("}"); } + + src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); + src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + + src.push("float lambertian = 1.0;"); + + src.push("vec3 xTangent = dFdx( vViewPosition.xyz );"); + src.push("vec3 yTangent = dFdy( vViewPosition.xyz );"); + src.push("vec3 viewNormal = normalize( cross( xTangent, yTangent ) );"); + + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); + } else { + src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } + + src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); + src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); + } + + src.push("vec4 color = vec4((lightAmbient.rgb * lightAmbient.a * vColor.rgb) + (reflectedColor * vColor.rgb), vColor.a);"); + if (gammaOutput) { + src.push("vec4 colorTexel = color * sRGBToLinear(texture(uColorMap, vUV));"); + } else { + src.push("vec4 colorTexel = color * texture(uColorMap, vUV);"); + } + src.push("float opacity = color.a;"); + + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + + src.push(" outColor = vec4(colorTexel.rgb * ambient, opacity);"); + } else { + src.push(" outColor = vec4(colorTexel.rgb, opacity);"); + } + + if (gammaOutput) { + src.push("outColor = linearToGamma(outColor, gammaFactor);"); + } + if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push("gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push("outColor = color;"); + src.push("}"); return src; } @@ -56034,7 +58701,7 @@ class LinesBatchingSilhouetteRenderer { /** * @private */ -class LinesBatchingRenderers { +class TrianglesBatchingRenderers { constructor(scene) { this._scene = scene; @@ -56045,53 +58712,291 @@ class LinesBatchingRenderers { this._colorRenderer.destroy(); this._colorRenderer = null; } + if (this._colorRendererWithSAO && (!this._colorRendererWithSAO.getValid())) { + this._colorRendererWithSAO.destroy(); + this._colorRendererWithSAO = null; + } + if (this._flatColorRenderer && (!this._flatColorRenderer.getValid())) { + this._flatColorRenderer.destroy(); + this._flatColorRenderer = null; + } + if (this._flatColorRendererWithSAO && (!this._flatColorRendererWithSAO.getValid())) { + this._flatColorRendererWithSAO.destroy(); + this._flatColorRendererWithSAO = null; + } + if (this._colorTextureRenderer && (!this._colorTextureRenderer.getValid())) { + this._colorTextureRenderer.destroy(); + this._colorTextureRenderer = null; + } + if (this._colorTextureRendererWithSAO && (!this._colorTextureRendererWithSAO.getValid())) { + this._colorTextureRendererWithSAO.destroy(); + this._colorTextureRendererWithSAO = null; + } + if (this._pbrRenderer && (!this._pbrRenderer.getValid())) { + this._pbrRenderer.destroy(); + this._pbrRenderer = null; + } + if (this._pbrRendererWithSAO && (!this._pbrRendererWithSAO.getValid())) { + this._pbrRendererWithSAO.destroy(); + this._pbrRendererWithSAO = null; + } + if (this._depthRenderer && (!this._depthRenderer.getValid())) { + this._depthRenderer.destroy(); + this._depthRenderer = null; + } + if (this._normalsRenderer && (!this._normalsRenderer.getValid())) { + this._normalsRenderer.destroy(); + this._normalsRenderer = null; + } if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { this._silhouetteRenderer.destroy(); this._silhouetteRenderer = null; } + if (this._edgesRenderer && (!this._edgesRenderer.getValid())) { + this._edgesRenderer.destroy(); + this._edgesRenderer = null; + } + if (this._edgesColorRenderer && (!this._edgesColorRenderer.getValid())) { + this._edgesColorRenderer.destroy(); + this._edgesColorRenderer = null; + } + if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { + this._pickMeshRenderer.destroy(); + this._pickMeshRenderer = null; + } + if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { + this._pickDepthRenderer.destroy(); + this._pickDepthRenderer = null; + } + if (this._pickNormalsRenderer && this._pickNormalsRenderer.getValid() === false) { + this._pickNormalsRenderer.destroy(); + this._pickNormalsRenderer = null; + } + if (this._pickNormalsFlatRenderer && this._pickNormalsFlatRenderer.getValid() === false) { + this._pickNormalsFlatRenderer.destroy(); + this._pickNormalsFlatRenderer = null; + } + if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { + this._occlusionRenderer.destroy(); + this._occlusionRenderer = null; + } + if (this._shadowRenderer && (!this._shadowRenderer.getValid())) { + this._shadowRenderer.destroy(); + this._shadowRenderer = null; + } } get colorRenderer() { if (!this._colorRenderer) { - this._colorRenderer = new LinesBatchingColorRenderer(this._scene, false); + this._colorRenderer = new TrianglesBatchingColorRenderer(this._scene, false); } return this._colorRenderer; } + get colorRendererWithSAO() { + if (!this._colorRendererWithSAO) { + this._colorRendererWithSAO = new TrianglesBatchingColorRenderer(this._scene, true); + } + return this._colorRendererWithSAO; + } + + get flatColorRenderer() { + if (!this._flatColorRenderer) { + this._flatColorRenderer = new TrianglesBatchingFlatColorRenderer(this._scene, false); + } + return this._flatColorRenderer; + } + + get flatColorRendererWithSAO() { + if (!this._flatColorRendererWithSAO) { + this._flatColorRendererWithSAO = new TrianglesBatchingFlatColorRenderer(this._scene, true); + } + return this._flatColorRendererWithSAO; + } + + get colorTextureRenderer() { + if (!this._colorTextureRenderer) { + this._colorTextureRenderer = new TrianglesBatchingColorTextureRenderer(this._scene, false); + } + return this._colorTextureRenderer; + } + + get colorTextureRendererWithSAO() { + if (!this._colorTextureRendererWithSAO) { + this._colorTextureRendererWithSAO = new TrianglesBatchingColorTextureRenderer(this._scene, true); + } + return this._colorTextureRendererWithSAO; + } + + get pbrRenderer() { + if (!this._pbrRenderer) { + this._pbrRenderer = new TrianglesBatchingPBRRenderer(this._scene, false); + } + return this._pbrRenderer; + } + + get pbrRendererWithSAO() { + if (!this._pbrRendererWithSAO) { + this._pbrRendererWithSAO = new TrianglesBatchingPBRRenderer(this._scene, true); + } + return this._pbrRendererWithSAO; + } + get silhouetteRenderer() { if (!this._silhouetteRenderer) { - this._silhouetteRenderer = new LinesBatchingSilhouetteRenderer(this._scene); + this._silhouetteRenderer = new TrianglesBatchingSilhouetteRenderer(this._scene); } return this._silhouetteRenderer; } + get depthRenderer() { + if (!this._depthRenderer) { + this._depthRenderer = new TrianglesBatchingDepthRenderer(this._scene); + } + return this._depthRenderer; + } + + get normalsRenderer() { + if (!this._normalsRenderer) { + this._normalsRenderer = new TrianglesBatchingNormalsRenderer(this._scene); + } + return this._normalsRenderer; + } + + get edgesRenderer() { + if (!this._edgesRenderer) { + this._edgesRenderer = new TrianglesBatchingEdgesRenderer(this._scene); + } + return this._edgesRenderer; + } + + get edgesColorRenderer() { + if (!this._edgesColorRenderer) { + this._edgesColorRenderer = new TrianglesBatchingEdgesColorRenderer(this._scene); + } + return this._edgesColorRenderer; + } + + get pickMeshRenderer() { + if (!this._pickMeshRenderer) { + this._pickMeshRenderer = new TrianglesBatchingPickMeshRenderer(this._scene); + } + return this._pickMeshRenderer; + } + + get pickNormalsRenderer() { + if (!this._pickNormalsRenderer) { + this._pickNormalsRenderer = new TrianglesBatchingPickNormalsRenderer(this._scene); + } + return this._pickNormalsRenderer; + } + + get pickNormalsFlatRenderer() { + if (!this._pickNormalsFlatRenderer) { + this._pickNormalsFlatRenderer = new TrianglesBatchingPickNormalsFlatRenderer(this._scene); + } + return this._pickNormalsFlatRenderer; + } + + get pickDepthRenderer() { + if (!this._pickDepthRenderer) { + this._pickDepthRenderer = new TrianglesBatchingPickDepthRenderer(this._scene); + } + return this._pickDepthRenderer; + } + + get occlusionRenderer() { + if (!this._occlusionRenderer) { + this._occlusionRenderer = new TrianglesBatchingOcclusionRenderer(this._scene); + } + return this._occlusionRenderer; + } + + get shadowRenderer() { + if (!this._shadowRenderer) { + this._shadowRenderer = new TrianglesBatchingShadowRenderer(this._scene); + } + return this._shadowRenderer; + } + _destroy() { if (this._colorRenderer) { this._colorRenderer.destroy(); } + if (this._colorRendererWithSAO) { + this._colorRendererWithSAO.destroy(); + } + if (this._flatColorRenderer) { + this._flatColorRenderer.destroy(); + } + if (this._flatColorRendererWithSAO) { + this._flatColorRendererWithSAO.destroy(); + } + if (this._colorTextureRenderer) { + this._colorTextureRenderer.destroy(); + } + if (this._colorTextureRendererWithSAO) { + this._colorTextureRendererWithSAO.destroy(); + } + if (this._pbrRenderer) { + this._pbrRenderer.destroy(); + } + if (this._pbrRendererWithSAO) { + this._pbrRendererWithSAO.destroy(); + } + if (this._depthRenderer) { + this._depthRenderer.destroy(); + } + if (this._normalsRenderer) { + this._normalsRenderer.destroy(); + } if (this._silhouetteRenderer) { this._silhouetteRenderer.destroy(); } + if (this._edgesRenderer) { + this._edgesRenderer.destroy(); + } + if (this._edgesColorRenderer) { + this._edgesColorRenderer.destroy(); + } + if (this._pickMeshRenderer) { + this._pickMeshRenderer.destroy(); + } + if (this._pickDepthRenderer) { + this._pickDepthRenderer.destroy(); + } + if (this._pickNormalsRenderer) { + this._pickNormalsRenderer.destroy(); + } + if (this._pickNormalsFlatRenderer) { + this._pickNormalsFlatRenderer.destroy(); + } + if (this._occlusionRenderer) { + this._occlusionRenderer.destroy(); + } + if (this._shadowRenderer) { + this._shadowRenderer.destroy(); + } } } -const cachedRenderers$3 = {}; +const cachdRenderers = {}; /** * @private */ -function getBatchingRenderers(scene) { +function getBatchingRenderers$1(scene) { const sceneId = scene.id; - let batchingRenderers = cachedRenderers$3[sceneId]; + let batchingRenderers = cachdRenderers[sceneId]; if (!batchingRenderers) { - batchingRenderers = new LinesBatchingRenderers(scene); - cachedRenderers$3[sceneId] = batchingRenderers; + batchingRenderers = new TrianglesBatchingRenderers(scene); + cachdRenderers[sceneId] = batchingRenderers; batchingRenderers._compile(); scene.on("compile", () => { batchingRenderers._compile(); }); scene.on("destroyed", () => { - delete cachedRenderers$3[sceneId]; + delete cachdRenderers[sceneId]; batchingRenderers._destroy(); }); } @@ -56101,7 +59006,7 @@ function getBatchingRenderers(scene) { /** * @private */ -class LinesBatchingBuffer { +class TrianglesBatchingBuffer { constructor(maxGeometryBatchSize = 5000000) { @@ -56113,54 +59018,292 @@ class LinesBatchingBuffer { this.maxIndices = maxGeometryBatchSize * 3; // Rough rule-of-thumb this.positions = []; this.colors = []; + this.uv = []; + this.metallicRoughness = []; + this.normals = []; + this.pickColors = []; this.flags = []; this.flags2 = []; this.offsets = []; this.indices = []; + this.edgeIndices = []; } } -const tempVec4a$8 = math.vec4([0, 0, 0, 1]); -const tempVec4b$8 = math.vec4([0, 0, 0, 1]); -const tempVec4c$5 = math.vec4([0, 0, 0, 1]); -const tempOBB3$1 = math.OBB3(); +const translate = math.mat4(); +const scale = math.mat4(); /** * @private */ -class LinesBatchingLayer { +function quantizePositions(positions, aabb, positionsDecodeMatrix) { // http://cg.postech.ac.kr/research/mesh_comp_mobile/mesh_comp_mobile_conference.pdf + const lenPositions = positions.length; + const quantizedPositions = new Uint16Array(lenPositions); + const xmin = aabb[0]; + const ymin = aabb[1]; + const zmin = aabb[2]; + const xwid = aabb[3] - xmin; + const ywid = aabb[4] - ymin; + const zwid = aabb[5] - zmin; + const maxInt = 65525; + const xMultiplier = maxInt / xwid; + const yMultiplier = maxInt / ywid; + const zMultiplier = maxInt / zwid; + const verify = (num) => num >= 0 ? num : 0; + for (let i = 0; i < lenPositions; i += 3) { + quantizedPositions[i + 0] = Math.floor(verify(positions[i + 0] - xmin) * xMultiplier); + quantizedPositions[i + 1] = Math.floor(verify(positions[i + 1] - ymin) * yMultiplier); + quantizedPositions[i + 2] = Math.floor(verify(positions[i + 2] - zmin) * zMultiplier); + } + math.identityMat4(translate); + math.translationMat4v(aabb, translate); + math.identityMat4(scale); + math.scalingMat4v([xwid / maxInt, ywid / maxInt, zwid / maxInt], scale); + math.mulMat4(translate, scale, positionsDecodeMatrix); + return quantizedPositions; +} + +/** + * @private + */ +function transformAndOctEncodeNormals(worldNormalMatrix, normals, lenNormals, compressedNormals, lenCompressedNormals) { + // http://jcgt.org/published/0003/02/01/ + + function dot(array, vec3) { + return array[0] * vec3[0] + array[1] * vec3[1] + array[2] * vec3[2]; + } + + let oct, dec, best, currentCos, bestCos; + let i; + let localNormal = new Float32Array([0, 0, 0, 0]); + let worldNormal = new Float32Array([0, 0, 0, 0]); + for (i = 0; i < lenNormals; i += 3) { + localNormal[0] = normals[i]; + localNormal[1] = normals[i + 1]; + localNormal[2] = normals[i + 2]; + + math.transformVec3(worldNormalMatrix, localNormal, worldNormal); + math.normalizeVec3(worldNormal, worldNormal); + + // Test various combinations of ceil and floor to minimize rounding errors + best = oct = octEncodeVec3(worldNormal, "floor", "floor"); + dec = octDecodeVec2(oct); + currentCos = bestCos = dot(worldNormal, dec); + oct = octEncodeVec3(worldNormal, "ceil", "floor"); + dec = octDecodeVec2(oct); + currentCos = dot(worldNormal, dec); + if (currentCos > bestCos) { + best = oct; + bestCos = currentCos; + } + oct = octEncodeVec3(worldNormal, "floor", "ceil"); + dec = octDecodeVec2(oct); + currentCos = dot(worldNormal, dec); + if (currentCos > bestCos) { + best = oct; + bestCos = currentCos; + } + oct = octEncodeVec3(worldNormal, "ceil", "ceil"); + dec = octDecodeVec2(oct); + currentCos = dot(worldNormal, dec); + if (currentCos > bestCos) { + best = oct; + bestCos = currentCos; + } + compressedNormals[lenCompressedNormals + i + 0] = best[0]; + compressedNormals[lenCompressedNormals + i + 1] = best[1]; + compressedNormals[lenCompressedNormals + i + 2] = 0.0; // Unused + } + lenCompressedNormals += lenNormals; + return lenCompressedNormals; +} + +/** + * @private + */ +function octEncodeNormals(normals) { // http://jcgt.org/published/0003/02/01/ + const lenNormals = normals.length; + const compressedNormals = new Int8Array(lenNormals); + let oct, dec, best, currentCos, bestCos; + for (let i = 0; i < lenNormals; i += 3) { + // Test various combinations of ceil and floor to minimize rounding errors + best = oct = octEncodeNormal(normals, i, "floor", "floor"); + dec = octDecodeVec2(oct); + currentCos = bestCos = dot(normals, i, dec); + oct = octEncodeNormal(normals, i, "ceil", "floor"); + dec = octDecodeVec2(oct); + currentCos = dot(normals, i, dec); + if (currentCos > bestCos) { + best = oct; + bestCos = currentCos; + } + oct = octEncodeNormal(normals, i, "floor", "ceil"); + dec = octDecodeVec2(oct); + currentCos = dot(normals, i, dec); + if (currentCos > bestCos) { + best = oct; + bestCos = currentCos; + } + oct = octEncodeNormal(normals, i, "ceil", "ceil"); + dec = octDecodeVec2(oct); + currentCos = dot(normals, i, dec); + if (currentCos > bestCos) { + best = oct; + bestCos = currentCos; + } + compressedNormals[i + 0] = best[0]; + compressedNormals[i + 1] = best[1]; + compressedNormals[i + 2] = 0.0; // Unused + } + return compressedNormals; +} + +/** + * @private + */ +function octEncodeVec3(p, xfunc, yfunc) { // Oct-encode single normal vector in 2 bytes + let x = p[0] / (Math.abs(p[0]) + Math.abs(p[1]) + Math.abs(p[2])); + let y = p[1] / (Math.abs(p[0]) + Math.abs(p[1]) + Math.abs(p[2])); + if (p[2] < 0) { + let tempx = x; + let tempy = y; + tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); + tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); + x = tempx; + y = tempy; + } + return new Int8Array([ + Math[xfunc](x * 127.5 + (x < 0 ? -1 : 0)), + Math[yfunc](y * 127.5 + (y < 0 ? -1 : 0)) + ]); +} + +/** + * @private + */ +function octEncodeNormal(array, i, xfunc, yfunc) { // Oct-encode single normal vector in 2 bytes + let x = array[i] / (Math.abs(array[i]) + Math.abs(array[i + 1]) + Math.abs(array[i + 2])); + let y = array[i + 1] / (Math.abs(array[i]) + Math.abs(array[i + 1]) + Math.abs(array[i + 2])); + if (array[i + 2] < 0) { + let tempx = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); + let tempy = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); + x = tempx; + y = tempy; + } + return new Int8Array([ + Math[xfunc](x * 127.5 + (x < 0 ? -1 : 0)), + Math[yfunc](y * 127.5 + (y < 0 ? -1 : 0)) + ]); +} + +/** + * @private + */ +function octDecodeVec2(oct) { // Decode an oct-encoded normal + let x = oct[0]; + let y = oct[1]; + x /= x < 0 ? 127 : 128; + y /= y < 0 ? 127 : 128; + const z = 1 - Math.abs(x) - Math.abs(y); + if (z < 0) { + x = (1 - Math.abs(y)) * (x >= 0 ? 1 : -1); + y = (1 - Math.abs(x)) * (y >= 0 ? 1 : -1); + } + const length = Math.sqrt(x * x + y * y + z * z); + return [ + x / length, + y / length, + z / length + ]; +} + +/** + * @private + */ +function dot(array, i, vec3) { + return array[i] * vec3[0] + array[i + 1] * vec3[1] + array[i + 2] * vec3[2]; +} + +const tempMat4$2 = math.mat4(); +const tempMat4b = math.mat4(); +const tempVec4a$a = math.vec4([0, 0, 0, 1]); +const tempVec4b$a = math.vec4([0, 0, 0, 1]); +const tempVec4c$7 = math.vec4([0, 0, 0, 1]); +const tempOBB3$2 = math.OBB3(); + +const tempVec3a$G = math.vec3(); +const tempVec3b$7 = math.vec3(); +const tempVec3c$5 = math.vec3(); +const tempVec3d$2 = math.vec3(); +const tempVec3e$1 = math.vec3(); +const tempVec3f$1 = math.vec3(); +const tempVec3g$1 = math.vec3(); + +/** + * @private + */ +class TrianglesBatchingLayer { /** * @param model - * @param cfg + * @param cfg.model + * @param cfg.autoNormals * @param cfg.layerIndex * @param cfg.positionsDecodeMatrix + * @param cfg.uvDecodeMatrix * @param cfg.maxGeometryBatchSize * @param cfg.origin * @param cfg.scratchMemory + * @param cfg.textureSet + * @param cfg.solid */ constructor(cfg) { /** - * Index of this LinesBatchingLayer in {@link VBOSceneModel#_layerList}. + * Owner model + * @type {VBOSceneModel} + */ + this.model = cfg.model; + + /** + * State sorting key. + * @type {string} + */ + this.sortId = "TrianglesBatchingLayer" + + (cfg.solid ? "-solid" : "-surface") + + (cfg.autoNormals ? "-autonormals" : "-normals") + + // TODO: These two parts need to be IDs (ie. unique): + + + (cfg.textureSet && cfg.textureSet.colorTexture ? "-colorTexture" : "") + + (cfg.textureSet && cfg.textureSet.metallicRoughnessTexture ? "-metallicRoughnessTexture" : ""); + + /** + * Index of this TrianglesBatchingLayer in {@link VBOSceneModel#_layerList}. * @type {Number} */ this.layerIndex = cfg.layerIndex; - this._batchingRenderers = getBatchingRenderers(cfg.model.scene); - this.model = cfg.model; - this._buffer = new LinesBatchingBuffer(cfg.maxGeometryBatchSize); + this._batchingRenderers = getBatchingRenderers$1(cfg.model.scene); + this._buffer = new TrianglesBatchingBuffer(cfg.maxGeometryBatchSize); this._scratchMemory = cfg.scratchMemory; this._state = new RenderState({ + origin: math.vec3(), positionsBuf: null, offsetsBuf: null, + normalsBuf: null, colorsBuf: null, + uvBuf: null, + metallicRoughnessBuf: null, flagsBuf: null, flags2Buf: null, indicesBuf: null, + edgeIndicesBuf: null, positionsDecodeMatrix: math.mat4(), - origin: null + uvDecodeMatrix: null, + textureSet: cfg.textureSet, + pbrSupported: false // Set in #finalize if we have enough to support quality rendering }); // These counts are used to avoid unnecessary render passes @@ -56189,23 +59332,36 @@ class LinesBatchingLayer { this._preCompressedPositionsExpected = false; } + if (cfg.uvDecodeMatrix) { + this._state.uvDecodeMatrix = math.mat3(cfg.uvDecodeMatrix); + this._preCompressedNormalsExpected = true; + } else { + this._preCompressedNormalsExpected = false; + } + if (cfg.origin) { - this._state.origin = math.vec3(cfg.origin); + this._state.origin.set(cfg.origin); } /** - * The axis-aligned World-space boundary of this LinesBatchingLayer's positions. + * The axis-aligned World-space boundary of this TrianglesBatchingLayer's positions. * @type {*|Float64Array} */ this.aabb = math.collapseAABB3(); + + /** + * When true, this layer contains solid triangle meshes, otherwise this layer contains surface triangle meshes + * @type {boolean} + */ + this.solid = !!cfg.solid; } /** - * Tests if there is room for another portion in this LinesBatchingLayer. + * Tests if there is room for another portion in this TrianglesBatchingLayer. * * @param lenPositions Number of positions we'd like to create in the portion. * @param lenIndices Number of indices we'd like to create in this portion. - * @returns {boolean} True if OK to create another portion. + * @returns {Boolean} True if OK to create another portion. */ canCreatePortion(lenPositions, lenIndices) { if (this._finalized) { @@ -56215,14 +59371,22 @@ class LinesBatchingLayer { } /** - * Creates a new portion within this LinesBatchingLayer, returns the new portion ID. + * Creates a new portion within this TrianglesBatchingLayer, returns the new portion ID. * * Gives the portion the specified geometry, color and matrix. * * @param cfg.positions Flat float Local-space positions array. * @param cfg.positionsCompressed Flat quantized positions array - decompressed with TrianglesBatchingLayer positionsDecodeMatrix + * @param [cfg.normals] Flat float normals array. + * @param [cfg.uv] Flat UVs array. + * @param [cfg.uvCompressed] + * @param [cfg.colors] Flat float colors array. + * @param [cfg.colorsCompressed] * @param cfg.indices Flat int indices array. + * @param [cfg.edgeIndices] Flat int edges indices array. * @param cfg.color Quantized RGB color [0..255,0..255,0..255,0..255] + * @param cfg.metallic Metalness factor [0..255] + * @param cfg.roughness Roughness factor [0..255] * @param cfg.opacity Opacity [0..255] * @param [cfg.meshMatrix] Flat float 4x4 matrix * @param [cfg.worldMatrix] Flat float 4x4 matrix @@ -56238,17 +59402,26 @@ class LinesBatchingLayer { const positions = cfg.positions; const positionsCompressed = cfg.positionsCompressed; + const normals = cfg.normals; + const normalsCompressed = cfg.normalsCompressed; + const uv = cfg.uv; + const uvCompressed = cfg.uvCompressed; + const colors = cfg.colors; + const colorsCompressed = cfg.colorsCompressed; const indices = cfg.indices; + const edgeIndices = cfg.edgeIndices; const color = cfg.color; + const metallic = cfg.metallic; + const roughness = cfg.roughness; const opacity = cfg.opacity; const meshMatrix = cfg.meshMatrix; const worldMatrix = cfg.worldMatrix; const worldAABB = cfg.worldAABB; - cfg.pickColor; + const pickColor = cfg.pickColor; + const scene = this.model.scene; const buffer = this._buffer; - const positionsIndex = buffer.positions.length; - const vertsIndex = positionsIndex / 3; + const vertsBaseIndex = buffer.positions.length / 3; let numVerts; @@ -56278,9 +59451,9 @@ class LinesBatchingLayer { worldAABB[5] = max[2]; if (worldMatrix) { - math.AABB3ToOBB3(worldAABB, tempOBB3$1); - math.transformOBB3(worldMatrix, tempOBB3$1); - math.OBB3ToAABB3(tempOBB3$1, worldAABB); + math.AABB3ToOBB3(worldAABB, tempOBB3$2); + math.transformOBB3(worldMatrix, tempOBB3$2); + math.OBB3ToAABB3(tempOBB3$2, worldAABB); } } else { @@ -56303,23 +59476,23 @@ class LinesBatchingLayer { for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { - tempVec4a$8[0] = buffer.positions[i + 0]; - tempVec4a$8[1] = buffer.positions[i + 1]; - tempVec4a$8[2] = buffer.positions[i + 2]; + tempVec4a$a[0] = buffer.positions[i + 0]; + tempVec4a$a[1] = buffer.positions[i + 1]; + tempVec4a$a[2] = buffer.positions[i + 2]; - math.transformPoint4(meshMatrix, tempVec4a$8, tempVec4b$8); + math.transformPoint4(meshMatrix, tempVec4a$a, tempVec4b$a); - buffer.positions[i + 0] = tempVec4b$8[0]; - buffer.positions[i + 1] = tempVec4b$8[1]; - buffer.positions[i + 2] = tempVec4b$8[2]; + buffer.positions[i + 0] = tempVec4b$a[0]; + buffer.positions[i + 1] = tempVec4b$a[1]; + buffer.positions[i + 2] = tempVec4b$a[2]; - math.expandAABB3Point3(this._modelAABB, tempVec4b$8); + math.expandAABB3Point3(this._modelAABB, tempVec4b$a); if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4b$8, tempVec4c$5); - math.expandAABB3Point3(worldAABB, tempVec4c$5); + math.transformPoint4(worldMatrix, tempVec4b$a, tempVec4c$7); + math.expandAABB3Point3(worldAABB, tempVec4c$7); } else { - math.expandAABB3Point3(worldAABB, tempVec4b$8); + math.expandAABB3Point3(worldAABB, tempVec4b$a); } } @@ -56327,17 +59500,17 @@ class LinesBatchingLayer { for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { - tempVec4a$8[0] = buffer.positions[i + 0]; - tempVec4a$8[1] = buffer.positions[i + 1]; - tempVec4a$8[2] = buffer.positions[i + 2]; + tempVec4a$a[0] = buffer.positions[i + 0]; + tempVec4a$a[1] = buffer.positions[i + 1]; + tempVec4a$a[2] = buffer.positions[i + 2]; - math.expandAABB3Point3(this._modelAABB, tempVec4a$8); + math.expandAABB3Point3(this._modelAABB, tempVec4a$a); if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4a$8, tempVec4b$8); - math.expandAABB3Point3(worldAABB, tempVec4b$8); + math.transformPoint4(worldMatrix, tempVec4a$a, tempVec4b$a); + math.expandAABB3Point3(worldAABB, tempVec4b$a); } else { - math.expandAABB3Point3(worldAABB, tempVec4a$8); + math.expandAABB3Point3(worldAABB, tempVec4a$a); } } } @@ -56355,13 +59528,39 @@ class LinesBatchingLayer { math.expandAABB3(this.aabb, worldAABB); - if (color) { + if (normalsCompressed && normalsCompressed.length > 0) { + for (let i = 0, len = normalsCompressed.length; i < len; i++) { + buffer.normals.push(normalsCompressed[i]); + } + } else if (normals && normals.length > 0) { + const worldNormalMatrix = tempMat4$2; + if (meshMatrix) { + math.inverseMat4(math.transposeMat4(meshMatrix, tempMat4b), worldNormalMatrix); // Note: order of inverse and transpose doesn't matter + } else { + math.identityMat4(worldNormalMatrix, worldNormalMatrix); + } + transformAndOctEncodeNormals(worldNormalMatrix, normals, normals.length, buffer.normals, buffer.normals.length); + } + if (colors) { + for (let i = 0, len = colors.length; i < len; i += 3) { + buffer.colors.push(colors[i] * 255); + buffer.colors.push(colors[i + 1] * 255); + buffer.colors.push(colors[i + 2] * 255); + buffer.colors.push(255); + } + } else if (colorsCompressed) { + for (let i = 0, len = colors.length; i < len; i += 3) { + buffer.colors.push(colors[i]); + buffer.colors.push(colors[i + 1]); + buffer.colors.push(colors[i + 2]); + buffer.colors.push(255); + } + } else if (color) { const r = color[0]; // Color is pre-quantized by VBOSceneModel const g = color[1]; const b = color[2]; const a = opacity; - for (let i = 0; i < numVerts; i++) { buffer.colors.push(r); buffer.colors.push(g); @@ -56369,14 +59568,47 @@ class LinesBatchingLayer { buffer.colors.push(a); } } + const metallicValue = (metallic !== null && metallic !== undefined) ? metallic : 0; + const roughnessValue = (roughness !== null && roughness !== undefined) ? roughness : 255; + for (let i = 0; i < numVerts; i++) { + buffer.metallicRoughness.push(metallicValue); + buffer.metallicRoughness.push(roughnessValue); + } + + if (uv && uv.length > 0) { + for (let i = 0, len = uv.length; i < len; i++) { + buffer.uv.push(uv[i]); + } + } else if (uvCompressed && uvCompressed.length > 0) { + for (let i = 0, len = uvCompressed.length; i < len; i++) { + buffer.uv.push(uvCompressed[i]); + } + } if (indices) { for (let i = 0, len = indices.length; i < len; i++) { - buffer.indices.push(indices[i] + vertsIndex); + buffer.indices.push(vertsBaseIndex + indices[i]); } } - if (this.model.scene.entityOffsetsEnabled) { + if (edgeIndices) { + for (let i = 0, len = edgeIndices.length; i < len; i++) { + buffer.edgeIndices.push(vertsBaseIndex + edgeIndices[i]); + } + } + + { + const pickColorsBase = buffer.pickColors.length; + const lenPickColors = numVerts * 4; + for (let i = pickColorsBase, len = pickColorsBase + lenPickColors; i < len; i += 4) { + buffer.pickColors.push(pickColor[0]); + buffer.pickColors.push(pickColor[1]); + buffer.pickColors.push(pickColor[2]); + buffer.pickColors.push(pickColor[3]); + } + } + + if (scene.entityOffsetsEnabled) { for (let i = 0; i < numVerts; i++) { buffer.offsets.push(0); buffer.offsets.push(0); @@ -56384,15 +59616,30 @@ class LinesBatchingLayer { } } - const portionId = this._portions.length / 2; + const portionId = this._portions.length; - this._portions.push(vertsIndex); - this._portions.push(numVerts); + const portion = { + vertsBaseIndex: vertsBaseIndex, + numVerts: numVerts + }; + + if (scene.pickSurfacePrecisionEnabled) { + // Quantized in-memory positions are initialized in finalize() + if (indices) { + portion.indices = indices; + } + if (scene.entityOffsetsEnabled) { + portion.offset = new Float32Array(3); + } + } + + this._portions.push(portion); this._numPortions++; + this.model.numPortions++; - this._numVerts += numVerts; + this._numVerts += portion.numVerts; return portionId; } @@ -56413,24 +59660,57 @@ class LinesBatchingLayer { const buffer = this._buffer; if (buffer.positions.length > 0) { - if (this._preCompressedPositionsExpected) { - const positions = new Uint16Array(buffer.positions); - state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, positions, buffer.positions.length, 3, gl.STATIC_DRAW); - } else { - const positions = new Float32Array(buffer.positions); - const quantizedPositions = quantizePositions(positions, this._modelAABB, state.positionsDecodeMatrix); - state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, buffer.positions.length, 3, gl.STATIC_DRAW); + + const quantizedPositions = (this._preCompressedPositionsExpected) + ? new Uint16Array(buffer.positions) + : quantizePositions(buffer.positions, this._modelAABB, state.positionsDecodeMatrix); // BOTTLENECK + + state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, quantizedPositions.length, 3, gl.STATIC_DRAW); + + if (this.model.scene.pickSurfacePrecisionEnabled) { + for (let i = 0, numPortions = this._portions.length; i < numPortions; i++) { + const portion = this._portions[i]; + const start = portion.vertsBaseIndex * 3; + const end = start + (portion.numVerts * 3); + portion.quantizedPositions = quantizedPositions.slice(start, end); + } } } + if (buffer.normals.length > 0) { + const normals = new Int8Array(buffer.normals); + let normalized = true; // For oct encoded UInts + state.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, normals, buffer.normals.length, 3, gl.STATIC_DRAW, normalized); + } + if (buffer.colors.length > 0) { const colors = new Uint8Array(buffer.colors); let normalized = false; state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, buffer.colors.length, 4, gl.DYNAMIC_DRAW, normalized); } - if (buffer.colors.length > 0) { // Because we build flags arrays here, get their length from the colors array - const flagsLength = buffer.colors.length; + if (buffer.uv.length > 0) { + if (!state.uvDecodeMatrix) { + const bounds = geometryCompressionUtils.getUVBounds(buffer.uv); + const result = geometryCompressionUtils.compressUVs(buffer.uv, bounds.min, bounds.max); + const uv = result.quantized; + let notNormalized = false; + state.uvDecodeMatrix = math.mat3(result.decodeMatrix); + state.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uv, uv.length, 2, gl.STATIC_DRAW, notNormalized); + } else { + let notNormalized = false; + state.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, buffer.uv, buffer.uv.length, 2, gl.STATIC_DRAW, notNormalized); + } + } + + if (buffer.metallicRoughness.length > 0) { + const metallicRoughness = new Uint8Array(buffer.metallicRoughness); + let normalized = false; + state.metallicRoughnessBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, metallicRoughness, buffer.metallicRoughness.length, 2, gl.STATIC_DRAW, normalized); + } + + if (buffer.positions.length > 0) { // Because we build flags arrays here, get their length from the positions array + const flagsLength = (buffer.positions.length / 3) * 4; const flags = new Uint8Array(flagsLength); const flags2 = new Uint8Array(flagsLength); let notNormalized = false; @@ -56439,6 +59719,12 @@ class LinesBatchingLayer { state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags2, flags2.length, 4, gl.DYNAMIC_DRAW, normalized); } + if (buffer.pickColors.length > 0) { + const pickColors = new Uint8Array(buffer.pickColors); + let normalized = false; + state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, pickColors, buffer.pickColors.length, 4, gl.STATIC_DRAW, normalized); + } + if (this.model.scene.entityOffsetsEnabled) { if (buffer.offsets.length > 0) { const offsets = new Float32Array(buffer.offsets); @@ -56450,11 +59736,32 @@ class LinesBatchingLayer { const indices = new Uint32Array(buffer.indices); state.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, indices, buffer.indices.length, 1, gl.STATIC_DRAW); } + if (buffer.edgeIndices.length > 0) { + const edgeIndices = new Uint32Array(buffer.edgeIndices); + state.edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, edgeIndices, buffer.edgeIndices.length, 1, gl.STATIC_DRAW); + } + + this._state.pbrSupported + = !!state.metallicRoughnessBuf + && !!state.uvBuf + && !!state.normalsBuf + && !!state.textureSet + && !!state.textureSet.colorTexture + && !!state.textureSet.metallicRoughnessTexture; + + this._state.colorTextureSupported + = !!state.uvBuf + && !!state.textureSet + && !!state.textureSet.colorTexture; this._buffer = null; this._finalized = true; } + isEmpty() { + return (!this._state.indicesBuf); + } + initFlags(portionId, flags, meshTransparent) { if (flags & ENTITY_FLAGS.VISIBLE) { this._numVisibleLayerPortions++; @@ -56624,10 +59931,11 @@ class LinesBatchingLayer { if (!this._finalized) { throw "Not finalized"; } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstColor = vertexBase * 4; + const portionsIdx = portionId; + const portion = this._portions[portionsIdx]; + const vertsBaseIndex = portion.vertsBaseIndex; + const numVerts = portion.numVerts; + const firstColor = vertsBaseIndex * 4; const lenColor = numVerts * 4; const tempArray = this._scratchMemory.getUInt8Array(lenColor); const r = color[0]; @@ -56640,7 +59948,9 @@ class LinesBatchingLayer { tempArray[i + 2] = b; tempArray[i + 3] = a; } - this._state.colorsBuf.setData(tempArray, firstColor, lenColor); + if (this._state.colorsBuf) { + this._state.colorsBuf.setData(tempArray, firstColor, lenColor); + } } setTransparent(portionId, flags, transparent) { @@ -56660,17 +59970,18 @@ class LinesBatchingLayer { throw "Not finalized"; } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstFlag = vertexBase * 4; + const portionsIdx = portionId; + const portion = this._portions[portionsIdx]; + const vertsBaseIndex = portion.vertsBaseIndex; + const numVerts = portion.numVerts; + const firstFlag = vertsBaseIndex * 4; const lenFlags = numVerts * 4; - this._scratchMemory.getUInt8Array(lenFlags); const visible = !!(flags & ENTITY_FLAGS.VISIBLE); const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); const selected = !!(flags & ENTITY_FLAGS.SELECTED); + const edges = !!(flags & ENTITY_FLAGS.EDGES); const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); const culled = !!(flags & ENTITY_FLAGS.CULLED); @@ -56679,7 +59990,7 @@ class LinesBatchingLayer { let f0; if (!visible || culled || xrayed || (highlighted && !this.model.scene.highlightMaterial.glowThrough) - || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { + || (selected && !this.model.scene.selectedMaterial.glowThrough)) { f0 = RENDER_PASSES.NOT_RENDERED; } else { if (transparent) { @@ -56704,26 +60015,49 @@ class LinesBatchingLayer { f1 = RENDER_PASSES.NOT_RENDERED; } + // Edges + + let f2 = 0; + if (!visible || culled) { + f2 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f2 = RENDER_PASSES.EDGES_SELECTED; + } else if (highlighted) { + f2 = RENDER_PASSES.EDGES_HIGHLIGHTED; + } else if (xrayed) { + f2 = RENDER_PASSES.EDGES_XRAYED; + } else if (edges) { + if (transparent) { + f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT; + } else { + f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE; + } + } else { + f2 = RENDER_PASSES.NOT_RENDERED; + } + // Pick let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; + if (deferred) { + // Avoid zillions of individual WebGL bufferSubData calls - buffer them to apply in one shot if (!this._deferredFlagValues) { this._deferredFlagValues = new Uint8Array(this._numVerts * 4); } for (let i = firstFlag, len = (firstFlag + lenFlags); i < len; i += 4) { this._deferredFlagValues[i + 0] = f0; this._deferredFlagValues[i + 1] = f1; - this._deferredFlagValues[i + 2] = 0; + this._deferredFlagValues[i + 2] = f2; this._deferredFlagValues[i + 3] = f3; } } else if (this._state.flagsBuf) { const tempArray = this._scratchMemory.getUInt8Array(lenFlags); for (let i = 0; i < lenFlags; i += 4) { - tempArray[i + 0] = f0; // x - color - tempArray[i + 1] = f1; // y - silhouette - select/highlight/xray - tempArray[i + 2] = 0; // z - edges - tempArray[i + 3] = f3; // w - pickable + tempArray[i + 0] = f0; // x - normal fill + tempArray[i + 1] = f1; // y - emphasis fill + tempArray[i + 2] = f2; // z - edges + tempArray[i + 3] = f3; // w - pick } this._state.flagsBuf.setData(tempArray, firstFlag, lenFlags); } @@ -56737,15 +60071,19 @@ class LinesBatchingLayer { } _setFlags2(portionId, flags, deferred = false) { + if (!this._finalized) { throw "Not finalized"; } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstFlag = vertexBase * 4; + + const portionsIdx = portionId; + const portion = this._portions[portionsIdx]; + const vertsBaseIndex = portion.vertsBaseIndex; + const numVerts = portion.numVerts; + const firstFlag = vertsBaseIndex * 4; const lenFlags = numVerts * 4; const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; + if (deferred) { if (!this._setDeferredFlag2Values) { this._setDeferredFlag2Values = new Uint8Array(this._numVerts * 4); @@ -56753,7 +60091,7 @@ class LinesBatchingLayer { for (let i = firstFlag, len = (firstFlag + lenFlags); i < len; i += 4) { this._setDeferredFlag2Values[i] = clippable; } - } else { + } else if (this._state.flags2Buf) { const tempArray = this._scratchMemory.getUInt8Array(lenFlags); for (let i = 0; i < lenFlags; i += 4) { tempArray[i + 0] = clippable; @@ -56777,10 +60115,11 @@ class LinesBatchingLayer { this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled return; } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstOffset = vertexBase * 3; + const portionsIdx = portionId; + const portion = this._portions[portionsIdx]; + const vertsBaseIndex = portion.vertsBaseIndex; + const numVerts = portion.numVerts; + const firstOffset = vertsBaseIndex * 3; const lenOffsets = numVerts * 3; const tempArray = this._scratchMemory.getFloat32Array(lenOffsets); const x = offset[0]; @@ -56791,17 +60130,72 @@ class LinesBatchingLayer { tempArray[i + 1] = y; tempArray[i + 2] = z; } - this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets); + if (this._state.offsetsBuf) { + this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets); + } + if (this.model.scene.pickSurfacePrecisionEnabled) { + portion.offset[0] = offset[0]; + portion.offset[1] = offset[1]; + portion.offset[2] = offset[2]; + } } - //-- RENDERING ---------------------------------------------------------------------------------------------- + // ---------------------- COLOR RENDERING ----------------------------------- drawColorOpaque(renderFlags, frameCtx) { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { return; } - if (this._batchingRenderers.colorRenderer) { - this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + this._updateBackfaceCull(renderFlags, frameCtx); + if (frameCtx.withSAO && this.model.saoEnabled) { + if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { + if (this._batchingRenderers.pbrRendererWithSAO) { + this._batchingRenderers.pbrRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { + if (this._batchingRenderers.colorTextureRendererWithSAO) { + this._batchingRenderers.colorTextureRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (this._state.normalsBuf) { + if (this._batchingRenderers.colorRendererWithSAO) { + this._batchingRenderers.colorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else { + if (this._batchingRenderers.flatColorRendererWithSAO) { + this._batchingRenderers.flatColorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } + } else { + if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { + if (this._batchingRenderers.pbrRenderer) { + this._batchingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { + if (this._batchingRenderers.colorTextureRenderer) { + this._batchingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (this._state.normalsBuf) { + if (this._batchingRenderers.colorRenderer) { + this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else { + if (this._batchingRenderers.flatColorRenderer) { + this._batchingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } + } + } + + _updateBackfaceCull(renderFlags, frameCtx) { + const backfaces = this.model.backfaces || (!this.solid) || renderFlags.sectioned; + if (frameCtx.backfaces !== backfaces) { + const gl = frameCtx.gl; + if (backfaces) { + gl.disable(gl.CULL_FACE); + } else { + gl.enable(gl.CULL_FACE); + } + frameCtx.backfaces = backfaces; } } @@ -56809,21 +60203,55 @@ class LinesBatchingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { return; } - if (this._batchingRenderers.colorRenderer) { - this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + this._updateBackfaceCull(renderFlags, frameCtx); + if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { + if (this._batchingRenderers.pbrRenderer) { + this._batchingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { + if (this._batchingRenderers.colorTextureRenderer) { + this._batchingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } else if (this._state.normalsBuf) { + if (this._batchingRenderers.colorRenderer) { + this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } else { + if (this._batchingRenderers.flatColorRenderer) { + this._batchingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } } } + // ---------------------- RENDERING SAO POST EFFECT TARGETS -------------- + drawDepth(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._batchingRenderers.depthRenderer) { + this._batchingRenderers.depthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses depth (eg SAO) does not apply to transparent objects + } } drawNormals(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._batchingRenderers.normalsRenderer) { + this._batchingRenderers.normalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses normals (eg SAO) does not apply to transparent objects + } } + // ---------------------- SILHOUETTE RENDERING ----------------------------------- + drawSilhouetteXRayed(renderFlags, frameCtx) { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { return; } + this._updateBackfaceCull(renderFlags, frameCtx); if (this._batchingRenderers.silhouetteRenderer) { this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); } @@ -56833,6 +60261,7 @@ class LinesBatchingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { return; } + this._updateBackfaceCull(renderFlags, frameCtx); if (this._batchingRenderers.silhouetteRenderer) { this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); } @@ -56842,41 +60271,223 @@ class LinesBatchingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { return; } + this._updateBackfaceCull(renderFlags, frameCtx); if (this._batchingRenderers.silhouetteRenderer) { this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); } } + // ---------------------- EDGES RENDERING ----------------------------------- + drawEdgesColorOpaque(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) { + return; + } + if (this._batchingRenderers.edgesColorRenderer) { + this._batchingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_OPAQUE); + } } drawEdgesColorTransparent(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0 || this._numTransparentLayerPortions === 0) { + return; + } + if (this._batchingRenderers.edgesColorRenderer) { + this._batchingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_TRANSPARENT); + } } drawEdgesHighlighted(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + return; + } + if (this._batchingRenderers.edgesRenderer) { + this._batchingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_HIGHLIGHTED); + } } drawEdgesSelected(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { + return; + } + if (this._batchingRenderers.edgesRenderer) { + this._batchingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_SELECTED); + } } drawEdgesXRayed(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + return; + } + if (this._batchingRenderers.edgesRenderer) { + this._batchingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_XRAYED); + } } - drawPickMesh(frameCtx) { + // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- + + drawOcclusion(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._batchingRenderers.occlusionRenderer) { + this._batchingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } } - drawPickDepths(frameCtx) { + // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- + + drawShadow(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._batchingRenderers.shadowRenderer) { + this._batchingRenderers.shadowRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } } - drawPickNormals(frameCtx) { + //---- PICKING ---------------------------------------------------------------------------------------------------- + + drawPickMesh(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._batchingRenderers.pickMeshRenderer) { + this._batchingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } } - drawOcclusion(frameCtx) { + drawPickDepths(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._batchingRenderers.pickDepthRenderer) { + this._batchingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } } - drawShadow(frameCtx) { + drawPickNormals(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // TODO + // if (this._state.normalsBuf) { + // if (this._batchingRenderers.pickNormalsRenderer) { + // this._batchingRenderers.pickNormalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + // } + //////////////////////////////////////////////////////////////////////////////////////////////////// + // } else { + if (this._batchingRenderers.pickNormalsFlatRenderer) { + this._batchingRenderers.pickNormalsFlatRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } + // } + } + + //------------------------------------------------------------------------------------------------ + + precisionRayPickSurface(portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldNormal) { + + if (!this.model.scene.pickSurfacePrecisionEnabled) { + return false; + } + + const state = this._state; + const portion = this._portions[portionId]; + + if (!portion) { + this.model.error("portion not found: " + portionId); + return false; + } + + const positions = portion.quantizedPositions; + const indices = portion.indices; + const origin = state.origin; + const offset = portion.offset; + + const rtcRayOrigin = tempVec3a$G; + const rtcRayDir = tempVec3b$7; + + rtcRayOrigin.set(origin ? math.subVec3(worldRayOrigin, origin, tempVec3c$5) : worldRayOrigin); // World -> RTC + rtcRayDir.set(worldRayDir); + + if (offset) { + math.subVec3(rtcRayOrigin, offset); + } + + math.transformRay(this.model.worldNormalMatrix, rtcRayOrigin, rtcRayDir, rtcRayOrigin, rtcRayDir); // RTC -> local + + const a = tempVec3d$2; + const b = tempVec3e$1; + const c = tempVec3f$1; + + let gotIntersect = false; + let closestDist = 0; + const closestIntersectPos = tempVec3g$1; + + for (let i = 0, len = indices.length; i < len; i += 3) { + + const ia = indices[i] * 3; + const ib = indices[i + 1] * 3; + const ic = indices[i + 2] * 3; + + a[0] = positions[ia]; + a[1] = positions[ia + 1]; + a[2] = positions[ia + 2]; + + b[0] = positions[ib]; + b[1] = positions[ib + 1]; + b[2] = positions[ib + 2]; + + c[0] = positions[ic]; + c[1] = positions[ic + 1]; + c[2] = positions[ic + 2]; + + math.decompressPosition(a, state.positionsDecodeMatrix); + math.decompressPosition(b, state.positionsDecodeMatrix); + math.decompressPosition(c, state.positionsDecodeMatrix); + + if (math.rayTriangleIntersect(rtcRayOrigin, rtcRayDir, a, b, c, closestIntersectPos)) { + + math.transformPoint3(this.model.worldMatrix, closestIntersectPos, closestIntersectPos); + + if (offset) { + math.addVec3(closestIntersectPos, offset); + } + + if (origin) { + math.addVec3(closestIntersectPos, origin); + } + + const dist = Math.abs(math.lenVec3(math.subVec3(closestIntersectPos, worldRayOrigin, []))); + + if (!gotIntersect || dist > closestDist) { + closestDist = dist; + worldSurfacePos.set(closestIntersectPos); + if (worldNormal) { // Not that wasteful to eagerly compute - unlikely to hit >2 surfaces on most geometry + math.triangleNormal(a, b, c, worldNormal); + } + gotIntersect = true; + } + } + } + + if (gotIntersect && worldNormal) { + math.transformVec3(this.model.worldNormalMatrix, worldNormal, worldNormal); + math.normalizeVec3(worldNormal); + } + + return gotIntersect; } + // --------- + destroy() { const state = this._state; if (state.positionsBuf) { @@ -56887,10 +60498,18 @@ class LinesBatchingLayer { state.offsetsBuf.destroy(); state.offsetsBuf = null; } + if (state.normalsBuf) { + state.normalsBuf.destroy(); + state.normalsBuf = null; + } if (state.colorsBuf) { state.colorsBuf.destroy(); state.colorsBuf = null; } + if (state.metallicRoughnessBuf) { + state.metallicRoughnessBuf.destroy(); + state.metallicRoughnessBuf = null; + } if (state.flagsBuf) { state.flagsBuf.destroy(); state.flagsBuf = null; @@ -56899,23 +60518,33 @@ class LinesBatchingLayer { state.flags2Buf.destroy(); state.flags2Buf = null; } + if (state.pickColorsBuf) { + state.pickColorsBuf.destroy(); + state.pickColorsBuf = null; + } if (state.indicesBuf) { state.indicesBuf.destroy(); state.indicessBuf = null; } + if (state.edgeIndicesBuf) { + state.edgeIndicesBuf.destroy(); + state.edgeIndicessBuf = null; + } state.destroy(); } } -const tempVec3a$o = math.vec3(); +const tempVec4$3 = math.vec4(); +const tempVec3a$F = math.vec3(); /** * @private */ -class LinesInstancingColorRenderer { +class TrianglesInstancingColorRenderer { - constructor(scene) { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -56925,7 +60554,8 @@ class LinesInstancingColorRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash(); + const scene = this._scene; + return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } drawLayer(frameCtx, instancingLayer, renderPass) { @@ -56935,8 +60565,8 @@ class LinesInstancingColorRenderer { const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; const origin = instancingLayer._state.origin; - const geometry = instancingLayer.geometry; if (!this._program) { this._allocate(); @@ -56953,9 +60583,10 @@ class LinesInstancingColorRenderer { gl.uniform1i(this._uRenderPass, renderPass); gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); - gl.lineWidth(scene.linesMaterial.lineWidth); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { @@ -56970,7 +60601,7 @@ class LinesInstancingColorRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$o); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$F); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -56991,7 +60622,16 @@ class LinesInstancingColorRenderer { gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); + this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); + this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + this._aNormal.bindArrayBuffer(geometry.normalsBuf); this._aColor.bindArrayBuffer(state.colorsBuf); gl.vertexAttribDivisor(this._aColor.location, 1); @@ -57011,14 +60651,16 @@ class LinesInstancingColorRenderer { geometry.indicesBuf.bind(); - gl.drawElementsInstanced(gl.LINES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); frameCtx.drawElements++; gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - + gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); gl.vertexAttribDivisor(this._aColor.location, 0); gl.vertexAttribDivisor(this._aFlags.location, 0); @@ -57035,6 +60677,7 @@ class LinesInstancingColorRenderer { const scene = this._scene; const gl = scene.canvas.gl; + const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -57050,10 +60693,44 @@ class LinesInstancingColorRenderer { this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); + this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; + + const lights = lightsState.lights; + let light; + + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + this._uSectionPlanes = []; for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { @@ -57065,6 +60742,7 @@ class LinesInstancingColorRenderer { } this._aPosition = program.getAttribute("position"); + this._aNormal = program.getAttribute("normal"); this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); @@ -57074,19 +60752,65 @@ class LinesInstancingColorRenderer { this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); + this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); + this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { + _bindProgram(frameCtx) { + const scene = this._scene; const gl = scene.canvas.gl; + const lightsState = scene._lightsState; + const lights = lightsState.lights; const project = scene.camera.project; + this._program.bind(); + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + const light = lights[i]; + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$3[0] = viewportWidth; + tempVec4$3[1] = viewportHeight; + tempVec4$3[2] = sao.blendCutoff; + tempVec4$3[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$3); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + } + } + if (scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); @@ -57103,13 +60827,19 @@ class LinesInstancingColorRenderer { _buildVertexShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; const clipping = sectionPlanesState.sectionPlanes.length > 0; + let i; + let len; + let light; const src = []; - src.push('#version 300 es'); - src.push("// Lines instancing color vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry drawing vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); + src.push("in vec2 normal;"); src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); @@ -57122,18 +60852,54 @@ class LinesInstancingColorRenderer { src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); + src.push("in vec4 modelNormalMatrixCol0;"); + src.push("in vec4 modelNormalMatrixCol1;"); + src.push("in vec4 modelNormalMatrixCol2;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 worldNormalMatrix;"); src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } src.push("uniform vec4 lightAmbient;"); + for (i = 0, len = lightsState.lights.length; i < len; i++) { + light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + + src.push("vec3 octDecode(vec2 oct) {"); + src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); + src.push(" if (v.z < 0.0) {"); + src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); + src.push(" }"); + src.push(" return normalize(v);"); + src.push("}"); + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); @@ -57158,16 +60924,58 @@ class LinesInstancingColorRenderer { src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + src.push("vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); + src.push("vec4 worldNormal = worldNormalMatrix * vec4(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2), 0.0);"); + src.push("vec3 viewNormal = normalize(vec4(viewNormalMatrix * worldNormal).xyz);"); - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); + src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); + + src.push("float lambertian = 1.0;"); + for (i = 0, len = lightsState.lights.length; i < len; i++) { + light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); + } else { + src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } + src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); + src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); } + + src.push("vec3 rgb = (vec3(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0));"); + src.push("vColor = vec4((lightAmbient.rgb * lightAmbient.a * rgb) + (reflectedColor * rgb), float(color.a) / 255.0);"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + } + + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } + src.push("gl_Position = clipPos;"); src.push("}"); src.push("}"); @@ -57177,12 +60985,11 @@ class LinesInstancingColorRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; - let i; - let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Lines instancing color fragment shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -57191,13 +60998,27 @@ class LinesInstancingColorRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); + } + if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); @@ -57206,19 +61027,26 @@ class LinesInstancingColorRenderer { src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); src.push("}"); } + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject @@ -57228,14 +61056,11 @@ class LinesInstancingColorRenderer { src.push(" float blendCutoff = uSAOParams[2];"); src.push(" float blendFactor = uSAOParams[3];"); src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); - src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBAToDepth(texture(uOcclusionTexture, uv))) * blendFactor;"); - src.push(" outColor = vec4(vColor.rgb * ambient, vColor.a);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" outColor = vec4(vColor.rgb * ambient, 1.0);"); } else { src.push(" outColor = vColor;"); } - if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } src.push("}"); return src; } @@ -57252,15 +61077,17 @@ class LinesInstancingColorRenderer { } } -const tempVec3a$n = math.vec3(); +const tempVec4$2 = math.vec4(); +const tempVec3a$E = math.vec3(); /** * @private */ -class LinesInstancingSilhouetteRenderer { +class TrianglesInstancingFlatColorRenderer { - constructor(scene) { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -57270,7 +61097,8 @@ class LinesInstancingSilhouetteRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash(); + const scene = this._scene; + return [scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } drawLayer(frameCtx, instancingLayer, renderPass) { @@ -57280,11 +61108,11 @@ class LinesInstancingSilhouetteRenderer { const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; const origin = instancingLayer._state.origin; - const geometry = instancingLayer.geometry; if (!this._program) { - this._allocate(instancingLayer.model.scene); + this._allocate(); if (this.errors) { return; } @@ -57292,38 +61120,14 @@ class LinesInstancingSilhouetteRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx); } gl.uniform1i(this._uRenderPass, renderPass); - if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { - const material = scene.xrayMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { - const material = scene.selectedMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else { - gl.uniform4fv(this._uColor, math.vec3([1, 1, 1])); - } - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.lineWidth(scene.linesMaterial.lineWidth); - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; @@ -57331,19 +61135,17 @@ class LinesInstancingSilhouetteRenderer { const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$n); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$E); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } } @@ -57358,13 +61160,16 @@ class LinesInstancingSilhouetteRenderer { gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); - this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + this._aFlags.bindArrayBuffer(state.flagsBuf); gl.vertexAttribDivisor(this._aFlags.location, 1); if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + this._aFlags2.bindArrayBuffer(state.flags2Buf); gl.vertexAttribDivisor(this._aFlags2.location, 1); } @@ -57375,16 +61180,18 @@ class LinesInstancingSilhouetteRenderer { geometry.indicesBuf.bind(); - gl.drawElementsInstanced(gl.LINES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - + gl.vertexAttribDivisor(this._aColor.location, 0); gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags2) { + + if (this._aFlags2) { // Won't be in shader when not clipping gl.vertexAttribDivisor(this._aFlags2.location, 0); } + if (this._aOffset) { gl.vertexAttribDivisor(this._aOffset.location, 0); } @@ -57394,7 +61201,7 @@ class LinesInstancingSilhouetteRenderer { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -57406,15 +61213,49 @@ class LinesInstancingSilhouetteRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uColor = program.getLocation("color"); + + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; + + const lights = lightsState.lights; + let light; + + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -57423,28 +61264,70 @@ class LinesInstancingSilhouetteRenderer { } this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aOffset = program.getAttribute("offset"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { + _bindProgram(frameCtx) { const scene = this._scene; const gl = scene.canvas.gl; + const lightsState = scene._lightsState; + const lights = lightsState.lights; const project = scene.camera.project; this._program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + const light = lights[i]; + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$2[0] = viewportWidth; + tempVec4$2[1] = viewportHeight; + tempVec4$2[2] = sao.blendCutoff; + tempVec4$2[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$2); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + } + } + if (scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); @@ -57463,21 +61346,24 @@ class LinesInstancingSilhouetteRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Lines instancing silhouette vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry flat-shading drawing vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); src.push("in vec4 modelMatrixCol0;"); // Modeling matrix src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); - + src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); @@ -57486,40 +61372,51 @@ class LinesInstancingSilhouetteRenderer { if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); - } - - src.push("uniform vec4 color;"); - + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); + } + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } + src.push("out vec4 vViewPosition;"); + src.push("out vec4 vColor;"); + src.push("void main(void) {"); - // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT - src.push(`if (int(flags.y) != renderPass) {`); + src.push(`if (int(flags.x) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vViewPosition = viewPosition;"); + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + } if (clipping) { src.push("vWorldPosition = worldPosition;"); src.push("vFlags2 = flags2;"); } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - } + src.push("gl_Position = clipPos;"); src.push("}"); src.push("}"); @@ -57529,10 +61426,14 @@ class LinesInstancingSilhouetteRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; + let i; + let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Lines instancing silhouette fragment shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry flat-shading drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -57541,9 +61442,23 @@ class LinesInstancingSilhouetteRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + src.push("in float isPerspective;"); + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); } + if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); @@ -57553,9 +61468,35 @@ class LinesInstancingSilhouetteRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("uniform vec4 color;"); + + src.push("uniform mat4 viewMatrix;"); + + src.push("uniform vec4 lightAmbient;"); + + for (i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + + src.push("in vec4 vViewPosition;"); + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); @@ -57565,766 +61506,93 @@ class LinesInstancingSilhouetteRenderer { src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); src.push("}"); } - if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push("outColor = color;"); - src.push("}"); - return src; - } - - webglContextRestored() { - this._program = null; - } - - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; - } -} - -/** - * @private - */ -class LinesInstancingRenderers { - - constructor(scene) { - this._scene = scene; - } - - _compile() { - if (this._colorRenderer && (!this._colorRenderer.getValid())) { - this._colorRenderer.destroy(); - this._colorRenderer = null; - } - if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { - this._silhouetteRenderer.destroy(); - this._silhouetteRenderer = null; - } - } - - get colorRenderer() { - if (!this._colorRenderer) { - this._colorRenderer = new LinesInstancingColorRenderer(this._scene); - } - return this._colorRenderer; - } - - get silhouetteRenderer() { - if (!this._silhouetteRenderer) { - this._silhouetteRenderer = new LinesInstancingSilhouetteRenderer(this._scene); - } - return this._silhouetteRenderer; - } - - _destroy() { - if (this._colorRenderer) { - this._colorRenderer.destroy(); - } - if (this._silhouetteRenderer) { - this._silhouetteRenderer.destroy(); - } - } -} - -const cachedRenderers$2 = {}; - -/** - * @private - */ -function getInstancingRenderers(scene) { - const sceneId = scene.id; - let instancingRenderers = cachedRenderers$2[sceneId]; - if (!instancingRenderers) { - instancingRenderers = new LinesInstancingRenderers(scene); - cachedRenderers$2[sceneId] = instancingRenderers; - instancingRenderers._compile(); - scene.on("compile", () => { - instancingRenderers._compile(); - }); - scene.on("destroyed", () => { - delete cachedRenderers$2[sceneId]; - instancingRenderers._destroy(); - }); - } - return instancingRenderers; -} - -const tempUint8Vec4$1 = new Uint8Array(4); - -const tempVec4a$7 = math.vec4([0, 0, 0, 1]); -const tempVec4b$7 = math.vec4([0, 0, 0, 1]); -const tempVec4c$4 = math.vec4([0, 0, 0, 1]); - -const tempVec3fa$1 = new Float32Array(3); - -/** - * @private - */ -class LinesInstancingLayer { - - /** - * @param cfg - * @param cfg.layerIndex - * @param cfg.model - * @param cfg.geometry - * @param cfg.material - * @param cfg.origin - */ - constructor(cfg) { - - /** - * Owner model - * @type {VBOSceneModel} - */ - this.model = cfg.model; - - /** - * Shared geometry - * @type {VBOSceneModelGeometry} - */ - this.geometry = cfg.geometry; - - /** - * Shared material - * @type {VBOSceneModelGeometry} - */ - this.material = cfg.material; - - /** - * State sorting key. - * @type {string} - */ - this.sortId = "LinesInstancingLayer"; - - /** - * Index of this InstancingLayer in VBOSceneModel#_layerList - * @type {Number} - */ - this.layerIndex = cfg.layerIndex; - - this._linesInstancingRenderers = getInstancingRenderers(cfg.model.scene); - - this._aabb = math.collapseAABB3(); - - this._state = new RenderState({ - obb: math.OBB3(), - numInstances: 0, - origin: null - }); - - // These counts are used to avoid unnecessary render passes - this._numPortions = 0; - this._numVisibleLayerPortions = 0; - this._numTransparentLayerPortions = 0; - this._numXRayedLayerPortions = 0; - this._numHighlightedLayerPortions = 0; - this._numSelectedLayerPortions = 0; - this._numClippableLayerPortions = 0; - this._numEdgesLayerPortions = 0; - this._numPickableLayerPortions = 0; - this._numCulledLayerPortions = 0; - - /** @private */ - this.numIndices = cfg.geometry.numIndices; - - // Vertex arrays - this._colors = []; - this._offsets = []; - - // Modeling matrix per instance, array for each column - this._modelMatrixCol0 = []; - this._modelMatrixCol1 = []; - this._modelMatrixCol2 = []; - - this._portions = []; - - if (cfg.origin) { - this._state.origin = math.vec3(cfg.origin); - } - - this._finalized = false; - - /** - * The axis-aligned World-space boundary of this InstancingLayer's positions. - * @type {*|Float64Array} - */ - this.aabb = math.collapseAABB3(); - } - - /** - * Creates a new portion within this InstancingLayer, returns the new portion ID. - * - * The portion will instance this InstancingLayer's geometry. - * - * Gives the portion the specified color and matrix. - * - * @param cfg Portion params - * @param cfg.color Color [0..255,0..255,0..255] - * @param cfg.opacity Opacity [0..255]. - * @param cfg.meshMatrix Flat float 4x4 matrix. - * @param [cfg.worldMatrix] Flat float 4x4 matrix. - * @param cfg.aabb Flat float AABB. - * @returns {number} Portion ID. - */ - createPortion(cfg) { - - const color = cfg.color; - const opacity = cfg.opacity; - const meshMatrix = cfg.meshMatrix; - const worldMatrix = cfg.worldMatrix; - const worldAABB = cfg.aabb; - - if (this._finalized) { - throw "Already finalized"; - } - - // TODO: find AABB for portion by transforming the geometry local AABB by the given meshMatrix? - - const r = color[0]; // Color is pre-quantized by VBOSceneModel - const g = color[1]; - const b = color[2]; - color[3]; - - this._colors.push(r); - this._colors.push(g); - this._colors.push(b); - this._colors.push(opacity); - - if (this.model.scene.entityOffsetsEnabled) { - this._offsets.push(0); - this._offsets.push(0); - this._offsets.push(0); - } - - this._modelMatrixCol0.push(meshMatrix[0]); - this._modelMatrixCol0.push(meshMatrix[4]); - this._modelMatrixCol0.push(meshMatrix[8]); - this._modelMatrixCol0.push(meshMatrix[12]); - - this._modelMatrixCol1.push(meshMatrix[1]); - this._modelMatrixCol1.push(meshMatrix[5]); - this._modelMatrixCol1.push(meshMatrix[9]); - this._modelMatrixCol1.push(meshMatrix[13]); - - this._modelMatrixCol2.push(meshMatrix[2]); - this._modelMatrixCol2.push(meshMatrix[6]); - this._modelMatrixCol2.push(meshMatrix[10]); - this._modelMatrixCol2.push(meshMatrix[14]); - - // Expand AABB - - math.collapseAABB3(worldAABB); - const obb = this._state.obb; - const lenPositions = obb.length; - for (let i = 0; i < lenPositions; i += 4) { - tempVec4a$7[0] = obb[i + 0]; - tempVec4a$7[1] = obb[i + 1]; - tempVec4a$7[2] = obb[i + 2]; - math.transformPoint4(meshMatrix, tempVec4a$7, tempVec4b$7); - if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4b$7, tempVec4c$4); - math.expandAABB3Point3(worldAABB, tempVec4c$4); - } else { - math.expandAABB3Point3(worldAABB, tempVec4b$7); - } - } - - if (this._state.origin) { - const origin = this._state.origin; - worldAABB[0] += origin[0]; - worldAABB[1] += origin[1]; - worldAABB[2] += origin[2]; - worldAABB[3] += origin[0]; - worldAABB[4] += origin[1]; - worldAABB[5] += origin[2]; - } - math.expandAABB3(this.aabb, worldAABB); - - this._state.numInstances++; - - const portionId = this._portions.length; - this._portions.push({}); + src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); + src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); - this._numPortions++; - this.model.numPortions++; + src.push("float lambertian = 1.0;"); - return portionId; - } + src.push("vec3 xTangent = dFdx( vViewPosition.xyz );"); + src.push("vec3 yTangent = dFdy( vViewPosition.xyz );"); + src.push("vec3 viewNormal = normalize( cross( xTangent, yTangent ) );"); - finalize() { - if (this._finalized) { - throw "Already finalized"; - } - const gl = this.model.scene.canvas.gl; - const colorsLength = this._colors.length; - const flagsLength = colorsLength; - if (colorsLength > 0) { - let notNormalized = false; - this._state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._colors), this._colors.length, 4, gl.DYNAMIC_DRAW, notNormalized); - this._colors = []; // Release memory - } - if (flagsLength > 0) { - // Because we only build flags arrays here, - // get their length from the colors array - let notNormalized = false; - let normalized = true; - this._state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, notNormalized); - this._state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, normalized); - } - if (this.model.scene.entityOffsetsEnabled) { - if (this._offsets.length > 0) { - const notNormalized = false; - this._state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._offsets), this._offsets.length, 3, gl.DYNAMIC_DRAW, notNormalized); - this._offsets = []; // Release memory + for (i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; } - } - if (this._modelMatrixCol0.length > 0) { - const normalized = false; - this._state.modelMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol0), this._modelMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); - this._state.modelMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol1), this._modelMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); - this._state.modelMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol2), this._modelMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); - this._modelMatrixCol0 = []; - this._modelMatrixCol1 = []; - this._modelMatrixCol2 = []; - } - this._finalized = true; - } - - // The following setters are called by VBOSceneModelMesh, in turn called by VBOSceneModelNode, only after the layer is finalized. - // It's important that these are called after finalize() in order to maintain integrity of counts like _numVisibleLayerPortions etc. - - initFlags(portionId, flags, meshTransparent) { - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } - if (flags & ENTITY_FLAGS.EDGES) { - this._numEdgesLayerPortions++; - this.model.numEdgesLayerPortions++; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } - if (meshTransparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } - this._setFlags(portionId, flags, meshTransparent); - this._setFlags2(portionId, flags); - } - - setVisible(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } else { - this._numVisibleLayerPortions--; - this.model.numVisibleLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } - - setHighlighted(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } else { - this._numHighlightedLayerPortions--; - this.model.numHighlightedLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } - - setXRayed(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } else { - this._numXRayedLayerPortions--; - this.model.numXRayedLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } - - setSelected(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } else { - this._numSelectedLayerPortions--; - this.model.numSelectedLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } - - setEdges(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.EDGES) { - this._numEdgesLayerPortions++; - this.model.numEdgesLayerPortions++; - } else { - this._numEdgesLayerPortions--; - this.model.numEdgesLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } - - setClippable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } else { - this._numClippableLayerPortions--; - this.model.numClippableLayerPortions--; - } - this._setFlags2(portionId, flags); - } - - setCollidable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } - } - - setPickable(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } else { - this._numPickableLayerPortions--; - this.model.numPickableLayerPortions--; - } - this._setFlags2(portionId, flags, meshTransparent); - } - - setCulled(portionId, flags, meshTransparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } else { - this._numCulledLayerPortions--; - this.model.numCulledLayerPortions--; - } - this._setFlags(portionId, flags, meshTransparent); - } - - setColor(portionId, color) { // RGBA color is normalized as ints - if (!this._finalized) { - throw "Not finalized"; - } - tempUint8Vec4$1[0] = color[0]; - tempUint8Vec4$1[1] = color[1]; - tempUint8Vec4$1[2] = color[2]; - tempUint8Vec4$1[3] = color[3]; - this._state.colorsBuf.setData(tempUint8Vec4$1, portionId * 4, 4); - } - - setTransparent(portionId, flags, transparent) { - if (transparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } else { - this._numTransparentLayerPortions--; - this.model.numTransparentLayerPortions--; - } - this._setFlags(portionId, flags, transparent); - } - - _setFlags(portionId, flags, meshTransparent) { - - if (!this._finalized) { - throw "Not finalized"; - } - - const visible = !!(flags & ENTITY_FLAGS.VISIBLE); - const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); - const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); - const selected = !!(flags & ENTITY_FLAGS.SELECTED); - const edges = !!(flags & ENTITY_FLAGS.EDGES); - const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); - const culled = !!(flags & ENTITY_FLAGS.CULLED); - - // Normal fill - - let f0; - if (!visible || culled || xrayed - || (highlighted && !this.model.scene.highlightMaterial.glowThrough) - || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { - f0 = RENDER_PASSES.NOT_RENDERED; - } else { - if (meshTransparent) { - f0 = RENDER_PASSES.COLOR_TRANSPARENT; + if (light.type === "dir") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); + } else { + src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } } else { - f0 = RENDER_PASSES.COLOR_OPAQUE; + continue; } + src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); + src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); } - // Emphasis fill - - let f1; - if (!visible || culled) { - f1 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f1 = RENDER_PASSES.SILHOUETTE_SELECTED; - } else if (highlighted) { - f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; - } else if (xrayed) { - f1 = RENDER_PASSES.SILHOUETTE_XRAYED; - } else { - f1 = RENDER_PASSES.NOT_RENDERED; - } - - // Edges + src.push("vec4 fragColor = vec4((lightAmbient.rgb * lightAmbient.a * vColor.rgb) + (reflectedColor * vColor.rgb), vColor.a);"); - let f2 = 0; - if (!visible || culled) { - f2 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f2 = RENDER_PASSES.EDGES_SELECTED; - } else if (highlighted) { - f2 = RENDER_PASSES.EDGES_HIGHLIGHTED; - } else if (xrayed) { - f2 = RENDER_PASSES.EDGES_XRAYED; - } else if (edges) { - if (meshTransparent) { - f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT; - } else { - f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE; - } + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" outColor = vec4(fragColor.rgb * ambient, 1.0);"); } else { - f2 = RENDER_PASSES.NOT_RENDERED; - } - - // Pick - - let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; - - tempUint8Vec4$1[0] = f0; // x - normal fill - tempUint8Vec4$1[1] = f1; // y - emphasis fill - tempUint8Vec4$1[2] = f2; // z - edges - tempUint8Vec4$1[3] = f3; // w - pick - - this._state.flagsBuf.setData(tempUint8Vec4$1, portionId * 4, 4); - } - - _setFlags2(portionId, flags) { - - if (!this._finalized) { - throw "Not finalized"; - } - - const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; - tempUint8Vec4$1[0] = clippable; - - this._state.flags2Buf.setData(tempUint8Vec4$1, portionId * 4, 4); - } - - setOffset(portionId, offset) { - if (!this._finalized) { - throw "Not finalized"; - } - if (!this.model.scene.entityOffsetsEnabled) { - this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled - return; - } - tempVec3fa$1[0] = offset[0]; - tempVec3fa$1[1] = offset[1]; - tempVec3fa$1[2] = offset[2]; - this._state.offsetsBuf.setData(tempVec3fa$1, portionId * 3, 3); - } - - // ---------------------- NORMAL RENDERING ----------------------------------- - - drawColorOpaque(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { - return; - } - - if (this._linesInstancingRenderers.colorRenderer) { - this._linesInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); - } - } - - drawColorTransparent(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { - return; - } - if (this._linesInstancingRenderers.colorRenderer) { - this._linesInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); - } - } - - // ---------------------- RENDERING SAO POST EFFECT TARGETS -------------- - - drawDepth(renderFlags, frameCtx) { - } - - drawNormals(renderFlags, frameCtx) { - } - - // ---------------------- EMPHASIS RENDERING ----------------------------------- - - drawSilhouetteXRayed(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { - return; - } - if (this._linesInstancingRenderers.silhouetteRenderer) { - this._linesInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); - } - } - - drawSilhouetteHighlighted(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { - return; - } - if (this._linesInstancingRenderers.silhouetteRenderer) { - this._linesInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); + src.push(" outColor = fragColor;"); } - } - drawSilhouetteSelected(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { - return; - } - if (this._linesInstancingRenderers.silhouetteRenderer) { - this._linesInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - } - - // ---------------------- EDGES RENDERING ----------------------------------- - - drawEdgesColorOpaque(renderFlags, frameCtx) { - } - - drawEdgesColorTransparent(renderFlags, frameCtx) { - } - - drawEdgesXRayed(renderFlags, frameCtx) { - } - - drawEdgesHighlighted(renderFlags, frameCtx) { - } - - drawEdgesSelected(renderFlags, frameCtx) { - } - - // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- - - drawOcclusion(renderFlags, frameCtx) { - } - - // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- - - drawShadow(renderFlags, frameCtx) { - } - - //---- PICKING ---------------------------------------------------------------------------------------------------- - - drawPickMesh(renderFlags, frameCtx) { - } - drawPickDepths(renderFlags, frameCtx) { + src.push("}"); + return src; } - drawPickNormals(renderFlags, frameCtx) { + webglContextRestored() { + this._program = null; } - destroy() { - const state = this._state; - if (state.positionsBuf) { - state.positionsBuf.destroy(); - state.positionsBuf = null; - } - if (state.colorsBuf) { - state.colorsBuf.destroy(); - state.colorsBuf = null; - } - if (state.flagsBuf) { - state.flagsBuf.destroy(); - state.flagsBuf = null; - } - if (state.flags2Buf) { - state.flags2Buf.destroy(); - state.flags2Buf = null; - } - if (state.offsetsBuf) { - state.offsetsBuf.destroy(); - state.offsetsBuf = null; - } - if (state.modelMatrixCol0Buf) { - state.modelMatrixCol0Buf.destroy(); - state.modelMatrixCol0Buf = null; - } - if (state.modelMatrixCol1Buf) { - state.modelMatrixCol1Buf.destroy(); - state.modelMatrixCol1Buf = null; - } - if (state.modelMatrixCol2Buf) { - state.modelMatrixCol2Buf.destroy(); - state.modelMatrixCol2Buf = null; + if (this._program) { + this._program.destroy(); } - state.destroy(); + this._program = null; } } -const tempVec3a$m = math.vec3(); +const tempVec3a$D = math.vec3(); /** * @private */ -class PointsBatchingColorRenderer { +class TrianglesInstancingSilhouetteRenderer { constructor(scene) { this._scene = scene; @@ -58334,24 +61602,24 @@ class PointsBatchingColorRenderer { getValid() { return this._hash === this._getHash(); - } + }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + drawLayer(frameCtx, instancingLayer, renderPass) { - const scene = this._scene; + const model = instancingLayer.model; + const scene = model.scene; const camera = scene.camera; - const model = pointsBatchingLayer.model; const gl = scene.canvas.gl; - const state = pointsBatchingLayer._state; - const origin = pointsBatchingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial; + const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; if (!this._program) { - this._allocate(); + this._allocate(instancingLayer.model.scene); if (this.errors) { return; } @@ -58364,13 +61632,35 @@ class PointsBatchingColorRenderer { gl.uniform1i(this._uRenderPass, renderPass); + if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + const material = scene.xrayMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + const material = scene.selectedMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else { + gl.uniform4fv(this._uColor, math.vec3([1, 1, 1])); + } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -58380,7 +61670,7 @@ class PointsBatchingColorRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$m); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$D); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -58391,46 +61681,55 @@ class PointsBatchingColorRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - if (this._aColor) { - this._aColor.bindArrayBuffer(state.colorsBuf); - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - if (pointsMaterial.filterIntensity) { - gl.uniform2f(this._uIntensityRange, pointsMaterial.minIntensity, pointsMaterial.maxIntensity); - } + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); - } + this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags.location, 1); if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + geometry.indicesBuf.bind(); - gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - frameCtx.drawArrays++; + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + + gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { + gl.vertexAttribDivisor(this._aFlags2.location, 0); + } + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } } _allocate() { const scene = this._scene; - const pointsMaterial = scene.pointsMaterial._state; const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; - this._program = new Program(gl, this._buildShader(scene)); + this._program = new Program(gl, this._buildShader()); if (this._program.errors) { this.errors = this._program.errors; @@ -58444,10 +61743,11 @@ class PointsBatchingColorRenderer { this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - + this._uColor = program.getLocation("color"); this._uSectionPlanes = []; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -58457,18 +61757,13 @@ class PointsBatchingColorRenderer { this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if (pointsMaterial.filterIntensity) { - this._uIntensityRange = program.getLocation("intensityRange"); - } - - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } @@ -58477,14 +61772,13 @@ class PointsBatchingColorRenderer { const scene = this._scene; const gl = scene.canvas.gl; - const program = this._program; const project = scene.camera.project; - program.bind(); + this._program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } @@ -58498,109 +61792,87 @@ class PointsBatchingColorRenderer { } _buildVertexShader() { - const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial; const src = []; - src.push('#version 300 es'); - src.push("// Points batching color vertex shader"); - + src.push("#version 300 es"); + src.push("// Instancing fill vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - src.push("uniform mat4 worldMatrix;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - - if (pointsMaterial.filterIntensity) { - src.push("uniform vec2 intensityRange;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } + src.push("uniform vec4 color;"); + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vColor;"); src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - src.push(`if (int(flags.x) != renderPass) {`); + src.push(`if (int(flags.y) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - if (pointsMaterial.filterIntensity) { - src.push("float intensity = float(color.a) / 255.0;"); - src.push("if (intensity < intensityRange[0] || intensity > intensityRange[1]) {"); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - } - - src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { - src.push("worldPosition.xyz = worldPosition.xyz + offset;"); + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, 1.0);"); - if (clipping) { src.push("vWorldPosition = worldPosition;"); src.push("vFlags2 = flags2;"); } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } src.push("}"); - if (pointsMaterial.filterIntensity) { - src.push("}"); - } src.push("}"); return src; } _buildFragmentShader() { - const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Points batching color fragment shader"); + src.push("#version 300 es"); + src.push("// Instancing fill fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -58608,8 +61880,8 @@ class PointsBatchingColorRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } @@ -58622,16 +61894,9 @@ class PointsBatchingColorRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vColor;"); + src.push("uniform vec4 color;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); @@ -58641,13 +61906,13 @@ class PointsBatchingColorRenderer { src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push(" if (dist > 0.0) { discard; }"); + src.push("if (dist > 0.0) { discard; }"); src.push("}"); } - src.push(" outColor = vColor;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push("outColor = color;"); src.push("}"); return src; } @@ -58664,13 +61929,13 @@ class PointsBatchingColorRenderer { } } -const defaultColor = new Float32Array([1, 1, 1]); -const tempVec3a$l = math.vec3(); +const tempVec3a$C = math.vec3(); +const defaultColor$2 = new Float32Array([0,0,0,1]); /** * @private */ -class PointsBatchingSilhouetteRenderer { +class TrianglesInstancingEdgesRenderer { constructor(scene) { this._scene = scene; @@ -58683,21 +61948,21 @@ class PointsBatchingSilhouetteRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + drawLayer(frameCtx, instancingLayer, renderPass) { - const model = pointsBatchingLayer.model; + const model = instancingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = pointsBatchingLayer._state; - const origin = pointsBatchingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; + const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; if (!this._program) { - this._allocate(); + this._allocate(instancingLayer); if (this.errors) { return; } @@ -58710,37 +61975,35 @@ class PointsBatchingSilhouetteRenderer { gl.uniform1i(this._uRenderPass, renderPass); - if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + if (renderPass === RENDER_PASSES.EDGES_XRAYED) { const material = scene.xrayMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + const edgeColor = material.edgeColor; + const edgeAlpha = material.edgeAlpha; + gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); - } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + } else if (renderPass === RENDER_PASSES.EDGES_HIGHLIGHTED) { const material = scene.highlightMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + const edgeColor = material.edgeColor; + const edgeAlpha = material.edgeAlpha; + gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); - } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + } else if (renderPass === RENDER_PASSES.EDGES_SELECTED) { const material = scene.selectedMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + const edgeColor = material.edgeColor; + const edgeAlpha = material.edgeAlpha; + gl.uniform4f(this._uColor, edgeColor[0], edgeColor[1], edgeColor[2], edgeAlpha); } else { - gl.uniform4fv(this._uColor, defaultColor); + gl.uniform4fv(this._uColor, defaultColor$2); } - const viewMat = (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix; - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMat); - + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -58750,7 +62013,7 @@ class PointsBatchingSilhouetteRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$l); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$C); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -58761,33 +62024,58 @@ class PointsBatchingSilhouetteRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags.location, 1); + } + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } + + geometry.edgeIndicesBuf.bind(); + + gl.drawElementsInstanced(gl.LINES, geometry.edgeIndicesBuf.numItems, geometry.edgeIndicesBuf.itemType, 0, state.numInstances); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 0); } if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - - gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); } _allocate() { - const scene = this._scene; const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -58799,14 +62087,15 @@ class PointsBatchingSilhouetteRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uColor = program.getLocation("color"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uColor = program.getLocation("color"); this._uSectionPlanes = []; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -58818,11 +62107,11 @@ class PointsBatchingSilhouetteRenderer { this._aOffset = program.getAttribute("offset"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } @@ -58837,7 +62126,7 @@ class PointsBatchingSilhouetteRenderer { gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } @@ -58851,36 +62140,36 @@ class PointsBatchingSilhouetteRenderer { } _buildVertexShader() { - const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; const src = []; - src.push ('#version 300 es'); - src.push("// Points batching silhouette vertex shader"); + src.push("#version 300 es"); + src.push("// Triangles instancing edges vertex shader"); + src.push("uniform int renderPass;"); - + src.push("uniform vec4 color;"); src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform vec4 color;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } if (clipping) { @@ -58888,16 +62177,19 @@ class PointsBatchingSilhouetteRenderer { src.push("out vec4 vFlags2;"); } + src.push("out vec4 vColor;"); + src.push("void main(void) {"); - // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | SILHOUETTE_XRAYED - // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED + // renderPass = EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - src.push(`if (int(flags.y) != renderPass) {`); + src.push(`if (int(flags.z) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + src.push("} else {"); + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } @@ -58909,15 +62201,10 @@ class PointsBatchingSilhouetteRenderer { src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } + src.push("vColor = vec4(color.r, color.g, color.b, color.a);"); src.push("}"); src.push("}"); return src; @@ -58926,12 +62213,11 @@ class PointsBatchingSilhouetteRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; - let i; - let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points batching silhouette vertex shader"); + src.push("#version 300 es"); + src.push("// Batched geometry edges drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -58940,33 +62226,27 @@ class PointsBatchingSilhouetteRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("uniform vec4 color;"); + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); @@ -58975,9 +62255,9 @@ class PointsBatchingSilhouetteRenderer { src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push("outColor = color;"); + src.push("outColor = vColor;"); src.push("}"); return src; } @@ -58994,12 +62274,12 @@ class PointsBatchingSilhouetteRenderer { } } -const tempVec3a$k = math.vec3(); +const tempVec3a$B = math.vec3(); /** * @private */ -class PointsBatchingPickMeshRenderer { +class TrianglesInstancingEdgesColorRenderer { constructor(scene) { this._scene = scene; @@ -59012,46 +62292,40 @@ class PointsBatchingPickMeshRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash); + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + drawLayer(frameCtx, instancingLayer, renderPass) { - const model = pointsBatchingLayer.model; + const model = instancingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = pointsBatchingLayer._state; - const origin = pointsBatchingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; + const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; if (!this._program) { - this._allocate(pointsBatchingLayer); + this._allocate(instancingLayer); + if (this.errors) { + return; + } } if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + this._bindProgram(); } gl.uniform1i(this._uRenderPass, renderPass); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -59061,7 +62335,7 @@ class PointsBatchingPickMeshRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$k); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$B); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -59072,37 +62346,62 @@ class PointsBatchingPickMeshRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); + this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags.location, 1); } if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - if (this._aPickColor) { - this._aPickColor.bindArrayBuffer(state.pickColorsBuf); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + geometry.edgeIndicesBuf.bind(); - gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); + gl.drawElementsInstanced(gl.LINES, geometry.edgeIndicesBuf.numItems, geometry.edgeIndicesBuf.itemType, 0, state.numInstances); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aColor.location, 0); + + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } + + if (this._aFlags) { + gl.vertexAttribDivisor(this._aFlags.location, 0); + } + + if (this._aFlags2) { + gl.vertexAttribDivisor(this._aFlags2.location, 0); + } } _allocate() { - const scene = this._scene; const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -59114,15 +62413,14 @@ class PointsBatchingPickMeshRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -59131,24 +62429,33 @@ class PointsBatchingPickMeshRenderer { } this._aPosition = program.getAttribute("position"); + this._aColor = program.getAttribute("color"); this._aOffset = program.getAttribute("offset"); - this._aPickColor = program.getAttribute("pickColor"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram(frameCtx) { + _bindProgram() { + const scene = this._scene; const gl = scene.canvas.gl; + const project = scene.camera.project; + this._program.bind(); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if ( scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } _buildShader() { @@ -59159,38 +62466,36 @@ class PointsBatchingPickMeshRenderer { } _buildVertexShader() { - const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points batching pick mesh vertex shader"); + src.push("#version 300 es"); + src.push("// Triangles instancing edges vertex shader"); + src.push("uniform int renderPass;"); - src.push("in vec3 position;"); + src.push("in vec4 color;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - - src.push("in vec4 pickColor;"); - - src.push("uniform bool pickInvisible;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } if (clipping) { @@ -59198,41 +62503,36 @@ class PointsBatchingPickMeshRenderer { src.push("out vec4 vFlags2;"); } - src.push("out vec4 vPickColor;"); + src.push("out vec4 vColor;"); src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK + // flags.z = NOT_RENDERED | EDGES_COLOR_OPAQUE | EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED + // renderPass = EDGES_HIGHLIGHTED | EDGES_XRAYED | EDGES_SELECTED - src.push(`if (int(flags.w) != renderPass) {`); + src.push(`if (int(flags.z) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + src.push("} else {"); + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } - src.push("gl_PointSize += 10.0;"); - src.push(" }"); + // src.push("vColor = vec4(float(color.r-100.0) / 255.0, float(color.g-100.0) / 255.0, float(color.b-100.0) / 255.0, float(color.a) / 255.0);"); + src.push("vColor = vec4(float(color.r*0.5) / 255.0, float(color.g*0.5) / 255.0, float(color.b*0.5) / 255.0, float(color.a) / 255.0);"); + src.push("}"); src.push("}"); return src; } @@ -59242,8 +62542,9 @@ class PointsBatchingPickMeshRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points batching pick mesh vertex shader"); + src.push("#version 300 es"); + src.push("// Batched geometry edges drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -59252,44 +62553,38 @@ class PointsBatchingPickMeshRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vPickColor;"); + src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" outColor = vPickColor; "); + src.push("outColor = vColor;"); src.push("}"); return src; } @@ -59306,16 +62601,18 @@ class PointsBatchingPickMeshRenderer { } } -const tempVec3a$j = math.vec3(); +const tempVec3a$A = math.vec3(); /** * @private */ -class PointsBatchingPickDepthRenderer { +class TrianglesInstancingPickMeshRenderer { constructor(scene) { + this._scene = scene; this._hash = this._getHash(); + this._allocate(); } @@ -59324,51 +62621,80 @@ class PointsBatchingPickDepthRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash); + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + drawLayer(frameCtx, instancingLayer, renderPass) { - const model = pointsBatchingLayer.model; + const model = instancingLayer.model; const scene = model.scene; const camera = scene.camera; const gl = scene.canvas.gl; - const state = pointsBatchingLayer._state; - const origin = pointsBatchingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; + const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; if (!this._program) { this._allocate(); + if (this.errors) { + return; + } } if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx); } gl.uniform1i(this._uRenderPass, renderPass); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); - gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); + + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPickColor.bindArrayBuffer(state.pickColorsBuf); + gl.vertexAttribDivisor(this._aPickColor.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } + + geometry.indicesBuf.bind(); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -59378,7 +62704,7 @@ class PointsBatchingPickDepthRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$j); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$A); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -59389,37 +62715,30 @@ class PointsBatchingPickDepthRenderer { } } - //============================================================= - // TODO: Use drawElements count and offset to draw only one entity - //============================================================= - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - this._aPosition.bindArrayBuffer(state.positionsBuf); + // Cleanup - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aPickColor.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags) { - this._aFlags.bindArrayBuffer(state.flagsBuf); + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } - - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - - gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); } _allocate() { const scene = this._scene; const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -59430,7 +62749,6 @@ class PointsBatchingPickDepthRenderer { const program = this._program; - this._uRenderPass = program.getLocation("renderPass"); this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); @@ -59438,7 +62756,9 @@ class PointsBatchingPickDepthRenderer { this._uProjMatrix = program.getLocation("projMatrix"); this._uSectionPlanes = []; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -59446,23 +62766,30 @@ class PointsBatchingPickDepthRenderer { }); } + this._uRenderPass = program.getLocation("renderPass"); this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); + this._aPickColor = program.getAttribute("pickColor"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._uPickZNear = program.getLocation("pickZNear"); - this._uPickZFar = program.getLocation("pickZFar"); - - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { - this._program.bind(); + _bindProgram(frameCtx) { + + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + + program.bind(); + + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); } _buildShader() { @@ -59474,74 +62801,76 @@ class PointsBatchingPickDepthRenderer { _buildVertexShader() { const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points batched pick depth vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry picking vertex shader"); + src.push("uniform int renderPass;"); - src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); + src.push("in vec4 pickColor;"); - src.push("uniform bool pickInvisible;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vViewPosition;"); + src.push("out vec4 vPickColor;"); src.push("void main(void) {"); // flags.w = NOT_RENDERED | PICK // renderPass = PICK src.push(`if (int(flags.w) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + + + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + + src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - src.push("vViewPosition = viewPosition;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } - src.push("gl_PointSize += 10.0;"); - src.push(" }"); + src.push("}"); src.push("}"); return src; } @@ -59551,9 +62880,9 @@ class PointsBatchingPickDepthRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points batched pick depth fragment shader"); - + src.push("#version 300 es"); + src.push("// Batched geometry picking fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -59561,15 +62890,11 @@ class PointsBatchingPickDepthRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } - - src.push("uniform float pickZNear;"); - src.push("uniform float pickZFar;"); - if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); @@ -59579,40 +62904,25 @@ class PointsBatchingPickDepthRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vViewPosition;"); - src.push("vec4 packDepth(const in float depth) {"); - src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); - src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); - src.push(" vec4 res = fract(depth * bitShift);"); - src.push(" res -= res.xxyz * bitMask;"); - src.push(" return res;"); - src.push("}"); + src.push("in vec4 vPickColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); - for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); + src.push(" float dist = 0.0;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); - src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth + src.push("outColor = vPickColor; "); src.push("}"); return src; } @@ -59629,12 +62939,12 @@ class PointsBatchingPickDepthRenderer { } } -const tempVec3a$i = math.vec3(); +const tempVec3a$z = math.vec3(); /** * @private */ -class PointsBatchingOcclusionRenderer { +class TrianglesInstancingPickDepthRenderer { constructor(scene) { this._scene = scene; @@ -59647,21 +62957,20 @@ class PointsBatchingOcclusionRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash); + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + drawLayer(frameCtx, instancingLayer, renderPass) { - const model = pointsBatchingLayer.model; + const model = instancingLayer.model; const scene = model.scene; const gl = scene.canvas.gl; - const state = pointsBatchingLayer._state; - const camera = scene.camera; - const origin = pointsBatchingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; + const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; if (!this._program) { - this._allocate(pointsBatchingLayer); + this._allocate(instancingLayer); if (this.errors) { return; } @@ -59672,15 +62981,32 @@ class PointsBatchingOcclusionRenderer { this._bindProgram(); } + const camera = scene.camera; + gl.uniform1i(this._uRenderPass, renderPass); - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + + gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + + gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); + gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; - const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; @@ -59690,7 +63016,7 @@ class PointsBatchingOcclusionRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$i); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$z); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -59701,25 +63027,49 @@ class PointsBatchingOcclusionRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(state.positionsBuf); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } if (this._aOffset) { this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - this._aFlags.bindArrayBuffer(state.flagsBuf); + geometry.indicesBuf.bind(); + + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + + // Cleanup + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); if (this._aFlags2) { // Won't be in shader when not clipping - this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - - gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } } _allocate() { @@ -59737,6 +63087,7 @@ class PointsBatchingOcclusionRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); @@ -59755,9 +63106,12 @@ class PointsBatchingOcclusionRenderer { this._aOffset = program.getAttribute("offset"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + this._uPickZNear = program.getLocation("pickZNear"); + this._uPickZFar = program.getLocation("pickZFar"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); @@ -59765,19 +63119,8 @@ class PointsBatchingOcclusionRenderer { } _bindProgram() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; - this._program.bind(); - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } } _buildShader() { @@ -59789,70 +63132,76 @@ class PointsBatchingOcclusionRenderer { _buildVertexShader() { const scene = this._scene; - const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points batching occlusion vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry depth vertex shader"); + + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } + src.push("in vec4 flags;"); src.push("in vec4 flags2;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } + + src.push("out vec4 vViewPosition;"); src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE - // Only opaque objects can be occluders + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK - src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - src.push(" } else {"); - src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } + src.push(" vViewPosition = viewPosition;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - } - src.push(" gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } - src.push(" }"); + src.push("gl_Position = clipPos;"); + src.push("}"); src.push("}"); return src; } @@ -59862,7 +63211,10 @@ class PointsBatchingOcclusionRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push("// Points batching occlusion fragment shader"); + src.push("#version 300 es"); + src.push("// Batched geometry depth fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -59870,10 +63222,16 @@ class PointsBatchingOcclusionRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + + src.push("uniform float pickZNear;"); + src.push("uniform float pickZFar;"); + if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); @@ -59883,31 +63241,33 @@ class PointsBatchingOcclusionRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } + src.push("in vec4 vViewPosition;"); + src.push("vec4 packDepth(const in float depth) {"); + src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); + src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); + src.push(" vec4 res = fract(depth * bitShift);"); + src.push(" res -= res.xxyz * bitMask;"); + src.push(" return res;"); + src.push("}"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); - src.push(" float dist = 0.0;"); + src.push(" float dist = 0.0;"); for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { - src.push(" if (sectionPlaneActive" + i + ") {"); - src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); - src.push(" }"); + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } - src.push(" if (dist > 0.0) { discard; }"); - src.push(" }"); + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue + src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); + src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth src.push("}"); return src; } @@ -59924,936 +63284,366 @@ class PointsBatchingOcclusionRenderer { } } +const tempVec3a$y = math.vec3(); + /** * @private */ -class PointsBatchingRenderers { +class TrianglesInstancingPickNormalsRenderer { constructor(scene) { this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - _compile() { - if (this._colorRenderer && (!this._colorRenderer.getValid())) { - this._colorRenderer.destroy(); - this._colorRenderer = null; - } - if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { - this._silhouetteRenderer.destroy(); - this._silhouetteRenderer = null; - } - if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { - this._pickMeshRenderer.destroy(); - this._pickMeshRenderer = null; - } - if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { - this._pickDepthRenderer.destroy(); - this._pickDepthRenderer = null; - } - if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { - this._occlusionRenderer.destroy(); - this._occlusionRenderer = null; - } - } + getValid() { + return this._hash === this._getHash(); + }; - get colorRenderer() { - if (!this._colorRenderer) { - this._colorRenderer = new PointsBatchingColorRenderer(this._scene); - } - return this._colorRenderer; + _getHash() { + return this._scene._sectionPlanesState.getHash(); } - get silhouetteRenderer() { - if (!this._silhouetteRenderer) { - this._silhouetteRenderer = new PointsBatchingSilhouetteRenderer(this._scene); - } - return this._silhouetteRenderer; - } + drawLayer(frameCtx, instancingLayer, renderPass) { - get pickMeshRenderer() { - if (!this._pickMeshRenderer) { - this._pickMeshRenderer = new PointsBatchingPickMeshRenderer(this._scene); - } - return this._pickMeshRenderer; - } + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; - get pickDepthRenderer() { - if (!this._pickDepthRenderer) { - this._pickDepthRenderer = new PointsBatchingPickDepthRenderer(this._scene); + if (!this._program) { + this._allocate(instancingLayer); + if (this.errors) { + return; + } } - return this._pickDepthRenderer; - } - get occlusionRenderer() { - if (!this._occlusionRenderer) { - this._occlusionRenderer = new PointsBatchingOcclusionRenderer(this._scene); + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); } - return this._occlusionRenderer; - } - _destroy() { - if (this._colorRenderer) { - this._colorRenderer.destroy(); - } - if (this._silhouetteRenderer) { - this._silhouetteRenderer.destroy(); - } - if (this._pickMeshRenderer) { - this._pickMeshRenderer.destroy(); - } - if (this._pickDepthRenderer) { - this._pickDepthRenderer.destroy(); - } - if (this._occlusionRenderer) { - this._occlusionRenderer.destroy(); - } - } -} + // In practice, these binds will only happen once per frame + // because we pick normals on a single previously-picked mesh -const cachedRenderers$1 = {}; + gl.uniform1i(this._uRenderPass, renderPass); -/** - * @private - */ -function getPointsBatchingRenderers(scene) { - const sceneId = scene.id; - let renderers = cachedRenderers$1[sceneId]; - if (!renderers) { - renderers = new PointsBatchingRenderers(scene); - cachedRenderers$1[sceneId] = renderers; - renderers._compile(); - scene.on("compile", () => { - renderers._compile(); - }); - scene.on("destroyed", () => { - delete cachedRenderers$1[sceneId]; - renderers._destroy(); - }); - } - return renderers; -} + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); -/** - * @private - */ -class PointsBatchingBuffer { - - constructor(maxGeometryBatchSize = 5000000) { - - if (maxGeometryBatchSize > 5000000) { - maxGeometryBatchSize = 5000000; - } - - this.maxVerts = maxGeometryBatchSize; - this.maxIndices = maxGeometryBatchSize * 3; // Rough rule-of-thumb - this.positions = []; - this.colors = []; - this.intensities = []; - this.pickColors = []; - this.flags = []; - this.flags2 = []; - this.offsets = []; - } -} - -const tempVec3a$h = math.vec4(); -const tempVec3b$6 = math.vec4(); -const tempVec4a$6 = math.vec4([0, 0, 0, 1]); -const tempVec4b$6 = math.vec4([0, 0, 0, 1]); -const tempVec4c$3 = math.vec4([0, 0, 0, 1]); -const tempOBB3 = math.OBB3(); - -/** - * @private - */ -class PointsBatchingLayer { - - /** - * @param model - * @param cfg - * @param cfg.layerIndex - * @param cfg.positionsDecodeMatrix - * @param cfg.maxGeometryBatchSize - * @param cfg.origin - * @param cfg.scratchMemory - */ - constructor(cfg) { - - /** - * Owner model - * @type {VBOSceneModel} - */ - this.model = cfg.model; - - /** - * State sorting key. - * @type {string} - */ - this.sortId = "PointsBatchingLayer"; - - /** - * Index of this PointsBatchingLayer in {@link VBOSceneModel#_layerList}. - * @type {Number} - */ - this.layerIndex = cfg.layerIndex; - - this._pointsBatchingRenderers = getPointsBatchingRenderers(cfg.model.scene); - - this._buffer = new PointsBatchingBuffer(cfg.maxGeometryBatchSize); - this._scratchMemory = cfg.scratchMemory; - - this._state = new RenderState({ - positionsBuf: null, - offsetsBuf: null, - colorsBuf: null, - flagsBuf: null, - flags2Buf: null, - positionsDecodeMatrix: math.mat4(), - origin: null - }); - - // These counts are used to avoid unnecessary render passes - this._numPortions = 0; - this._numVisibleLayerPortions = 0; - this._numTransparentLayerPortions = 0; - this._numXRayedLayerPortions = 0; - this._numSelectedLayerPortions = 0; - this._numHighlightedLayerPortions = 0; - this._numClippableLayerPortions = 0; - this._numPickableLayerPortions = 0; - this._numCulledLayerPortions = 0; - - this._modelAABB = math.collapseAABB3(); // Model-space AABB - this._portions = []; - - this._finalized = false; - - if (cfg.positionsDecodeMatrix) { - this._state.positionsDecodeMatrix.set(cfg.positionsDecodeMatrix); - this._preCompressedPositionsExpected = true; - } else { - this._preCompressedPositionsExpected = false; - } - - if (cfg.origin) { - this._state.origin = math.vec3(cfg.origin); - } - - /** - * The axis-aligned World-space boundary of this PointsBatchingLayer's positions. - * @type {*|Float64Array} - */ - this.aabb = math.collapseAABB3(); - } + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - /** - * Tests if there is room for another portion in this PointsBatchingLayer. - * - * @param lenPositions Number of positions we'd like to create in the portion. - * @returns {boolean} True if OK to create another portion. - */ - canCreatePortion(lenPositions) { - if (this._finalized) { - throw "Already finalized"; - } - return ((this._buffer.positions.length + lenPositions) < (this._buffer.maxVerts * 3)); - } + gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - /** - * Creates a new portion within this PointsBatchingLayer, returns the new portion ID. - * - * Gives the portion the specified geometry, color and matrix. - * - * @param cfg.positions Flat float Local-space positions array. - * @param cfg.positionsCompressed Flat quantized positions array - decompressed with PointsBatchingLayer positionsDecodeMatrix - * @param [cfg.colorsCompressed] Quantized RGB colors [0..255,0..255,0..255,0..255] - * @param [cfg.colors] Flat float colors array. - * @param cfg.color Float RGB color [0..1,0..1,0..1] - * @param [cfg.meshMatrix] Flat float 4x4 matrix - * @param [cfg.worldMatrix] Flat float 4x4 matrix - * @param cfg.worldAABB Flat float AABB World-space AABB - * @param cfg.pickColor Quantized pick color - * @returns {number} Portion ID - */ - createPortion(cfg) { + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); - if (this._finalized) { - throw "Already finalized"; + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - const positions = cfg.positions; - const positionsCompressed = cfg.positionsCompressed; - const color = cfg.color; - const colorsCompressed = cfg.colorsCompressed; - const colors = cfg.colors; - const meshMatrix = cfg.meshMatrix; - const worldMatrix = cfg.worldMatrix; - const worldAABB = cfg.worldAABB; - const pickColor = cfg.pickColor; - - const buffer = this._buffer; - const positionsIndex = buffer.positions.length; - const vertsIndex = positionsIndex / 3; - - let numVerts; - - if (this._preCompressedPositionsExpected) { - - if (!positionsCompressed) { - throw "positionsCompressed expected"; - } - - for (let i = 0, len = positionsCompressed.length; i < len; i++) { - buffer.positions.push(positionsCompressed[i]); - } - - const bounds = geometryCompressionUtils.getPositionsBounds(positionsCompressed); - - const min = geometryCompressionUtils.decompressPosition(bounds.min, this._state.positionsDecodeMatrix, tempVec3a$h); - const max = geometryCompressionUtils.decompressPosition(bounds.max, this._state.positionsDecodeMatrix, tempVec3b$6); - - worldAABB[0] = min[0]; - worldAABB[1] = min[1]; - worldAABB[2] = min[2]; - worldAABB[3] = max[0]; - worldAABB[4] = max[1]; - worldAABB[5] = max[2]; - - if (worldMatrix) { - math.AABB3ToOBB3(worldAABB, tempOBB3); - math.transformOBB3(worldMatrix, tempOBB3); - math.OBB3ToAABB3(tempOBB3, worldAABB); - } - - numVerts = positionsCompressed.length / 3; - - } else { - - if (!positions) { - throw "positions expected"; - } - - numVerts = positions.length / 3; - - const lenPositions = positions.length; - const positionsBase = buffer.positions.length; - - for (let i = 0, len = positions.length; i < len; i++) { - buffer.positions.push(positions[i]); - } - - if (meshMatrix) { - - for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { - - tempVec4a$6[0] = buffer.positions[i + 0]; - tempVec4a$6[1] = buffer.positions[i + 1]; - tempVec4a$6[2] = buffer.positions[i + 2]; - - math.transformPoint4(meshMatrix, tempVec4a$6, tempVec4b$6); - - buffer.positions[i + 0] = tempVec4b$6[0]; - buffer.positions[i + 1] = tempVec4b$6[1]; - buffer.positions[i + 2] = tempVec4b$6[2]; - - math.expandAABB3Point3(this._modelAABB, tempVec4b$6); - - if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4b$6, tempVec4c$3); - math.expandAABB3Point3(worldAABB, tempVec4c$3); - } else { - math.expandAABB3Point3(worldAABB, tempVec4b$6); - } - } - - } else { - - for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { - - tempVec4a$6[0] = buffer.positions[i + 0]; - tempVec4a$6[1] = buffer.positions[i + 1]; - tempVec4a$6[2] = buffer.positions[i + 2]; - - math.expandAABB3Point3(this._modelAABB, tempVec4a$6); - - if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4a$6, tempVec4b$6); - math.expandAABB3Point3(worldAABB, tempVec4b$6); - } else { - math.expandAABB3Point3(worldAABB, tempVec4a$6); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$y); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } } - - - } - - if (this._state.origin) { - const origin = this._state.origin; - worldAABB[0] += origin[0]; - worldAABB[1] += origin[1]; - worldAABB[2] += origin[2]; - worldAABB[3] += origin[0]; - worldAABB[4] += origin[1]; - worldAABB[5] += origin[2]; - } - - math.expandAABB3(this.aabb, worldAABB); - - if (colorsCompressed) { - for (let i = 0, len = colorsCompressed.length; i < len; i++) { - buffer.colors.push(colorsCompressed[i]); - } - - } else if (colors) { - for (let i = 0, len = colors.length; i < len; i++) { - buffer.colors.push(colors[i] * 255); - } - - } else if (color) { - - const r = color[0]; // Color is pre-quantized by VBOSceneModel - const g = color[1]; - const b = color[2]; - const a = 1.0; - - for (let i = 0; i < numVerts; i++) { - buffer.colors.push(r); - buffer.colors.push(g); - buffer.colors.push(b); - buffer.colors.push(a); - } - } - - { - const pickColorsBase = buffer.pickColors.length; - const lenPickColors = numVerts * 4; - for (let i = pickColorsBase, len = pickColorsBase + lenPickColors; i < len; i += 4) { - buffer.pickColors.push(pickColor[0]); - buffer.pickColors.push(pickColor[1]); - buffer.pickColors.push(pickColor[2]); - buffer.pickColors.push(pickColor[3]); - } - } - - if (this.model.scene.entityOffsetsEnabled) { - for (let i = 0; i < numVerts; i++) { - buffer.offsets.push(0); - buffer.offsets.push(0); - buffer.offsets.push(0); - } } - const portionId = this._portions.length / 2; - - this._portions.push(vertsIndex); - this._portions.push(numVerts); - - this._numPortions++; - this.model.numPortions++; - - return portionId; - } - - /** - * Builds batch VBOs from appended geometries. - * No more portions can then be created. - */ - finalize() { - - if (this._finalized) { - this.model.error("Already finalized"); - return; - } - - const state = this._state; - const gl = this.model.scene.canvas.gl; - const buffer = this._buffer; - - if (buffer.positions.length > 0) { - if (this._preCompressedPositionsExpected) { - const positions = new Uint16Array(buffer.positions); - state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, positions, buffer.positions.length, 3, gl.STATIC_DRAW); - } else { - const positions = new Float32Array(buffer.positions); - const quantizedPositions = quantizePositions(positions, this._modelAABB, state.positionsDecodeMatrix); - state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, buffer.positions.length, 3, gl.STATIC_DRAW); - } - } - - if (buffer.colors.length > 0) { - const colors = new Uint8Array(buffer.colors); - let normalized = false; - state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, buffer.colors.length, 4, gl.STATIC_DRAW, normalized); - } - - if (buffer.positions.length > 0) { // Because we build flags arrays here, get their length from the positions array - const flagsLength = (buffer.positions.length / 3) * 4; - const flags = new Uint8Array(flagsLength); - const flags2 = new Uint8Array(flagsLength); - let notNormalized = false; - let normalized = true; - state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags, flags.length, 4, gl.DYNAMIC_DRAW, notNormalized); - state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags2, flags2.length, 4, gl.DYNAMIC_DRAW, normalized); - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - if (buffer.pickColors.length > 0) { - const pickColors = new Uint8Array(buffer.pickColors); - let normalized = false; - state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, pickColors, buffer.pickColors.length, 4, gl.STATIC_DRAW, normalized); - } + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - if (this.model.scene.entityOffsetsEnabled) { - if (buffer.offsets.length > 0) { - const offsets = new Float32Array(buffer.offsets); - state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, offsets, buffer.offsets.length, 3, gl.DYNAMIC_DRAW); - } - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - this._buffer = null; - this._finalized = true; - } + this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); + this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); + this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); - initFlags(portionId, flags, meshTransparent) { - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } - if (meshTransparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } - this._setFlags(portionId, flags, meshTransparent); - this._setFlags2(portionId, flags); - } + gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); - setVisible(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.VISIBLE) { - this._numVisibleLayerPortions++; - this.model.numVisibleLayerPortions++; - } else { - this._numVisibleLayerPortions--; - this.model.numVisibleLayerPortions--; - } - this._setFlags(portionId, flags, transparent); - } + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + this._aNormal.bindArrayBuffer(geometry.normalsBuf); - setHighlighted(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.HIGHLIGHTED) { - this._numHighlightedLayerPortions++; - this.model.numHighlightedLayerPortions++; - } else { - this._numHighlightedLayerPortions--; - this.model.numHighlightedLayerPortions--; - } - this._setFlags(portionId, flags, transparent); - } + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); - setXRayed(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.XRAYED) { - this._numXRayedLayerPortions++; - this.model.numXRayedLayerPortions++; - } else { - this._numXRayedLayerPortions--; - this.model.numXRayedLayerPortions--; + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - this._setFlags(portionId, flags, transparent); - } - setSelected(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.SELECTED) { - this._numSelectedLayerPortions++; - this.model.numSelectedLayerPortions++; - } else { - this._numSelectedLayerPortions--; - this.model.numSelectedLayerPortions--; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - this._setFlags(portionId, flags, transparent); - } - setEdges(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - // Not applicable to point clouds - } + geometry.indicesBuf.bind(); - setClippable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CLIPPABLE) { - this._numClippableLayerPortions++; - this.model.numClippableLayerPortions++; - } else { - this._numClippableLayerPortions--; - this.model.numClippableLayerPortions--; - } - this._setFlags2(portionId, flags); - } + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - setCulled(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.CULLED) { - this._numCulledLayerPortions++; - this.model.numCulledLayerPortions++; - } else { - this._numCulledLayerPortions--; - this.model.numCulledLayerPortions--; - } - this._setFlags(portionId, flags, transparent); - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); - setCollidable(portionId, flags) { - if (!this._finalized) { - throw "Not finalized"; + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - } - setPickable(portionId, flags, transparent) { - if (!this._finalized) { - throw "Not finalized"; - } - if (flags & ENTITY_FLAGS.PICKABLE) { - this._numPickableLayerPortions++; - this.model.numPickableLayerPortions++; - } else { - this._numPickableLayerPortions--; - this.model.numPickableLayerPortions--; + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } - this._setFlags(portionId, flags, transparent); } - setColor(portionId, color) { - if (!this._finalized) { - throw "Not finalized"; - } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstColor = vertexBase * 4; - const lenColor = numVerts * 4; - const tempArray = this._scratchMemory.getUInt8Array(lenColor); - const r = color[0]; - const g = color[1]; - const b = color[2]; - for (let i = 0; i < lenColor; i += 4) { - tempArray[i + 0] = r; - tempArray[i + 1] = g; - tempArray[i + 2] = b; - } - this._state.colorsBuf.setData(tempArray, firstColor, lenColor); - } + _allocate() { - setTransparent(portionId, flags, transparent) { - if (transparent) { - this._numTransparentLayerPortions++; - this.model.numTransparentLayerPortions++; - } else { - this._numTransparentLayerPortions--; - this.model.numTransparentLayerPortions--; - } - this._setFlags(portionId, flags, transparent); - } + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; - _setFlags(portionId, flags, transparent) { + this._program = new Program(gl, this._buildShader()); - if (!this._finalized) { - throw "Not finalized"; + if (this._program.errors) { + this.errors = this._program.errors; + return; } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstFlag = vertexBase * 4; - const lenFlags = numVerts * 4; - const tempArray = this._scratchMemory.getUInt8Array(lenFlags); - - const visible = !!(flags & ENTITY_FLAGS.VISIBLE); - const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); - const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); - const selected = !!(flags & ENTITY_FLAGS.SELECTED); - const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); - const culled = !!(flags & ENTITY_FLAGS.CULLED); + const program = this._program; - // Normal fill + this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - let f0; - if (!visible || culled || xrayed - || (highlighted && !this.model.scene.highlightMaterial.glowThrough) - || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { - f0 = RENDER_PASSES.NOT_RENDERED; - } else { - if (transparent) { - f0 = RENDER_PASSES.COLOR_TRANSPARENT; - } else { - f0 = RENDER_PASSES.COLOR_OPAQUE; - } + this._uSectionPlanes = []; + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - // Emphasis fill - - let f1; - if (!visible || culled) { - f1 = RENDER_PASSES.NOT_RENDERED; - } else if (selected) { - f1 = RENDER_PASSES.SILHOUETTE_SELECTED; - } else if (highlighted) { - f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; - } else if (xrayed) { - f1 = RENDER_PASSES.SILHOUETTE_XRAYED; - } else { - f1 = RENDER_PASSES.NOT_RENDERED; - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aNormal = program.getAttribute("normal"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - // Pick + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; + this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); + this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); + this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); - for (let i = 0; i < lenFlags; i += 4) { - tempArray[i + 0] = f0; // x - normal fill - tempArray[i + 1] = f1; // y - emphasis fill - tempArray[i + 2] = 0; // z - edges - don't care - tempArray[i + 3] = f3; // w - pick + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } - - this._state.flagsBuf.setData(tempArray, firstFlag, lenFlags); } - _setFlags2(portionId, flags) { - - if (!this._finalized) { - throw "Not finalized"; - } - - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstFlag = vertexBase * 4; - const lenFlags = numVerts * 4; - const tempArray = this._scratchMemory.getUInt8Array(lenFlags); - - const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; - - for (let i = 0; i < lenFlags; i += 4) { - tempArray[i + 0] = clippable; - } - - this._state.flags2Buf.setData(tempArray, firstFlag, lenFlags); + _bindProgram() { + this._program.bind(); } - setOffset(portionId, offset) { - if (!this._finalized) { - throw "Not finalized"; - } - if (!this.model.scene.entityOffsetsEnabled) { - this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled - return; - } - const portionsIdx = portionId * 2; - const vertexBase = this._portions[portionsIdx]; - const numVerts = this._portions[portionsIdx + 1]; - const firstOffset = vertexBase * 3; - const lenOffsets = numVerts * 3; - const tempArray = this._scratchMemory.getFloat32Array(lenOffsets); - const x = offset[0]; - const y = offset[1]; - const z = offset[2]; - for (let i = 0; i < lenOffsets; i += 3) { - tempArray[i + 0] = x; - tempArray[i + 1] = y; - tempArray[i + 2] = z; - } - this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets); + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - //-- NORMAL RENDERING ---------------------------------------------------------------------------------------------- - - drawColorOpaque(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { - return; - } - if (this._pointsBatchingRenderers.colorRenderer) { - this._pointsBatchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push("#version 300 es"); + src.push("// Instancing geometry normals vertex shader"); + + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - } - - drawColorTransparent(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { - return; + src.push("in vec2 normal;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + src.push("in vec4 modelNormalMatrixCol0;"); + src.push("in vec4 modelNormalMatrixCol1;"); + src.push("in vec4 modelNormalMatrixCol2;"); + src.push("uniform bool pickInvisible;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } - if (this._pointsBatchingRenderers.colorRenderer) { - this._pointsBatchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + src.push("vec3 octDecode(vec2 oct) {"); + src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); + src.push(" if (v.z < 0.0) {"); + src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); + src.push(" }"); + src.push(" return normalize(v);"); + src.push("}"); + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - } - - // -- RENDERING SAO POST EFFECT TARGETS ---------------------------------------------------------------------------- - - drawDepth(renderFlags, frameCtx) { - } - - drawNormals(renderFlags, frameCtx) { - } + src.push("out vec3 vWorldNormal;"); + src.push("void main(void) {"); - // -- EMPHASIS RENDERING ------------------------------------------------------------------------------------------- + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK - drawSilhouetteXRayed(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { - return; - } - if (this._pointsBatchingRenderers.silhouetteRenderer) { - this._pointsBatchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); - } - } + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - drawSilhouetteHighlighted(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { - return; - } - if (this._pointsBatchingRenderers.silhouetteRenderer) { - this._pointsBatchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); + src.push("} else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - } - - drawSilhouetteSelected(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { - return; + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); + src.push(" vec3 worldNormal = vec3(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2));"); + src.push(" vWorldNormal = worldNormal;"); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); } - if (this._pointsBatchingRenderers.silhouetteRenderer) { - this._pointsBatchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } + src.push("gl_Position = clipPos;"); + src.push("}"); + src.push("}"); + return src; } - //-- EDGES RENDERING ----------------------------------------------------------------------------------------------- - - drawEdgesColorOpaque(renderFlags, frameCtx) { - } - - drawEdgesColorTransparent(renderFlags, frameCtx) { - } - - drawEdgesHighlighted(renderFlags, frameCtx) { - } - - drawEdgesSelected(renderFlags, frameCtx) { - } + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push("#version 300 es"); + src.push("// Batched geometry normals fragment shader"); - drawEdgesXRayed(renderFlags, frameCtx) { - } + - //---- PICKING ---------------------------------------------------------------------------------------------------- + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); - drawPickMesh(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - if (this._pointsBatchingRenderers.pickMeshRenderer) { - this._pointsBatchingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - } - drawPickDepths(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; - } - if (this._pointsBatchingRenderers.pickDepthRenderer) { - this._pointsBatchingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } } - } - - drawPickNormals(renderFlags, frameCtx) { - } - - //---- OCCLUSION TESTING ------------------------------------------------------------------------------------------- - - drawOcclusion(renderFlags, frameCtx) { - if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { - return; + src.push("in vec3 vWorldNormal;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); } - if (this._pointsBatchingRenderers.occlusionRenderer) { - this._pointsBatchingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push(" outColor = vec4((vWorldNormal * 0.5) + 0.5, 1.0);"); + src.push("}"); + return src; } - //---- SHADOWS ----------------------------------------------------------------------------------------------------- - - drawShadow(renderFlags, frameCtx) { + webglContextRestored() { + this._program = null; } destroy() { - const state = this._state; - if (state.positionsBuf) { - state.positionsBuf.destroy(); - state.positionsBuf = null; - } - if (state.offsetsBuf) { - state.offsetsBuf.destroy(); - state.offsetsBuf = null; - } - if (state.colorsBuf) { - state.colorsBuf.destroy(); - state.colorsBuf = null; - } - if (state.flagsBuf) { - state.flagsBuf.destroy(); - state.flagsBuf = null; - } - if (state.flags2Buf) { - state.flags2Buf.destroy(); - state.flags2Buf = null; - } - if (state.pickColorsBuf) { - state.pickColorsBuf.destroy(); - state.pickColorsBuf = null; + if (this._program) { + this._program.destroy(); } - state.destroy(); + this._program = null; } } -const tempVec3a$g = math.vec3(); +const tempVec3a$x = math.vec3(); /** * @private */ -class PointsInstancingColorRenderer { +class TrianglesInstancingOcclusionRenderer { constructor(scene) { this._scene = scene; @@ -60863,10 +63653,10 @@ class PointsInstancingColorRenderer { getValid() { return this._hash === this._getHash(); - } + }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } drawLayer(frameCtx, instancingLayer, renderPass) { @@ -60876,9 +63666,8 @@ class PointsInstancingColorRenderer { const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; const origin = instancingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; - const geometry = instancingLayer.geometry; if (!this._program) { this._allocate(); @@ -60897,13 +63686,6 @@ class PointsInstancingColorRenderer { gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aColor.bindArrayBuffer(geometry.colorsBuf); - - if (pointsMaterial.filterIntensity) { - gl.uniform2f(this._uIntensityRange, pointsMaterial.minIntensity, pointsMaterial.maxIntensity); - } - const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; @@ -60917,7 +63699,7 @@ class PointsInstancingColorRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$g); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$x); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -60938,6 +63720,18 @@ class PointsInstancingColorRenderer { gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); + } + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } + this._aFlags.bindArrayBuffer(state.flagsBuf); gl.vertexAttribDivisor(this._aFlags.location, 1); @@ -60946,29 +63740,22 @@ class PointsInstancingColorRenderer { gl.vertexAttribDivisor(this._aFlags2.location, 1); } - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + geometry.indicesBuf.bind(); - gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - frameCtx.drawArrays++; + // Cleanup gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - + if (this._aColor) { + gl.vertexAttribDivisor(this._aColor.location, 0); + } gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags2) { // Won't be in shader when not clipping gl.vertexAttribDivisor(this._aFlags2.location, 0); } - if (this._aOffset) { gl.vertexAttribDivisor(this._aOffset.location, 0); } @@ -60977,8 +63764,8 @@ class PointsInstancingColorRenderer { _allocate() { const scene = this._scene; - const pointsMaterial = scene.pointsMaterial._state; const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -60990,16 +63777,14 @@ class PointsInstancingColorRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uSectionPlanes = []; - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -61008,28 +63793,19 @@ class PointsInstancingColorRenderer { } this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); - this._aOffset = program.getAttribute("offset"); this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uOcclusionTexture = "uOcclusionTexture"; - - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if (pointsMaterial.filterIntensity) { - this._uIntensityRange = program.getLocation("intensityRange"); - } - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } - } + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } + } _bindProgram() { @@ -61058,101 +63834,62 @@ class PointsInstancingColorRenderer { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; const src = []; - src.push('#version 300 es'); - src.push("// Points instancing color vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing occlusion vertex shader"); src.push("uniform int renderPass;"); - src.push("in vec3 position;"); - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); src.push("in vec4 modelMatrixCol0;"); // Modeling matrix src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); - src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - - if (pointsMaterial.filterIntensity) { - src.push("uniform vec2 intensityRange;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); + src.push("in float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("in float isPerspective;"); } - if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vColor;"); - src.push("void main(void) {"); // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); src.push("} else {"); - - if (pointsMaterial.filterIntensity) { - src.push("float intensity = float(color.a) / 255.0;"); - src.push("if (intensity < intensityRange[0] || intensity > intensityRange[1]) {"); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); - } - - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - - src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, 1.0);"); - + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); + src.push(" vWorldPosition = worldPosition;"); } - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } - src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } src.push("}"); - if (pointsMaterial.filterIntensity) { - src.push("}"); - } src.push("}"); return src; } @@ -61162,8 +63899,8 @@ class PointsInstancingColorRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Points instancing color fragment shader"); + src.push("#version 300 es"); + src.push("// Instancing occlusion fragment shader"); src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); @@ -61173,33 +63910,26 @@ class PointsInstancingColorRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("out float isPerspective;"); src.push("uniform float logDepthBufFC;"); - src.push("in float vFragDepth;"); + src.push("out float vFragDepth;"); } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vColor;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); @@ -61207,9 +63937,9 @@ class PointsInstancingColorRenderer { src.push("if (dist > 0.0) { discard; }"); src.push("}"); } - src.push(" outColor = vColor;"); + src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } src.push("}"); return src; @@ -61227,12 +63957,12 @@ class PointsInstancingColorRenderer { } } -const tempVec3a$f = math.vec3(); +const tempVec3a$w = math.vec3(); /** * @private */ -class PointsInstancingSilhouetteRenderer { +class TrianglesInstancingDepthRenderer { constructor(scene) { this._scene = scene; @@ -61245,7 +63975,7 @@ class PointsInstancingSilhouetteRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } drawLayer(frameCtx, instancingLayer, renderPass) { @@ -61255,12 +63985,11 @@ class PointsInstancingSilhouetteRenderer { const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; const origin = instancingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; - const geometry = instancingLayer.geometry; if (!this._program) { - this._allocate(instancingLayer.model.scene); + this._allocate(); if (this.errors) { return; } @@ -61273,30 +64002,8 @@ class PointsInstancingSilhouetteRenderer { gl.uniform1i(this._uRenderPass, renderPass); - if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { - const material = scene.xrayMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { - const material = scene.highlightMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { - const material = scene.selectedMaterial._state; - const fillColor = material.fillColor; - const fillAlpha = material.fillAlpha; - gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - - } else { - gl.uniform4fv(this._uColor, math.vec3([1, 1, 1])); - } - - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { @@ -61311,7 +64018,7 @@ class PointsInstancingSilhouetteRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$f); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$w); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -61322,8 +64029,6 @@ class PointsInstancingSilhouetteRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); @@ -61332,35 +64037,36 @@ class PointsInstancingSilhouetteRenderer { gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } + + this._aFlags.bindArrayBuffer(state.flagsBuf); gl.vertexAttribDivisor(this._aFlags.location, 1); if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + this._aFlags2.bindArrayBuffer(state.flags2Buf); gl.vertexAttribDivisor(this._aFlags2.location, 1); } - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + geometry.indicesBuf.bind(); - gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aFlags.location, 0); - if (this._aFlags2) { + + if (this._aFlags2) { // Won't be in shader when not clipping gl.vertexAttribDivisor(this._aFlags2.location, 0); } + if (this._aOffset) { gl.vertexAttribDivisor(this._aOffset.location, 0); } @@ -61370,7 +64076,6 @@ class PointsInstancingSilhouetteRenderer { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -61382,15 +64087,15 @@ class PointsInstancingSilhouetteRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); - this._uColor = program.getLocation("color"); + this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -61406,10 +64111,7 @@ class PointsInstancingSilhouetteRenderer { this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if ( scene.logarithmicDepthBufferEnabled) { + if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } @@ -61424,7 +64126,7 @@ class PointsInstancingSilhouetteRenderer { gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - if ( scene.logarithmicDepthBufferEnabled) { + if (scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } @@ -61438,66 +64140,55 @@ class PointsInstancingSilhouetteRenderer { } _buildVertexShader() { - const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; const src = []; - src.push ('#version 300 es'); - src.push("// Points instancing silhouette vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry depth drawing vertex shader"); src.push("uniform int renderPass;"); - src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol0;"); src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); - src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } - - src.push("uniform vec4 color;"); - if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - + src.push("out vec2 vHighPrecisionZW;"); src.push("void main(void) {"); - // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - src.push(`if (int(flags.y) != renderPass) {`); + src.push(`if (int(flags.x) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - - src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); if (clipping) { src.push("vWorldPosition = worldPosition;"); @@ -61505,16 +64196,11 @@ class PointsInstancingSilhouetteRenderer { } src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } + src.push("vHighPrecisionZW = gl_Position.zw;"); src.push("}"); src.push("}"); return src; @@ -61523,45 +64209,37 @@ class PointsInstancingSilhouetteRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; + let i; + let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points instancing silhouette fragment shader"); - src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("#version 300 es"); + src.push("// Instancing geometry depth drawing fragment shader"); + src.push("precision highp float;"); src.push("precision highp int;"); - src.push("#else"); - src.push("precision mediump float;"); - src.push("precision mediump int;"); - src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("uniform vec4 color;"); + src.push("in vec2 vHighPrecisionZW;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); @@ -61570,9 +64248,10 @@ class PointsInstancingSilhouetteRenderer { src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push("outColor = color;"); + src.push("float fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;"); + src.push(" outColor = vec4(vec3(1.0 - fragCoordZ), 1.0); "); src.push("}"); return src; } @@ -61589,18 +64268,16 @@ class PointsInstancingSilhouetteRenderer { } } -const tempVec3a$e = math.vec3(); +const tempVec3a$v = math.vec3(); /** * @private */ -class PointsInstancingPickMeshRenderer { +class TrianglesInstancingNormalsRenderer { constructor(scene) { - this._scene = scene; this._hash = this._getHash(); - this._allocate(); } @@ -61609,7 +64286,7 @@ class PointsInstancingPickMeshRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } drawLayer(frameCtx, instancingLayer, renderPass) { @@ -61619,12 +64296,11 @@ class PointsInstancingPickMeshRenderer { const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; const origin = instancingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; - const geometry = instancingLayer.geometry; if (!this._program) { - this._allocate(); + this._allocate(instancingLayer); if (this.errors) { return; } @@ -61632,55 +64308,16 @@ class PointsInstancingPickMeshRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx); + this._bindProgram(); } gl.uniform1i(this._uRenderPass, renderPass); - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aPickColor.bindArrayBuffer(state.pickColorsBuf); - gl.vertexAttribDivisor(this._aPickColor.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { @@ -61695,7 +64332,7 @@ class PointsInstancingPickMeshRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$e); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$v); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -61706,14 +64343,43 @@ class PointsInstancingPickMeshRenderer { } } - gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - // Cleanup + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + this._aNormal.bindArrayBuffer(geometry.normalsBuf); + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } + + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); + + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } + + geometry.indicesBuf.bind(); + + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - gl.vertexAttribDivisor(this._aPickColor.location, 0); + gl.vertexAttribDivisor(this._aColor.location, 0); gl.vertexAttribDivisor(this._aFlags.location, 0); if (this._aFlags2) { // Won't be in shader when not clipping @@ -61740,15 +64406,16 @@ class PointsInstancingPickMeshRenderer { const program = this._program; - this._uPickInvisible = program.getLocation("pickInvisible"); + this._uRenderPass = program.getLocation("renderPass"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); + this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); this._uSectionPlanes = []; const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), @@ -61757,33 +64424,39 @@ class PointsInstancingPickMeshRenderer { }); } - this._uRenderPass = program.getLocation("renderPass"); this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); - this._aPickColor = program.getAttribute("pickColor"); + this._aNormal = program.getAttribute("normal"); + this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); - this._aFlags2 = program.getAttribute("flags2"); + + if (this._aFlags2) { + this._aFlags2 = program.getAttribute("flags2"); + } + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if (scene.logarithmicDepthBufferEnabled) { + if ( scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram(frameCtx) { + _bindProgram() { const scene = this._scene; const gl = scene.canvas.gl; - const program = this._program; + const project = scene.camera.project; - program.bind(); + this._program.bind(); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if ( scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } _buildShader() { @@ -61797,79 +64470,76 @@ class PointsInstancingPickMeshRenderer { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; const src = []; - src.push ('#version 300 es'); - src.push("// Points instancing pick mesh vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry normals drawing vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } + src.push("in vec3 normal;"); + src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 pickColor;"); - - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol0;"); src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); - - src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 worldNormalMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } - + src.push("vec3 octDecode(vec2 oct) {"); + src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); + src.push(" if (v.z < 0.0) {"); + src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); + src.push(" }"); + src.push(" return normalize(v);"); + src.push("}"); if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - src.push("out vec4 vPickColor;"); + src.push("out vec3 vViewNormal;"); src.push("void main(void) {"); - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK - - src.push(`if (int(flags.w) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); src.push("} else {"); - - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 worldNormal = worldNormalMatrix * vec4(octDecode(normal.xy), 0.0); "); + src.push(" vec3 viewNormal = normalize((viewNormalMatrix * worldNormal).xyz);"); - src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } + src.push(" vViewNormal = viewNormal;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } + src.push("gl_Position = clipPos;"); src.push("}"); src.push("}"); return src; @@ -61880,8 +64550,9 @@ class PointsInstancingPickMeshRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points instancing pick mesh fragment shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry depth drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -61890,35 +64561,30 @@ class PointsInstancingPickMeshRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vPickColor;"); + src.push("in vec3 vViewNormal;"); + src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); + src.push(" return normalize( normal ) * 0.5 + 0.5;"); + src.push("}"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } - if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); @@ -61927,9 +64593,9 @@ class PointsInstancingPickMeshRenderer { src.push("}"); } if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push("outColor = vPickColor; "); + src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); src.push("}"); return src; } @@ -61946,16 +64612,19 @@ class PointsInstancingPickMeshRenderer { } } -const tempVec3a$d = math.vec3(); +const tempVec3a$u = math.vec3(); /** + * Renders InstancingLayer fragment depths to a shadow map. + * * @private */ -class PointsInstancingPickDepthRenderer { +class TrianglesInstancingShadowRenderer { constructor(scene) { this._scene = scene; this._hash = this._getHash(); + this._lastLightId = null; this._allocate(); } @@ -61964,21 +64633,18 @@ class PointsInstancingPickDepthRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } - drawLayer(frameCtx, instancingLayer, renderPass) { - + drawLayer( frameCtx, instancingLayer) { const model = instancingLayer.model; const scene = model.scene; const gl = scene.canvas.gl; const state = instancingLayer._state; - const origin = instancingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; - const geometry = instancingLayer.geometry; + const geometry = state.geometry; if (!this._program) { - this._allocate(instancingLayer); + this._allocate(); if (this.errors) { return; } @@ -61986,36 +64652,45 @@ class PointsInstancingPickDepthRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx, instancingLayer); } - const camera = scene.camera; + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - gl.uniform1i(this._uRenderPass, renderPass); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; - const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); - gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); - gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); - gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } + // TODO: Section planes need to be set if RTC center has changed since last RTC center recorded on frameCtx + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; + const origin = instancingLayer._state.origin; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; if (sectionPlaneUniforms) { @@ -62024,7 +64699,7 @@ class PointsInstancingPickDepthRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$d); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$u); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -62035,44 +64710,16 @@ class PointsInstancingPickDepthRenderer { } } - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - - gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + geometry.indicesBuf.bind(); - // Cleanup + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - + gl.vertexAttribDivisor(this._aColor.location, 0); gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { // Won't be in shader when not clipping gl.vertexAttribDivisor(this._aFlags2.location, 0); } @@ -62083,57 +64730,45 @@ class PointsInstancingPickDepthRenderer { } _allocate() { - const scene = this._scene; const gl = scene.canvas.gl; - + const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); - if (this._program.errors) { this.errors = this._program.errors; return; } - const program = this._program; - - this._uRenderPass = program.getLocation("renderPass"); - this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uWorldMatrix = program.getLocation("worldMatrix"); - this._uViewMatrix = program.getLocation("viewMatrix"); - this._uProjMatrix = program.getLocation("projMatrix"); + this._uShadowViewMatrix = program.getLocation("shadowViewMatrix"); + this._uShadowProjMatrix = program.getLocation("shadowProjMatrix"); this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), dir: program.getLocation("sectionPlaneDir" + i) }); } - this._aPosition = program.getAttribute("position"); this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - - this._uPickZNear = program.getLocation("pickZNear"); - this._uPickZFar = program.getLocation("pickZFar"); - - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - - if (scene.logarithmicDepthBufferEnabled) { - this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); - } } - _bindProgram() { - this._program.bind(); - + _bindProgram(frameCtx, instancingLayer) { + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + program.bind(); + gl.uniformMatrix4fv(this._uShadowViewMatrix, false, frameCtx.shadowViewMatrix); + gl.uniformMatrix4fv(this._uShadowProjMatrix, false, frameCtx.shadowProjMatrix); + this._lastLightId = null; } _buildShader() { @@ -62147,81 +64782,44 @@ class PointsInstancingPickDepthRenderer { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; const src = []; - - src.push ('#version 300 es'); - src.push("// Points instancing pick depth vertex shader"); - - src.push("uniform int renderPass;"); - + src.push("#version 300 es"); + src.push("// Instancing geometry shadow drawing vertex shader"); src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - + src.push("in vec4 color;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol0;"); src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); - - src.push("uniform bool pickInvisible;"); - src.push("uniform mat4 worldMatrix;"); - src.push("uniform mat4 viewMatrix;"); - src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 shadowViewMatrix;"); + src.push("uniform mat4 shadowProjMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - - if (scene.logarithmicDepthBufferEnabled) { - src.push("uniform float logDepthBufFC;"); - src.push("out float vFragDepth;"); - } - if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } - - src.push("out vec4 vViewPosition;"); src.push("void main(void) {"); - - // flags.w = NOT_RENDERED | PICK - // renderPass = PICK - - src.push(`if (int(flags.w) != renderPass) {`); + src.push("bool visible = (float(flags.x) > 0.0);"); + src.push("bool transparent = ((float(color.a) / 255.0) < 1.0);"); + src.push(`if (!visible || transparent) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - + src.push(" worldPosition = vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vec4 viewPosition = shadowViewMatrix * worldPosition; "); + if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - src.push(" vFlags2 = flags2;"); - } - src.push(" vViewPosition = viewPosition;"); - src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); - } - src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } + src.push(" gl_Position = shadowProjMatrix * viewPosition;"); src.push("}"); src.push("}"); return src; @@ -62232,9 +64830,9 @@ class PointsInstancingPickDepthRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Points instancing pick depth fragment shader"); - + src.push("#version 300 es"); + src.push("// Instancing geometry depth drawing fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -62242,48 +64840,30 @@ class PointsInstancingPickDepthRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } - - src.push("uniform float pickZNear;"); - src.push("uniform float pickZFar;"); - if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec4 vViewPosition;"); - src.push("vec4 packDepth(const in float depth) {"); - src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); - src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); - src.push(" vec4 res = fract(depth * bitShift);"); - src.push(" res -= res.xxyz * bitMask;"); - src.push(" return res;"); + src.push("in vec3 vViewNormal;"); + src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); + src.push(" return normalize( normal ) * 0.5 + 0.5;"); src.push("}"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } - if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); @@ -62294,8 +64874,7 @@ class PointsInstancingPickDepthRenderer { if (scene.logarithmicDepthBufferEnabled) { src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); - src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth + src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); src.push("}"); return src; } @@ -62312,15 +64891,21 @@ class PointsInstancingPickDepthRenderer { } } -const tempVec3a$c = math.vec3(); +const tempVec4$1 = math.vec4(); +const tempVec3a$t = math.vec3(); + +const TEXTURE_DECODE_FUNCS = {}; +TEXTURE_DECODE_FUNCS[LinearEncoding] = "linearToLinear"; +TEXTURE_DECODE_FUNCS[sRGBEncoding] = "sRGBToLinear"; /** * @private */ -class PointsInstancingOcclusionRenderer { +class TrianglesInstancingPBRRenderer { - constructor(scene) { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); this._allocate(); } @@ -62330,19 +64915,23 @@ class PointsInstancingOcclusionRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + const scene = this._scene; + return [scene.gammaOutput, scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } drawLayer(frameCtx, instancingLayer, renderPass) { + const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; + const model = instancingLayer.model; - const scene = model.scene; + const scene = this._scene; const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; - const origin = instancingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; - const geometry = instancingLayer.geometry; + const origin = state.origin; + const textureSet = state.textureSet; + const geometry = state.geometry; + const lightsState = scene._lightsState; if (!this._program) { this._allocate(); @@ -62353,13 +64942,16 @@ class PointsInstancingOcclusionRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(); + this._bindProgram(frameCtx); } gl.uniform1i(this._uRenderPass, renderPass); gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uViewNormalMatrix, false, camera.viewNormalMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uWorldNormalMatrix, false, model.worldNormalMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { @@ -62374,7 +64966,7 @@ class PointsInstancingOcclusionRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$c); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$t); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -62387,6 +64979,10 @@ class PointsInstancingOcclusionRenderer { gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); + if (this._uUVDecodeMatrix) { + gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, geometry.uvDecodeMatrix); + } + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); @@ -62395,17 +64991,25 @@ class PointsInstancingOcclusionRenderer { gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - if (this._aColor) { - this._aColor.bindArrayBuffer(geometry.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); - } + this._aModelNormalMatrixCol0.bindArrayBuffer(state.modelNormalMatrixCol0Buf); + this._aModelNormalMatrixCol1.bindArrayBuffer(state.modelNormalMatrixCol1Buf); + this._aModelNormalMatrixCol2.bindArrayBuffer(state.modelNormalMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 1); this._aPosition.bindArrayBuffer(geometry.positionsBuf); + this._aNormal.bindArrayBuffer(geometry.normalsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); + if (this._aUV) { + this._aUV.bindArrayBuffer(geometry.uvBuf); } + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); + + this._aMetallicRoughness.bindArrayBuffer(state.metallicRoughnessBuf); + gl.vertexAttribDivisor(this._aMetallicRoughness.location, 1); this._aFlags.bindArrayBuffer(state.flagsBuf); gl.vertexAttribDivisor(this._aFlags.location, 1); @@ -62415,24 +65019,71 @@ class PointsInstancingOcclusionRenderer { gl.vertexAttribDivisor(this._aFlags2.location, 1); } - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + if (lightsState.reflectionMaps.length > 0 && lightsState.reflectionMaps[0].texture && this._uReflectionMap) { + this._program.bindTexture(this._uReflectionMap, lightsState.reflectionMaps[0].texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; + } - // Cleanup + if (lightsState.lightMaps.length > 0 && lightsState.lightMaps[0].texture && this._uLightMap) { + this._program.bindTexture(this._uLightMap, lightsState.lightMaps[0].texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4$1[0] = viewportWidth; + tempVec4$1[1] = viewportHeight; + tempVec4$1[2] = sao.blendCutoff; + tempVec4$1[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4$1); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + frameCtx.bindTexture++; + } + } + + if (textureSet) { + this._program.bindTexture(this._uBaseColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uMetallicRoughMap, textureSet.metallicRoughnessTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uEmissiveMap, textureSet.emissiveTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + this._program.bindTexture(this._uNormalMap, textureSet.normalsTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + } + + geometry.indicesBuf.bind(); + + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + + frameCtx.drawElements++; gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - if (this._aColor) { - gl.vertexAttribDivisor(this._aColor.location, 0); - } + gl.vertexAttribDivisor(this._aModelNormalMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelNormalMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aColor.location, 0); + gl.vertexAttribDivisor(this._aMetallicRoughness.location, 0); gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { // Won't be in shader when not clipping gl.vertexAttribDivisor(this._aFlags2.location, 0); } + if (this._aOffset) { gl.vertexAttribDivisor(this._aOffset.location, 0); } @@ -62442,7 +65093,7 @@ class PointsInstancingOcclusionRenderer { const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; this._program = new Program(gl, this._buildShader()); @@ -62454,14 +65105,61 @@ class PointsInstancingOcclusionRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uWorldNormalMatrix = program.getLocation("worldNormalMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uViewNormalMatrix = program.getLocation("viewNormalMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); + + this._uGammaFactor = program.getLocation("gammaFactor"); + + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; + + const lights = lightsState.lights; + let light; + + for (var i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + + if (lightsState.reflectionMaps.length > 0) { + this._uReflectionMap = "reflectionMap"; + } + + if (lightsState.lightMaps.length > 0) { + this._uLightMap = "lightMap"; + } + this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -62470,37 +65168,74 @@ class PointsInstancingOcclusionRenderer { } this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); + this._aNormal = program.getAttribute("normal"); + this._aUV = program.getAttribute("uv"); this._aColor = program.getAttribute("color"); + this._aMetallicRoughness = program.getAttribute("metallicRoughness"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aOffset = program.getAttribute("offset"); + + this._uBaseColorMap = "uBaseColorMap"; + this._uMetallicRoughMap = "uMetallicRoughMap"; + this._uEmissiveMap = "uEmissiveMap"; + this._uNormalMap = "uNormalMap"; this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + this._aModelNormalMatrixCol0 = program.getAttribute("modelNormalMatrixCol0"); + this._aModelNormalMatrixCol1 = program.getAttribute("modelNormalMatrixCol1"); + this._aModelNormalMatrixCol2 = program.getAttribute("modelNormalMatrixCol2"); + + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - _bindProgram() { - + _bindProgram(frameCtx) { const scene = this._scene; const gl = scene.canvas.gl; + const lightsState = scene._lightsState; + const lights = lightsState.lights; const project = scene.camera.project; this._program.bind(); gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + const light = lights[i]; + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + if (scene.logarithmicDepthBufferEnabled) { const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } + + if (this._uGammaFactor) { + gl.uniform1f(this._uGammaFactor, scene.gammaFactor); + } } _buildShader() { @@ -62514,94 +65249,144 @@ class PointsInstancingOcclusionRenderer { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; + const clippingCaps = sectionPlanesState.clippingCaps; const src = []; + src.push("#version 300 es"); + src.push("// Instancing geometry quality drawing vertex shader"); - src.push ('#version 300 es'); - src.push("// Points instancing occlusion vertex shader"); src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + src.push("in vec3 normal;"); + src.push("in vec4 color;"); + src.push("in vec2 uv;"); + src.push("in vec2 metallicRoughness;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); if (scene.entityOffsetsEnabled) { src.push("in vec3 offset;"); } - src.push("in vec4 color;"); - src.push("in vec4 flags;"); - src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); // Modeling matrix src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); + src.push("in vec4 modelNormalMatrixCol0;"); + src.push("in vec4 modelNormalMatrixCol1;"); + src.push("in vec4 modelNormalMatrixCol2;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 worldNormalMatrix;"); src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 viewNormalMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } + src.push("uniform mat3 uvDecodeMatrix;"); if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); + } + + src.push("vec3 octDecode(vec2 oct) {"); + src.push(" vec3 v = vec3(oct.xy, 1.0 - abs(oct.x) - abs(oct.y));"); + src.push(" if (v.z < 0.0) {"); + src.push(" v.xy = (1.0 - abs(v.yx)) * vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0);"); + src.push(" }"); + src.push(" return normalize(v);"); + src.push("}"); + + src.push("out vec4 vViewPosition;"); + src.push("out vec3 vViewNormal;"); + src.push("out vec4 vColor;"); + src.push("out vec2 vUV;"); + src.push("out vec2 vMetallicRoughness;"); + + if (lightsState.lightMaps.length > 0) { + src.push("out vec3 vWorldNormal;"); } if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); + if (clippingCaps) { + src.push("out vec4 vClipPosition;"); + } } + src.push("void main(void) {"); // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT src.push(`if (int(flags.x) != renderPass) {`); - src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - if (clipping) { - src.push(" vWorldPosition = worldPosition;"); - } + src.push("vec4 modelNormal = vec4(octDecode(normal.xy), 0.0); "); + src.push("vec4 worldNormal = worldNormalMatrix * vec4(dot(modelNormal, modelNormalMatrixCol0), dot(modelNormal, modelNormalMatrixCol1), dot(modelNormal, modelNormalMatrixCol2), 1.0);"); + src.push("vec3 viewNormal = vec4(viewNormalMatrix * worldNormal).xyz;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); - if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } - src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + if (clippingCaps) { + src.push("vClipPosition = clipPos;"); + } } + + src.push("vViewPosition = viewPosition;"); + src.push("vViewNormal = viewNormal;"); + src.push("vColor = color;"); + src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); + src.push("vMetallicRoughness = metallicRoughness;"); + + if (lightsState.lightMaps.length > 0) { + src.push("vWorldNormal = worldNormal.xyz;"); + } + + src.push("gl_Position = clipPos;"); src.push("}"); src.push("}"); return src; } _buildFragmentShader() { + const scene = this._scene; + const gammaOutput = scene.gammaOutput; // If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is false. const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; const clipping = sectionPlanesState.sectionPlanes.length > 0; + const clippingCaps = sectionPlanesState.clippingCaps; const src = []; - src.push ('#version 300 es'); - src.push("// Points instancing occlusion vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry quality drawing fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -62609,44 +65394,398 @@ class PointsInstancingOcclusionRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + + src.push("uniform sampler2D uBaseColorMap;"); + src.push("uniform sampler2D uMetallicRoughMap;"); + src.push("uniform sampler2D uEmissiveMap;"); + src.push("uniform sampler2D uNormalMap;"); + + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); + } + + if (lightsState.reflectionMaps.length > 0) { + src.push("uniform samplerCube reflectionMap;"); + } + + if (lightsState.lightMaps.length > 0) { + src.push("uniform samplerCube lightMap;"); + } + + src.push("uniform vec4 lightAmbient;"); + + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + + src.push("uniform float gammaFactor;"); + src.push("vec4 linearToLinear( in vec4 value ) {"); + src.push(" return value;"); + src.push("}"); + src.push("vec4 sRGBToLinear( in vec4 value ) {"); + src.push(" return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );"); + src.push("}"); + src.push("vec4 gammaToLinear( in vec4 value) {"); + src.push(" return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );"); + src.push("}"); + if (gammaOutput) { + src.push("vec4 linearToGamma( in vec4 value, in float gammaFactor ) {"); + src.push(" return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );"); + src.push("}"); + } + if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + if (clippingCaps) { + src.push("in vec4 vClipPosition;"); + } + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } + + src.push("in vec4 vViewPosition;"); + src.push("in vec3 vViewNormal;"); + src.push("in vec4 vColor;"); + src.push("in vec2 vUV;"); + src.push("in vec2 vMetallicRoughness;"); + + if (lightsState.lightMaps.length > 0) { + src.push("in vec3 vWorldNormal;"); + } + + src.push("uniform mat4 viewMatrix;"); + + // CONSTANT DEFINITIONS + + src.push("#define PI 3.14159265359"); + src.push("#define RECIPROCAL_PI 0.31830988618"); + src.push("#define RECIPROCAL_PI2 0.15915494"); + src.push("#define EPSILON 1e-6"); + + src.push("#define saturate(a) clamp( a, 0.0, 1.0 )"); + + // UTILITY DEFINITIONS + + src.push("vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {"); + src.push(" vec3 texel = texture( uNormalMap, uv ).xyz;"); + src.push(" if (texel.r == 0.0 && texel.g == 0.0 && texel.b == 0.0) {"); + src.push(" return normalize(surf_norm );"); + src.push(" }"); + src.push(" vec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );"); + src.push(" vec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );"); + src.push(" vec2 st0 = dFdx( uv.st );"); + src.push(" vec2 st1 = dFdy( uv.st );"); + src.push(" vec3 S = normalize( q0 * st1.t - q1 * st0.t );"); + src.push(" vec3 T = normalize( -q0 * st1.s + q1 * st0.s );"); + src.push(" vec3 N = normalize( surf_norm );"); + src.push(" vec3 mapN = texel.xyz * 2.0 - 1.0;"); + src.push(" mat3 tsn = mat3( S, T, N );"); + // src.push(" mapN *= 3.0;"); + src.push(" return normalize( tsn * mapN );"); + src.push("}"); + + src.push("vec3 inverseTransformDirection(in vec3 dir, in mat4 matrix) {"); + src.push(" return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );"); + src.push("}"); + + // STRUCTURES + + src.push("struct IncidentLight {"); + src.push(" vec3 color;"); + src.push(" vec3 direction;"); + src.push("};"); + + src.push("struct ReflectedLight {"); + src.push(" vec3 diffuse;"); + src.push(" vec3 specular;"); + src.push("};"); + + src.push("struct Geometry {"); + src.push(" vec3 position;"); + src.push(" vec3 viewNormal;"); + src.push(" vec3 worldNormal;"); + src.push(" vec3 viewEyeDir;"); + src.push("};"); + + src.push("struct Material {"); + src.push(" vec3 diffuseColor;"); + src.push(" float specularRoughness;"); + src.push(" vec3 specularColor;"); + src.push(" float shine;"); // Only used for Phong + src.push("};"); + + // IRRADIANCE EVALUATION + + src.push("float GGXRoughnessToBlinnExponent(const in float ggxRoughness) {"); + src.push(" float r = ggxRoughness + 0.0001;"); + src.push(" return (2.0 / (r * r) - 2.0);"); + src.push("}"); + + src.push("float getSpecularMIPLevel(const in float blinnShininessExponent, const in int maxMIPLevel) {"); + src.push(" float maxMIPLevelScalar = float( maxMIPLevel );"); + src.push(" float desiredMIPLevel = maxMIPLevelScalar - 0.79248 - 0.5 * log2( ( blinnShininessExponent * blinnShininessExponent ) + 1.0 );"); + src.push(" return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );"); + src.push("}"); + + if (lightsState.reflectionMaps.length > 0) { + src.push("vec3 getLightProbeIndirectRadiance(const in vec3 reflectVec, const in float blinnShininessExponent, const in int maxMIPLevel) {"); + src.push(" float mipLevel = 0.5 * getSpecularMIPLevel(blinnShininessExponent, maxMIPLevel);"); //TODO: a random factor - fix this + src.push(" vec3 envMapColor = " + TEXTURE_DECODE_FUNCS[lightsState.reflectionMaps[0].encoding] + "(texture(reflectionMap, reflectVec, mipLevel)).rgb;"); + src.push(" return envMapColor;"); + src.push("}"); + } + + // SPECULAR BRDF EVALUATION + + src.push("vec3 F_Schlick(const in vec3 specularColor, const in float dotLH) {"); + src.push(" float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );"); + src.push(" return ( 1.0 - specularColor ) * fresnel + specularColor;"); + src.push("}"); + + src.push("float G_GGX_Smith(const in float alpha, const in float dotNL, const in float dotNV) {"); + src.push(" float a2 = ( alpha * alpha );"); + src.push(" float gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); + src.push(" float gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); + src.push(" return 1.0 / ( gl * gv );"); + src.push("}"); + + src.push("float G_GGX_SmithCorrelated(const in float alpha, const in float dotNL, const in float dotNV) {"); + src.push(" float a2 = ( alpha * alpha );"); + src.push(" float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * ( dotNV * dotNV ) );"); + src.push(" float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * ( dotNL * dotNL ) );"); + src.push(" return 0.5 / max( gv + gl, EPSILON );"); + src.push("}"); + + src.push("float D_GGX(const in float alpha, const in float dotNH) {"); + src.push(" float a2 = ( alpha * alpha );"); + src.push(" float denom = ( dotNH * dotNH) * ( a2 - 1.0 ) + 1.0;"); + src.push(" return RECIPROCAL_PI * a2 / ( denom * denom);"); + src.push("}"); + + src.push("vec3 BRDF_Specular_GGX(const in IncidentLight incidentLight, const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); + src.push(" float alpha = ( roughness * roughness );"); + src.push(" vec3 halfDir = normalize( incidentLight.direction + geometry.viewEyeDir );"); + src.push(" float dotNL = saturate( dot( geometry.viewNormal, incidentLight.direction ) );"); + src.push(" float dotNV = saturate( dot( geometry.viewNormal, geometry.viewEyeDir ) );"); + src.push(" float dotNH = saturate( dot( geometry.viewNormal, halfDir ) );"); + src.push(" float dotLH = saturate( dot( incidentLight.direction, halfDir ) );"); + src.push(" vec3 F = F_Schlick( specularColor, dotLH );"); + src.push(" float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );"); + src.push(" float D = D_GGX( alpha, dotNH );"); + src.push(" return F * (G * D);"); + src.push("}"); + + src.push("vec3 BRDF_Specular_GGX_Environment(const in Geometry geometry, const in vec3 specularColor, const in float roughness) {"); + src.push(" float dotNV = saturate(dot(geometry.viewNormal, geometry.viewEyeDir));"); + src.push(" const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022);"); + src.push(" const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04);"); + src.push(" vec4 r = roughness * c0 + c1;"); + src.push(" float a004 = min(r.x * r.x, exp2(-9.28 * dotNV)) * r.x + r.y;"); + src.push(" vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;"); + src.push(" return specularColor * AB.x + AB.y;"); + src.push("}"); + + if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { + + src.push("void computePBRLightMapping(const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); + + if (lightsState.lightMaps.length > 0) { + src.push(" vec3 irradiance = " + TEXTURE_DECODE_FUNCS[lightsState.lightMaps[0].encoding] + "(texture(lightMap, geometry.worldNormal)).rgb;"); + src.push(" irradiance *= PI;"); + src.push(" vec3 diffuseBRDFContrib = (RECIPROCAL_PI * material.diffuseColor);"); + src.push(" reflectedLight.diffuse += irradiance * diffuseBRDFContrib;"); + } + + if (lightsState.reflectionMaps.length > 0) { + src.push(" vec3 reflectVec = reflect(geometry.viewEyeDir, geometry.viewNormal);"); + src.push(" reflectVec = inverseTransformDirection(reflectVec, viewMatrix);"); + src.push(" float blinnExpFromRoughness = GGXRoughnessToBlinnExponent(material.specularRoughness);"); + src.push(" vec3 radiance = getLightProbeIndirectRadiance(reflectVec, blinnExpFromRoughness, 8);"); + src.push(" vec3 specularBRDFContrib = BRDF_Specular_GGX_Environment(geometry, material.specularColor, material.specularRoughness);"); + src.push(" reflectedLight.specular += radiance * specularBRDFContrib;"); + } + + src.push("}"); + } + + // MAIN LIGHTING COMPUTATION FUNCTION + + src.push("void computePBRLighting(const in IncidentLight incidentLight, const in Geometry geometry, const in Material material, inout ReflectedLight reflectedLight) {"); + src.push(" float dotNL = saturate(dot(geometry.viewNormal, incidentLight.direction));"); + src.push(" vec3 irradiance = dotNL * incidentLight.color * PI;"); + src.push(" reflectedLight.diffuse += irradiance * (RECIPROCAL_PI * material.diffuseColor);"); + src.push(" reflectedLight.specular += irradiance * BRDF_Specular_GGX(incidentLight, geometry, material.specularColor, material.specularRoughness);"); + src.push("}"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + if (clippingCaps) { + src.push(" if (dist > (0.002 * vClipPosition.w)) {"); + src.push(" discard;"); + src.push(" }"); + src.push(" if (dist > 0.0) { "); + src.push(" outColor=vec4(1.0, 0.0, 0.0, 1.0);"); + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" return;"); + src.push("}"); + } else { + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); + } src.push("}"); } - src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue + + src.push("IncidentLight light;"); + src.push("Material material;"); + src.push("Geometry geometry;"); + src.push("ReflectedLight reflectedLight = ReflectedLight(vec3(0.0,0.0,0.0), vec3(0.0,0.0,0.0));"); + + src.push("vec3 rgb = (vec3(float(vColor.r) / 255.0, float(vColor.g) / 255.0, float(vColor.b) / 255.0));"); + src.push("float opacity = float(vColor.a) / 255.0;"); + + src.push("vec3 baseColor = rgb;"); + src.push("float specularF0 = 1.0;"); + src.push("float metallic = float(vMetallicRoughness.r) / 255.0;"); + src.push("float roughness = float(vMetallicRoughness.g) / 255.0;"); + src.push("float dielectricSpecular = 0.16 * specularF0 * specularF0;"); + + src.push("vec4 baseColorTexel = sRGBToLinear(texture(uBaseColorMap, vUV));"); + src.push("baseColor *= baseColorTexel.rgb;"); + // src.push("opacity = baseColorTexel.a;"); + + src.push("vec3 metalRoughTexel = texture(uMetallicRoughMap, vUV).rgb;"); + src.push("metallic *= metalRoughTexel.b;"); + src.push("roughness *= metalRoughTexel.g;"); + + src.push("vec3 viewNormal = perturbNormal2Arb( vViewPosition.xyz, normalize(vViewNormal), vUV );"); + + src.push("material.diffuseColor = baseColor * (1.0 - dielectricSpecular) * (1.0 - metallic);"); + src.push("material.specularRoughness = clamp(roughness, 0.04, 1.0);"); + src.push("material.specularColor = mix(vec3(dielectricSpecular), baseColor, metallic);"); + + src.push("geometry.position = vViewPosition.xyz;"); + src.push("geometry.viewNormal = -normalize(viewNormal);"); + src.push("geometry.viewEyeDir = normalize(vViewPosition.xyz);"); + + if (lightsState.lightMaps.length > 0) { + src.push("geometry.worldNormal = normalize(vWorldNormal);"); + } + + if (lightsState.lightMaps.length > 0 || lightsState.reflectionMaps.length > 0) { + src.push("computePBRLightMapping(geometry, material, reflectedLight);"); + } + + for (let i = 0, len = lightsState.lights.length; i < len; i++) { + + const light = lightsState.lights[i]; + + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("light.direction = normalize(lightDir" + i + ");"); + } else { + src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("light.direction = normalize(lightPos" + i + " - vViewPosition.xyz);"); + } else { + src.push("light.direction = normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("light.direction = normalize(lightDir" + i + ");"); + } else { + src.push("light.direction = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } + + src.push("light.color = lightColor" + i + ".rgb * lightColor" + i + ".a;"); // a is intensity + + src.push("computePBRLighting(light, geometry, material, reflectedLight);"); + } + + src.push("vec3 emissiveColor = sRGBToLinear(texture(uEmissiveMap, vUV)).rgb;"); // TODO: correct gamma function + + src.push("vec3 outgoingLight = (lightAmbient.rgb * lightAmbient.a * baseColor * opacity * rgb) + (reflectedLight.diffuse) + (reflectedLight.specular) + emissiveColor;"); + src.push("vec4 fragColor;"); + + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" fragColor = vec4(outgoingLight.rgb * ambient, opacity);"); + } else { + src.push(" fragColor = vec4(outgoingLight.rgb, opacity);"); + } + + if (gammaOutput) { + src.push("fragColor = linearToGamma(fragColor, gammaFactor);"); + } + + src.push("outColor = fragColor;"); + if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push("}"); return src; } @@ -62663,12 +65802,12 @@ class PointsInstancingOcclusionRenderer { } } -const tempVec3a$b = math.vec3(); +const tempVec3a$s = math.vec3(); /** * @private */ -class PointsInstancingDepthRenderer { +class TrianglesInstancingPickNormalsFlatRenderer { constructor(scene) { this._scene = scene; @@ -62681,7 +65820,7 @@ class PointsInstancingDepthRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + return this._scene._sectionPlanesState.getHash(); } drawLayer(frameCtx, instancingLayer, renderPass) { @@ -62691,12 +65830,11 @@ class PointsInstancingDepthRenderer { const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; const origin = instancingLayer._state.origin; - const pointsMaterial = scene.pointsMaterial._state; - const geometry = instancingLayer.geometry; if (!this._program) { - this._allocate(); + this._allocate(instancingLayer); if (this.errors) { return; } @@ -62707,10 +65845,25 @@ class PointsInstancingDepthRenderer { this._bindProgram(); } + // In practice, these binds will only happen once per frame + // because we pick normals on a single previously-picked mesh + gl.uniform1i(this._uRenderPass, renderPass); + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); + + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; + + gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { @@ -62719,23 +65872,23 @@ class PointsInstancingDepthRenderer { const renderFlags = model.renderFlags; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; - if (sectionPlaneUniforms) { - const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; - gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); - if (active) { - const sectionPlane = sectionPlanes[sectionPlaneIndex]; - if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$b); - gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); - } else { - gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); - } - gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$s); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); @@ -62744,15 +65897,8 @@ class PointsInstancingDepthRenderer { gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this._aPosition.bindArrayBuffer(geometry.positionsBuf); - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); - } - this._aFlags.bindArrayBuffer(state.flagsBuf); gl.vertexAttribDivisor(this._aFlags.location, 1); @@ -62761,11 +65907,14 @@ class PointsInstancingDepthRenderer { gl.vertexAttribDivisor(this._aFlags2.location, 1); } - gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); - const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); - gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + geometry.indicesBuf.bind(); + + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); @@ -62785,6 +65934,7 @@ class PointsInstancingDepthRenderer { const scene = this._scene; const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; this._program = new Program(gl, this._buildShader()); @@ -62796,15 +65946,15 @@ class PointsInstancingDepthRenderer { const program = this._program; this._uRenderPass = program.getLocation("renderPass"); - + this._uPickInvisible = program.getLocation("pickInvisible"); this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); this._uWorldMatrix = program.getLocation("worldMatrix"); this._uViewMatrix = program.getLocation("viewMatrix"); this._uProjMatrix = program.getLocation("projMatrix"); this._uSectionPlanes = []; - - for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), @@ -62816,32 +65966,18 @@ class PointsInstancingDepthRenderer { this._aOffset = program.getAttribute("offset"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); - this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - if (scene.logarithmicDepthBufferEnabled) { this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } _bindProgram() { - - const scene = this._scene; - const gl = scene.canvas.gl; - const project = scene.camera.project; - this._program.bind(); - - gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - - if (scene.logarithmicDepthBufferEnabled) { - const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); - gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); - } } _buildShader() { @@ -62855,10 +65991,10 @@ class PointsInstancingDepthRenderer { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; - const pointsMaterial = scene.pointsMaterial._state; const src = []; - src.push('#version 300 es'); - src.push("// Points instancing depth vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry normals vertex shader"); + src.push("uniform int renderPass;"); src.push("in vec3 position;"); if (scene.entityOffsetsEnabled) { @@ -62866,35 +66002,33 @@ class PointsInstancingDepthRenderer { } src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); + src.push("uniform bool pickInvisible;"); src.push("uniform mat4 worldMatrix;"); src.push("uniform mat4 viewMatrix;"); src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - - src.push("uniform float pointSize;"); - if (pointsMaterial.perspectivePoints) { - src.push("uniform float nearPlaneHeight;"); - } - if (scene.logarithmicDepthBufferEnabled) { src.push("uniform float logDepthBufFC;"); src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); } if (clipping) { - src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } + src.push("out vec4 vWorldPosition;"); src.push("void main(void) {"); - // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT - // renderPass = COLOR_OPAQUE + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK - src.push(`if (int(flags.x) != renderPass) {`); + src.push(`if (int(flags.w) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - src.push("} else {"); src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); @@ -62902,23 +66036,13 @@ class PointsInstancingDepthRenderer { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - - if (clipping) { - src.push("vWorldPosition = worldPosition;"); - src.push("vFlags2 = flags2;"); - } + src.push(" vWorldPosition = worldPosition;"); src.push("vec4 clipPos = projMatrix * viewPosition;"); if (scene.logarithmicDepthBufferEnabled) { - src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); } src.push("gl_Position = clipPos;"); - if (pointsMaterial.perspectivePoints) { - src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); - src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); - src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); - } else { - src.push("gl_PointSize = pointSize;"); - } src.push("}"); src.push("}"); return src; @@ -62927,12 +66051,11 @@ class PointsInstancingDepthRenderer { _buildFragmentShader() { const scene = this._scene; const sectionPlanesState = scene._sectionPlanesState; - let i; - let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push('#version 300 es'); - src.push("// Points instancing depth vertex shader"); + src.push("#version 300 es"); + src.push("// Batched geometry normals fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); src.push("precision highp int;"); @@ -62940,48 +66063,29 @@ class PointsInstancingDepthRenderer { src.push("precision mediump float;"); src.push("precision mediump int;"); src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + src.push("in vec4 vWorldPosition;"); if (clipping) { - src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("uniform bool sectionPlaneActive" + i + ";"); src.push("uniform vec3 sectionPlanePos" + i + ";"); src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - - src.push("const float packUpScale = 256. / 255.;"); - src.push("const float unpackDownscale = 255. / 256.;"); - src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); - src.push("const vec4 unpackFactors = unpackDownscale / vec4( packFactors, 1. );"); - src.push("const float shiftRight8 = 1.0 / 256.;"); - - src.push("vec4 packDepthToRGBA( const in float v ) {"); - src.push(" vec4 r = vec4( fract( v * packFactors ), v );"); - src.push(" r.yzw -= r.xyz * shiftRight8;"); - src.push(" return r * packUpScale;"); - src.push("}"); - + src.push("in vec3 vWorldNormal;"); src.push("out vec4 outColor;"); src.push("void main(void) {"); - - if (scene.pointsMaterial.roundPoints) { - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); - } - if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); src.push(" float dist = 0.0;"); - for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { src.push("if (sectionPlaneActive" + i + ") {"); src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); @@ -62989,10 +66093,13 @@ class PointsInstancingDepthRenderer { src.push("if (dist > 0.0) { discard; }"); src.push("}"); } - src.push(" outColor = packDepthToRGBA( gl_FragCoord.z); "); // Must be linear depth if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push(" vec3 xTangent = dFdx( vWorldPosition.xyz );"); + src.push(" vec3 yTangent = dFdy( vWorldPosition.xyz );"); + src.push(" vec3 worldNormal = normalize( cross( xTangent, yTangent ) );"); + src.push(" outColor = vec4((worldNormal * 0.5) + 0.5, 1.0);"); src.push("}"); return src; } @@ -63009,19 +66116,18 @@ class PointsInstancingDepthRenderer { } } -const tempVec3a$a = math.vec3(); +const tempVec4 = math.vec4(); +const tempVec3a$r = math.vec3(); /** - * Renders InstancingLayer fragment depths to a shadow map. - * * @private */ -class PointsInstancingShadowRenderer { +class TrianglesInstancingColorTextureRenderer { - constructor(scene) { + constructor(scene, withSAO) { this._scene = scene; + this._withSAO = withSAO; this._hash = this._getHash(); - this._lastLightId = null; this._allocate(); } @@ -63030,15 +66136,21 @@ class PointsInstancingShadowRenderer { }; _getHash() { - return this._scene._sectionPlanesState.getHash(); + const scene = this._scene; + return [scene.gammaOutput, scene._lightsState.getHash(), scene._sectionPlanesState.getHash(), (this._withSAO ? "sao" : "nosao")].join(";"); } - drawLayer( frameCtx, instancingLayer) { + drawLayer(frameCtx, instancingLayer, renderPass) { + const maxTextureUnits = WEBGL_INFO.MAX_TEXTURE_IMAGE_UNITS; const model = instancingLayer.model; const scene = model.scene; + const camera = scene.camera; const gl = scene.canvas.gl; const state = instancingLayer._state; + const geometry = state.geometry; + const origin = instancingLayer._state.origin; + const textureSet = state.textureSet; if (!this._program) { this._allocate(); @@ -63049,45 +66161,19 @@ class PointsInstancingShadowRenderer { if (frameCtx.lastProgramId !== this._program.id) { frameCtx.lastProgramId = this._program.id; - this._bindProgram(frameCtx, instancingLayer); - } - - gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - - this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); - this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); - this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - - gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); - gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - - this._aPosition.bindArrayBuffer(state.positionsBuf); - - if (this._aOffset) { - this._aOffset.bindArrayBuffer(state.offsetsBuf); - gl.vertexAttribDivisor(this._aOffset.location, 1); + this._bindProgram(frameCtx); } - this._aColor.bindArrayBuffer(state.colorsBuf); - gl.vertexAttribDivisor(this._aColor.location, 1); - - this._aFlags.bindArrayBuffer(state.flagsBuf); - gl.vertexAttribDivisor(this._aFlags.location, 1); - - if (this._aFlags2) { - this._aFlags2.bindArrayBuffer(state.flags2Buf); - gl.vertexAttribDivisor(this._aFlags2.location, 1); - } + gl.uniform1i(this._uRenderPass, renderPass); - // TODO: Section planes need to be set if RTC center has changed since last RTC center recorded on frameCtx + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; if (numSectionPlanes > 0) { const sectionPlanes = scene._sectionPlanesState.sectionPlanes; const baseIndex = instancingLayer.layerIndex * numSectionPlanes; const renderFlags = model.renderFlags; - const origin = instancingLayer._state.origin; for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; if (sectionPlaneUniforms) { @@ -63096,7 +66182,7 @@ class PointsInstancingShadowRenderer { if (active) { const sectionPlane = sectionPlanes[sectionPlaneIndex]; if (origin) { - const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$a); + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$r); gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); } else { gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); @@ -63107,9 +66193,44 @@ class PointsInstancingShadowRenderer { } } - gl.uniform1f(this._uPointSize, 10); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - gl.drawArraysInstanced(gl.POINTS, 0, state.positionsBuf.numItems, state.numInstances); + if (this._uUVDecodeMatrix) { + gl.uniformMatrix3fv(this._uUVDecodeMatrix, false, geometry.uvDecodeMatrix); + } + + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + this._aUV.bindArrayBuffer(geometry.uvBuf); + + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); + + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } + + geometry.indicesBuf.bind(); + + gl.drawElementsInstanced(gl.TRIANGLES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); + + frameCtx.drawElements++; gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); @@ -63124,49 +66245,160 @@ class PointsInstancingShadowRenderer { if (this._aOffset) { gl.vertexAttribDivisor(this._aOffset.location, 0); } + + if (textureSet) { + if (textureSet.colorTexture) { + this._program.bindTexture(this._uColorMap, textureSet.colorTexture.texture, frameCtx.textureUnit); + frameCtx.textureUnit = (frameCtx.textureUnit + 1) % maxTextureUnits; + } + } + + if (this._withSAO) { + const sao = scene.sao; + const saoEnabled = sao.possible; + if (saoEnabled) { + const viewportWidth = gl.drawingBufferWidth; + const viewportHeight = gl.drawingBufferHeight; + tempVec4[0] = viewportWidth; + tempVec4[1] = viewportHeight; + tempVec4[2] = sao.blendCutoff; + tempVec4[3] = sao.blendFactor; + gl.uniform4fv(this._uSAOParams, tempVec4); + this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 0); + } + } } _allocate() { + const scene = this._scene; const gl = scene.canvas.gl; - const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; + this._program = new Program(gl, this._buildShader()); + if (this._program.errors) { this.errors = this._program.errors; return; } + const program = this._program; + + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - this._uShadowViewMatrix = program.getLocation("shadowViewMatrix"); - this._uShadowProjMatrix = program.getLocation("shadowProjMatrix"); + this._uUVDecodeMatrix = program.getLocation("uvDecodeMatrix"); + + this._uWorldMatrix = program.getLocation("worldMatrix"); + + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + + this._uGammaFactor = program.getLocation("gammaFactor"); + + this._uLightAmbient = program.getLocation("lightAmbient"); + this._uLightColor = []; + this._uLightDir = []; + this._uLightPos = []; + this._uLightAttenuation = []; + + const lights = lightsState.lights; + let light; + + for (let i = 0, len = lights.length; i < len; i++) { + light = lights[i]; + switch (light.type) { + case "dir": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = null; + this._uLightDir[i] = program.getLocation("lightDir" + i); + break; + case "point": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = null; + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + case "spot": + this._uLightColor[i] = program.getLocation("lightColor" + i); + this._uLightPos[i] = program.getLocation("lightPos" + i); + this._uLightDir[i] = program.getLocation("lightDir" + i); + this._uLightAttenuation[i] = program.getLocation("lightAttenuation" + i); + break; + } + } + this._uSectionPlanes = []; - const clips = sectionPlanesState.sectionPlanes; - for (let i = 0, len = clips.length; i < len; i++) { + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { this._uSectionPlanes.push({ active: program.getLocation("sectionPlaneActive" + i), pos: program.getLocation("sectionPlanePos" + i), dir: program.getLocation("sectionPlaneDir" + i) }); } + this._aPosition = program.getAttribute("position"); - this._aOffset = program.getAttribute("offset"); this._aColor = program.getAttribute("color"); + this._aUV = program.getAttribute("uv"); this._aFlags = program.getAttribute("flags"); this._aFlags2 = program.getAttribute("flags2"); + this._aOffset = program.getAttribute("offset"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this._uPointSize = program.getLocation("pointSize"); + + this._uColorMap = "uColorMap"; + + this._uOcclusionTexture = "uOcclusionTexture"; + this._uSAOParams = program.getLocation("uSAOParams"); + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - _bindProgram(frameCtx, instancingLayer) { + _bindProgram(frameCtx) { + const scene = this._scene; const gl = scene.canvas.gl; - const program = this._program; - program.bind(); - gl.uniformMatrix4fv(this._uShadowViewMatrix, false, frameCtx.shadowViewMatrix); - gl.uniformMatrix4fv(this._uShadowProjMatrix, false, frameCtx.shadowProjMatrix); - this._lastLightId = null; + const lightsState = scene._lightsState; + const lights = lightsState.lights; + const project = scene.camera.project; + + this._program.bind(); + + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (this._uLightAmbient) { + gl.uniform4fv(this._uLightAmbient, scene._lightsState.getAmbientColorAndIntensity()); + } + + for (let i = 0, len = lights.length; i < len; i++) { + const light = lights[i]; + if (this._uLightColor[i]) { + gl.uniform4f(this._uLightColor[i], light.color[0], light.color[1], light.color[2], light.intensity); + } + if (this._uLightPos[i]) { + gl.uniform3fv(this._uLightPos[i], light.pos); + if (this._uLightAttenuation[i]) { + gl.uniform1f(this._uLightAttenuation[i], light.attenuation); + } + } + if (this._uLightDir[i]) { + gl.uniform3fv(this._uLightDir[i], light.dir); + } + } + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } + + if (this._uGammaFactor) { + gl.uniform1f(this._uGammaFactor, scene.gammaFactor); + } } _buildShader() { @@ -63181,57 +66413,97 @@ class PointsInstancingShadowRenderer { const sectionPlanesState = scene._sectionPlanesState; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Instancing geometry shadow drawing vertex shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry drawing vertex shader"); + + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); - if (scene.entityOffsetsEnabled) { - src.push("in vec3 offset;"); - } src.push("in vec4 color;"); + src.push("in vec2 uv;"); src.push("in vec4 flags;"); src.push("in vec4 flags2;"); - src.push("in vec4 modelMatrixCol0;"); + + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } + + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix src.push("in vec4 modelMatrixCol1;"); src.push("in vec4 modelMatrixCol2;"); - src.push("uniform mat4 shadowViewMatrix;"); - src.push("uniform mat4 shadowProjMatrix;"); + + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); src.push("uniform mat4 positionsDecodeMatrix;"); - src.push("uniform float pointSize;"); + src.push("uniform mat3 uvDecodeMatrix;"); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + src.push("bool isPerspectiveMatrix(mat4 m) {"); + src.push(" return (m[2][3] == - 1.0);"); + src.push("}"); + src.push("out float isPerspective;"); + } + if (clipping) { src.push("out vec4 vWorldPosition;"); src.push("out vec4 vFlags2;"); } + src.push("out vec4 vViewPosition;"); + src.push("out vec4 vColor;"); + src.push("out vec2 vUV;"); + src.push("void main(void) {"); - src.push("bool visible = (float(flags.x) > 0.0);"); - src.push("bool transparent = ((float(color.a) / 255.0) < 1.0);"); - src.push(`if (!visible || transparent) {`); + + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT + + src.push(`if (int(flags.x) != renderPass) {`); src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); - src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); - src.push(" worldPosition = vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); if (scene.entityOffsetsEnabled) { src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - src.push(" vec4 viewPosition = shadowViewMatrix * worldPosition; "); + + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vViewPosition = viewPosition;"); + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + src.push("vUV = (uvDecodeMatrix * vec3(uv, 1.0)).xy;"); + + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + src.push("isPerspective = float (isPerspectiveMatrix(projMatrix));"); + } if (clipping) { src.push("vWorldPosition = worldPosition;"); src.push("vFlags2 = flags2;"); } - src.push(" gl_Position = shadowProjMatrix * viewPosition;"); + + src.push("gl_Position = clipPos;"); src.push("}"); - src.push("gl_PointSize = pointSize;"); src.push("}"); return src; } _buildFragmentShader() { const scene = this._scene; + const gammaOutput = scene.gammaOutput; // If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is false. const sectionPlanesState = scene._sectionPlanesState; + const lightsState = scene._lightsState; + let i; + let len; const clipping = sectionPlanesState.sectionPlanes.length > 0; const src = []; - src.push ('#version 300 es'); - src.push("// Instancing geometry depth drawing fragment shader"); + src.push("#version 300 es"); + src.push("// Instancing geometry drawing fragment shader"); src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); src.push("precision highp float;"); @@ -63241,9 +66513,39 @@ class PointsInstancingShadowRenderer { src.push("precision mediump int;"); src.push("#endif"); if (scene.logarithmicDepthBufferEnabled) { + src.push("in float isPerspective;"); src.push("uniform float logDepthBufFC;"); src.push("in float vFragDepth;"); } + src.push("uniform sampler2D uColorMap;"); + if (this._withSAO) { + src.push("uniform sampler2D uOcclusionTexture;"); + src.push("uniform vec4 uSAOParams;"); + + src.push("const float packUpscale = 256. / 255.;"); + src.push("const float unpackDownScale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unPackFactors = unpackDownScale / vec4( packFactors, 1. );"); + + src.push("float unpackRGBToFloat( const in vec4 v ) {"); + src.push(" return dot( v, unPackFactors );"); + src.push("}"); + } + src.push("uniform float gammaFactor;"); + src.push("vec4 linearToLinear( in vec4 value ) {"); + src.push(" return value;"); + src.push("}"); + src.push("vec4 sRGBToLinear( in vec4 value ) {"); + src.push(" return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );"); + src.push("}"); + src.push("vec4 gammaToLinear( in vec4 value) {"); + src.push(" return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );"); + src.push("}"); + if (gammaOutput) { + src.push("vec4 linearToGamma( in vec4 value, in float gammaFactor ) {"); + src.push(" return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );"); + src.push("}"); + } if (clipping) { src.push("in vec4 vWorldPosition;"); src.push("in vec4 vFlags2;"); @@ -63253,17 +66555,33 @@ class PointsInstancingShadowRenderer { src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - src.push("in vec3 vViewNormal;"); - src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); - src.push(" return normalize( normal ) * 0.5 + 0.5;"); - src.push("}"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform vec4 lightAmbient;"); + for (i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + src.push("uniform vec4 lightColor" + i + ";"); + if (light.type === "dir") { + src.push("uniform vec3 lightDir" + i + ";"); + } + if (light.type === "point") { + src.push("uniform vec3 lightPos" + i + ";"); + } + if (light.type === "spot") { + src.push("uniform vec3 lightPos" + i + ";"); + src.push("uniform vec3 lightDir" + i + ";"); + } + } + + src.push("in vec4 vViewPosition;"); + src.push("in vec4 vColor;"); + src.push("in vec2 vUV;"); src.push("out vec4 outColor;"); + src.push("void main(void) {"); - src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); - src.push(" float r = dot(cxy, cxy);"); - src.push(" if (r > 1.0) {"); - src.push(" discard;"); - src.push(" }"); + if (clipping) { src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); src.push(" if (clippable) {"); @@ -63273,59 +66591,175 @@ class PointsInstancingShadowRenderer { src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); src.push("}"); } - src.push("if (dist > 0.0) { discard; }"); + src.push(" if (dist > 0.0) { "); + src.push(" discard;"); + src.push(" }"); src.push("}"); } - if (scene.logarithmicDepthBufferEnabled) { - src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); - } - src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); - src.push("}"); - return src; - } - - webglContextRestored() { - this._program = null; - } - destroy() { - if (this._program) { - this._program.destroy(); - } - this._program = null; - } -} + src.push("vec3 reflectedColor = vec3(0.0, 0.0, 0.0);"); + src.push("vec3 viewLightDir = vec3(0.0, 0.0, -1.0);"); -/** - * @private - */ -class PointsInstancingRenderers { + src.push("float lambertian = 1.0;"); - constructor(scene) { - this._scene = scene; - } + src.push("vec3 xTangent = dFdx( vViewPosition.xyz );"); + src.push("vec3 yTangent = dFdy( vViewPosition.xyz );"); + src.push("vec3 viewNormal = normalize( cross( xTangent, yTangent ) );"); - _compile() { - if (this._colorRenderer && (!this._colorRenderer.getValid())) { - this._colorRenderer.destroy(); - this._colorRenderer = null; - } - if (this._depthRenderer && (!this._depthRenderer.getValid())) { - this._depthRenderer.destroy(); - this._depthRenderer = null; - } - if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { - this._silhouetteRenderer.destroy(); - this._silhouetteRenderer = null; - } - if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { - this._pickMeshRenderer.destroy(); - this._pickMeshRenderer = null; - } - if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { + for (i = 0, len = lightsState.lights.length; i < len; i++) { + const light = lightsState.lights[i]; + if (light.type === "ambient") { + continue; + } + if (light.type === "dir") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "point") { + if (light.space === "view") { + src.push("viewLightDir = -normalize(lightPos" + i + " - viewPosition.xyz);"); + } else { + src.push("viewLightDir = -normalize((viewMatrix * vec4(lightPos" + i + ", 0.0)).xyz);"); + } + } else if (light.type === "spot") { + if (light.space === "view") { + src.push("viewLightDir = normalize(lightDir" + i + ");"); + } else { + src.push("viewLightDir = normalize((viewMatrix * vec4(lightDir" + i + ", 0.0)).xyz);"); + } + } else { + continue; + } + src.push("lambertian = max(dot(-viewNormal, viewLightDir), 0.0);"); + src.push("reflectedColor += lambertian * (lightColor" + i + ".rgb * lightColor" + i + ".a);"); + } + + src.push("vec4 color = vec4((lightAmbient.rgb * lightAmbient.a * vColor.rgb) + (reflectedColor * vColor.rgb), vColor.a);"); + if (gammaOutput) { + src.push("vec4 colorTexel = color * sRGBToLinear(texture(uColorMap, vUV));"); + } else { + src.push("vec4 colorTexel = color * texture(uColorMap, vUV);"); + } + src.push("float opacity = color.a;"); + + if (this._withSAO) { + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBToFloat(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" outColor = vec4(vColor.rgb * colorTexel.rgb * ambient, opacity);"); + } else { + src.push(" outColor = vec4(vColor.rgb * colorTexel.rgb, opacity);"); + } + + if (gammaOutput) { + src.push("outColor = linearToGamma(outColor, gammaFactor);"); + } + + if (scene.logarithmicDepthBufferEnabled) { + src.push(" gl_FragDepth = isPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + + src.push("}"); + return src; + } + + webglContextRestored() { + this._program = null; + } + + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; + } +} + +/** + * @private + */ +class TrianglesInstancingRenderers { + + constructor(scene) { + this._scene = scene; + } + + _compile() { + if (this._colorRenderer && (!this._colorRenderer.getValid())) { + this._colorRenderer.destroy(); + this._colorRenderer = null; + } + if (this._colorRendererWithSAO && (!this._colorRendererWithSAO.getValid())) { + this._colorRendererWithSAO.destroy(); + this._colorRendererWithSAO = null; + } + if (this._flatColorRenderer && (!this._flatColorRenderer.getValid())) { + this._flatColorRenderer.destroy(); + this._flatColorRenderer = null; + } + if (this._flatColorRendererWithSAO && (!this._flatColorRendererWithSAO.getValid())) { + this._flatColorRendererWithSAO.destroy(); + this._flatColorRendererWithSAO = null; + } + if (this._pbrRenderer && (!this._pbrRenderer.getValid())) { + this._pbrRenderer.destroy(); + this._pbrRenderer = null; + } + if (this._pbrRendererWithSAO && (!this._pbrRendererWithSAO.getValid())) { + this._pbrRendererWithSAO.destroy(); + this._pbrRendererWithSAO = null; + } + if (this._colorTextureRenderer && (!this._colorTextureRenderer.getValid())) { + this._colorTextureRenderer.destroy(); + this._colorTextureRenderer = null; + } + if (this._colorTextureRendererWithSAO && (!this._colorTextureRendererWithSAO.getValid())) { + this._colorTextureRendererWithSAO.destroy(); + this._colorTextureRendererWithSAO = null; + } + if (this._depthRenderer && (!this._depthRenderer.getValid())) { + this._depthRenderer.destroy(); + this._depthRenderer = null; + } + if (this._normalsRenderer && (!this._normalsRenderer.getValid())) { + this._normalsRenderer.destroy(); + this._normalsRenderer = null; + } + if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { + this._silhouetteRenderer.destroy(); + this._silhouetteRenderer = null; + } + if (this._edgesRenderer && (!this._edgesRenderer.getValid())) { + this._edgesRenderer.destroy(); + this._edgesRenderer = null; + } + if (this._edgesColorRenderer && (!this._edgesColorRenderer.getValid())) { + this._edgesColorRenderer.destroy(); + this._edgesColorRenderer = null; + } + if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { + this._pickMeshRenderer.destroy(); + this._pickMeshRenderer = null; + } + if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { this._pickDepthRenderer.destroy(); this._pickDepthRenderer = null; } + if (this._pickNormalsRenderer && this._pickNormalsRenderer.getValid() === false) { + this._pickNormalsRenderer.destroy(); + this._pickNormalsRenderer = null; + } + if (this._pickNormalsFlatRenderer && (!this._pickNormalsFlatRenderer.getValid())) { + this._pickNormalsFlatRenderer.destroy(); + this._pickNormalsFlatRenderer = null; + } if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { this._occlusionRenderer.destroy(); this._occlusionRenderer = null; @@ -63338,49 +66772,133 @@ class PointsInstancingRenderers { get colorRenderer() { if (!this._colorRenderer) { - this._colorRenderer = new PointsInstancingColorRenderer(this._scene, false); + this._colorRenderer = new TrianglesInstancingColorRenderer(this._scene, false); } return this._colorRenderer; } + get colorRendererWithSAO() { + if (!this._colorRendererWithSAO) { + this._colorRendererWithSAO = new TrianglesInstancingColorRenderer(this._scene, true); + } + return this._colorRendererWithSAO; + } + + get flatColorRenderer() { + if (!this._flatColorRenderer) { + this._flatColorRenderer = new TrianglesInstancingFlatColorRenderer(this._scene, false); + } + return this._flatColorRenderer; + } + + get flatColorRendererWithSAO() { + if (!this._flatColorRendererWithSAO) { + this._flatColorRendererWithSAO = new TrianglesInstancingFlatColorRenderer(this._scene, true); + } + return this._flatColorRendererWithSAO; + } + + get pbrRenderer() { + if (!this._pbrRenderer) { + this._pbrRenderer = new TrianglesInstancingPBRRenderer(this._scene, false); + } + return this._pbrRenderer; + } + + get pbrRendererWithSAO() { + if (!this._pbrRendererWithSAO) { + this._pbrRendererWithSAO = new TrianglesInstancingPBRRenderer(this._scene, true); + } + return this._pbrRendererWithSAO; + } + + get colorTextureRenderer() { + if (!this._colorTextureRenderer) { + this._colorTextureRenderer = new TrianglesInstancingColorTextureRenderer(this._scene, false); + } + return this._colorTextureRenderer; + } + + get colorTextureRendererWithSAO() { + if (!this._colorTextureRendererWithSAO) { + this._colorTextureRendererWithSAO = new TrianglesInstancingColorTextureRenderer(this._scene, true); + } + return this._colorTextureRendererWithSAO; + } + get silhouetteRenderer() { if (!this._silhouetteRenderer) { - this._silhouetteRenderer = new PointsInstancingSilhouetteRenderer(this._scene); + this._silhouetteRenderer = new TrianglesInstancingSilhouetteRenderer(this._scene); } return this._silhouetteRenderer; } get depthRenderer() { if (!this._depthRenderer) { - this._depthRenderer = new PointsInstancingDepthRenderer(this._scene); + this._depthRenderer = new TrianglesInstancingDepthRenderer(this._scene); } return this._depthRenderer; } + get normalsRenderer() { + if (!this._normalsRenderer) { + this._normalsRenderer = new TrianglesInstancingNormalsRenderer(this._scene); + } + return this._normalsRenderer; + } + + get edgesRenderer() { + if (!this._edgesRenderer) { + this._edgesRenderer = new TrianglesInstancingEdgesRenderer(this._scene); + } + return this._edgesRenderer; + } + + get edgesColorRenderer() { + if (!this._edgesColorRenderer) { + this._edgesColorRenderer = new TrianglesInstancingEdgesColorRenderer(this._scene); + } + return this._edgesColorRenderer; + } + get pickMeshRenderer() { if (!this._pickMeshRenderer) { - this._pickMeshRenderer = new PointsInstancingPickMeshRenderer(this._scene); + this._pickMeshRenderer = new TrianglesInstancingPickMeshRenderer(this._scene); } return this._pickMeshRenderer; } + get pickNormalsRenderer() { + if (!this._pickNormalsRenderer) { + this._pickNormalsRenderer = new TrianglesInstancingPickNormalsRenderer(this._scene); + } + return this._pickNormalsRenderer; + } + + get pickNormalsFlatRenderer() { + if (!this._pickNormalsFlatRenderer) { + this._pickNormalsFlatRenderer = new TrianglesInstancingPickNormalsFlatRenderer(this._scene); + } + return this._pickNormalsFlatRenderer; + } + get pickDepthRenderer() { if (!this._pickDepthRenderer) { - this._pickDepthRenderer = new PointsInstancingPickDepthRenderer(this._scene); + this._pickDepthRenderer = new TrianglesInstancingPickDepthRenderer(this._scene); } return this._pickDepthRenderer; } get occlusionRenderer() { if (!this._occlusionRenderer) { - this._occlusionRenderer = new PointsInstancingOcclusionRenderer(this._scene); + this._occlusionRenderer = new TrianglesInstancingOcclusionRenderer(this._scene); } return this._occlusionRenderer; } get shadowRenderer() { if (!this._shadowRenderer) { - this._shadowRenderer = new PointsInstancingShadowRenderer(this._scene); + this._shadowRenderer = new TrianglesInstancingShadowRenderer(this._scene); } return this._shadowRenderer; } @@ -63389,18 +66907,54 @@ class PointsInstancingRenderers { if (this._colorRenderer) { this._colorRenderer.destroy(); } + if (this._colorRendererWithSAO) { + this._colorRendererWithSAO.destroy(); + } + if (this._flatColorRenderer) { + this._flatColorRenderer.destroy(); + } + if (this._flatColorRendererWithSAO) { + this._flatColorRendererWithSAO.destroy(); + } + if (this._pbrRenderer) { + this._pbrRenderer.destroy(); + } + if (this._pbrRendererWithSAO) { + this._pbrRendererWithSAO.destroy(); + } + if (this._colorTextureRenderer) { + this._colorTextureRenderer.destroy(); + } + if (this._colorTextureRendererWithSAO) { + this._colorTextureRendererWithSAO.destroy(); + } if (this._depthRenderer) { this._depthRenderer.destroy(); } + if (this._normalsRenderer) { + this._normalsRenderer.destroy(); + } if (this._silhouetteRenderer) { this._silhouetteRenderer.destroy(); } + if (this._edgesRenderer) { + this._edgesRenderer.destroy(); + } + if (this._edgesColorRenderer) { + this._edgesColorRenderer.destroy(); + } if (this._pickMeshRenderer) { this._pickMeshRenderer.destroy(); } if (this._pickDepthRenderer) { this._pickDepthRenderer.destroy(); } + if (this._pickNormalsRenderer) { + this._pickNormalsRenderer.destroy(); + } + if (this._pickNormalsFlatRenderer) { + this._pickNormalsFlatRenderer.destroy(); + } if (this._occlusionRenderer) { this._occlusionRenderer.destroy(); } @@ -63410,46 +66964,54 @@ class PointsInstancingRenderers { } } -const cachedRenderers = {}; +const cachedRenderers$4 = {}; /** * @private */ -function getPointsInstancingRenderers(scene) { +function getInstancingRenderers$1(scene) { const sceneId = scene.id; - let instancingRenderers = cachedRenderers[sceneId]; + let instancingRenderers = cachedRenderers$4[sceneId]; if (!instancingRenderers) { - instancingRenderers = new PointsInstancingRenderers(scene); - cachedRenderers[sceneId] = instancingRenderers; + instancingRenderers = new TrianglesInstancingRenderers(scene); + cachedRenderers$4[sceneId] = instancingRenderers; instancingRenderers._compile(); scene.on("compile", () => { instancingRenderers._compile(); }); scene.on("destroyed", () => { - delete cachedRenderers[sceneId]; + delete cachedRenderers$4[sceneId]; instancingRenderers._destroy(); }); } return instancingRenderers; } -const tempUint8Vec4 = new Uint8Array(4); -const tempVec4a$5 = math.vec4([0, 0, 0, 1]); -const tempVec4b$5 = math.vec4([0, 0, 0, 1]); -const tempVec4c$2 = math.vec4([0, 0, 0, 1]); -const tempVec3fa = new Float32Array(3); +const tempUint8Vec4$2 = new Uint8Array(4); +const tempVec4a$9 = math.vec4([0, 0, 0, 1]); +const tempVec4b$9 = math.vec4([0, 0, 0, 1]); +const tempVec4c$6 = math.vec4([0, 0, 0, 1]); +const tempVec3fa$2 = new Float32Array(3); + +const tempVec3a$q = math.vec3(); +const tempVec3b$6 = math.vec3(); +const tempVec3c$4 = math.vec3(); +const tempVec3d$1 = math.vec3(); +const tempVec3e = math.vec3(); +const tempVec3f = math.vec3(); +const tempVec3g = math.vec3(); /** * @private */ -class PointsInstancingLayer { +class TrianglesInstancingLayer { /** * @param cfg * @param cfg.layerIndex * @param cfg.model * @param cfg.geometry - * @param cfg.material + * @param cfg.textureSet * @param cfg.origin */ constructor(cfg) { @@ -63460,23 +67022,11 @@ class PointsInstancingLayer { */ this.model = cfg.model; - /** - * Shared geometry - * @type {VBOSceneModelGeometry} - */ - this.geometry = cfg.geometry; - - /** - * Shared material - * @type {VBOSceneModelGeometry} - */ - this.material = cfg.material; - /** * State sorting key. * @type {string} */ - this.sortId = "PointsInstancingLayer"; + this.sortId = "TrianglesInstancingLayer" + (cfg.solid ? "-solid" : "-surface") + (cfg.normals ? "-normals" : "-autoNormals"); /** * Index of this InstancingLayer in VBOSceneModel#_layerList @@ -63484,14 +67034,20 @@ class PointsInstancingLayer { */ this.layerIndex = cfg.layerIndex; - this._pointsInstancingRenderers = getPointsInstancingRenderers(cfg.model.scene); + this._instancingRenderers = getInstancingRenderers$1(cfg.model.scene); + this._aabb = math.collapseAABB3(); - this._state = new RenderState({ - obb: math.OBB3(), + const stateCfg = { numInstances: 0, - origin: cfg.origin ? math.vec3(cfg.origin) : null - }); + obb: math.OBB3(), + origin: math.vec3(), + geometry: cfg.geometry, + textureSet: cfg.textureSet, + pbrSupported: false // Set in #finalize if we have enough to support quality rendering + }; + + this._state = new RenderState(stateCfg); // These counts are used to avoid unnecessary render passes this._numPortions = 0; @@ -63508,7 +67064,9 @@ class PointsInstancingLayer { /** @private */ this.numIndices = cfg.geometry.numIndices; - // Per-instance arrays + // Vertex arrays + this._colors = []; + this._metallicRoughness = []; this._pickColors = []; this._offsets = []; @@ -63517,8 +67075,17 @@ class PointsInstancingLayer { this._modelMatrixCol1 = []; this._modelMatrixCol2 = []; + // Modeling normal matrix per instance, array for each column + this._modelNormalMatrixCol0 = []; + this._modelNormalMatrixCol1 = []; + this._modelNormalMatrixCol2 = []; + this._portions = []; + if (cfg.origin) { + this._state.origin.set(cfg.origin); + } + this._finalized = false; /** @@ -63526,6 +67093,12 @@ class PointsInstancingLayer { * @type {*|Float64Array} */ this.aabb = math.collapseAABB3(); + + /** + * When true, this layer contains solid triangle meshes, otherwise this layer contains surface triangle meshes + * @type {boolean} + */ + this.solid = !!cfg.solid; } /** @@ -63536,14 +67109,22 @@ class PointsInstancingLayer { * Gives the portion the specified color and matrix. * * @param cfg Portion params + * @param cfg.color Color [0..255,0..255,0..255] + * @param cfg.metallic Metalness factor [0..255] + * @param cfg.roughness Roughness factor [0..255] + * @param cfg.opacity Opacity [0..255]. * @param cfg.meshMatrix Flat float 4x4 matrix. * @param [cfg.worldMatrix] Flat float 4x4 matrix. - * @param cfg.aabb Flat float AABB. + * @param cfg.worldAABB Flat float AABB. * @param cfg.pickColor Quantized pick color * @returns {number} Portion ID. */ createPortion(cfg) { + const color = cfg.color; + const metallic = cfg.metallic; + const roughness = cfg.roughness; + const opacity = cfg.opacity; const meshMatrix = cfg.meshMatrix; const worldMatrix = cfg.worldMatrix; const worldAABB = cfg.aabb; @@ -63553,6 +67134,21 @@ class PointsInstancingLayer { throw "Already finalized"; } + // TODO: find AABB for portion by transforming the geometry local AABB by the given meshMatrix? + + const r = color[0]; // Color is pre-quantized by VBOSceneModel + const g = color[1]; + const b = color[2]; + color[3]; + + this._colors.push(r); + this._colors.push(g); + this._colors.push(b); + this._colors.push(opacity); + + this._metallicRoughness.push((metallic !== null && metallic !== undefined) ? metallic : 0); + this._metallicRoughness.push((roughness !== null && roughness !== undefined) ? roughness : 255); + if (this.model.scene.entityOffsetsEnabled) { this._offsets.push(0); this._offsets.push(0); @@ -63574,7 +67170,30 @@ class PointsInstancingLayer { this._modelMatrixCol2.push(meshMatrix[10]); this._modelMatrixCol2.push(meshMatrix[14]); - // Per-instance pick colors + if (this._state.geometry.normalsBuf) { + + // Note: order of inverse and transpose doesn't matter + + let transposedMat = math.transposeMat4(meshMatrix, math.mat4()); // TODO: Use cached matrix + let normalMatrix = math.inverseMat4(transposedMat); + + this._modelNormalMatrixCol0.push(normalMatrix[0]); + this._modelNormalMatrixCol0.push(normalMatrix[4]); + this._modelNormalMatrixCol0.push(normalMatrix[8]); + this._modelNormalMatrixCol0.push(normalMatrix[12]); + + this._modelNormalMatrixCol1.push(normalMatrix[1]); + this._modelNormalMatrixCol1.push(normalMatrix[5]); + this._modelNormalMatrixCol1.push(normalMatrix[9]); + this._modelNormalMatrixCol1.push(normalMatrix[13]); + + this._modelNormalMatrixCol2.push(normalMatrix[2]); + this._modelNormalMatrixCol2.push(normalMatrix[6]); + this._modelNormalMatrixCol2.push(normalMatrix[10]); + this._modelNormalMatrixCol2.push(normalMatrix[14]); + } + + // Per-vertex pick colors this._pickColors.push(pickColor[0]); this._pickColors.push(pickColor[1]); @@ -63584,18 +67203,18 @@ class PointsInstancingLayer { // Expand AABB math.collapseAABB3(worldAABB); - const obb = this._state.obb; + const obb = this._state.geometry.obb; const lenPositions = obb.length; for (let i = 0; i < lenPositions; i += 4) { - tempVec4a$5[0] = obb[i + 0]; - tempVec4a$5[1] = obb[i + 1]; - tempVec4a$5[2] = obb[i + 2]; - math.transformPoint4(meshMatrix, tempVec4a$5, tempVec4b$5); + tempVec4a$9[0] = obb[i + 0]; + tempVec4a$9[1] = obb[i + 1]; + tempVec4a$9[2] = obb[i + 2]; + math.transformPoint4(meshMatrix, tempVec4a$9, tempVec4b$9); if (worldMatrix) { - math.transformPoint4(worldMatrix, tempVec4b$5, tempVec4c$2); - math.expandAABB3Point3(worldAABB, tempVec4c$2); + math.transformPoint4(worldMatrix, tempVec4b$9, tempVec4c$6); + math.expandAABB3Point3(worldAABB, tempVec4c$6); } else { - math.expandAABB3Point3(worldAABB, tempVec4b$5); + math.expandAABB3Point3(worldAABB, tempVec4b$9); } } @@ -63614,7 +67233,16 @@ class PointsInstancingLayer { this._state.numInstances++; const portionId = this._portions.length; - this._portions.push({}); + + const portion = {}; + + if (this.model.scene.pickSurfacePrecisionEnabled) { + portion.matrix = meshMatrix.slice(); + portion.inverseMatrix = null; // Lazy-computed in precisionRayPickSurface + portion.normalMatrix = null; // Lazy-computed in precisionRayPickSurface + } + + this._portions.push(portion); this._numPortions++; this.model.numPortions++; @@ -63626,10 +67254,24 @@ class PointsInstancingLayer { if (this._finalized) { throw "Already finalized"; } + const state = this._state; + const geometry = state.geometry; + const textureSet = state.textureSet; const gl = this.model.scene.canvas.gl; - const flagsLength = this._pickColors.length; + const colorsLength = this._colors.length; + const flagsLength = colorsLength; + if (colorsLength > 0) { + let notNormalized = false; + this._state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._colors), this._colors.length, 4, gl.DYNAMIC_DRAW, notNormalized); + this._colors = []; // Release memory + } + if (this._metallicRoughness.length > 0) { + const metallicRoughness = new Uint8Array(this._metallicRoughness); + let normalized = false; + this._state.metallicRoughnessBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, metallicRoughness, this._metallicRoughness.length, 2, gl.STATIC_DRAW, normalized); + } if (flagsLength > 0) { - // Because we only build flags arrays here, + // Because we only build flags arrays here, // get their length from the colors array let notNormalized = false; let normalized = true; @@ -63644,19 +67286,44 @@ class PointsInstancingLayer { } } if (this._modelMatrixCol0.length > 0) { + const normalized = false; + this._state.modelMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol0), this._modelMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); this._state.modelMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol1), this._modelMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); this._state.modelMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol2), this._modelMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); this._modelMatrixCol0 = []; this._modelMatrixCol1 = []; this._modelMatrixCol2 = []; + + if (this._state.geometry.normalsBuf) { + this._state.modelNormalMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelNormalMatrixCol0), this._modelNormalMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); + this._state.modelNormalMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelNormalMatrixCol1), this._modelNormalMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); + this._state.modelNormalMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelNormalMatrixCol2), this._modelNormalMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); + this._modelNormalMatrixCol0 = []; + this._modelNormalMatrixCol1 = []; + this._modelNormalMatrixCol2 = []; + } } if (this._pickColors.length > 0) { const normalized = false; this._state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._pickColors), this._pickColors.length, 4, gl.STATIC_DRAW, normalized); this._pickColors = []; // Release memory } + + this._state.pbrSupported + = !!state.metallicRoughnessBuf + && !!geometry.uvBuf + && !!geometry.normalsBuf + && !!textureSet + && !!textureSet.colorTexture + && !!textureSet.metallicRoughnessTexture; + + this._state.colorTextureSupported + = !!geometry.uvBuf + && !!textureSet + && !!textureSet.colorTexture; + this._finalized = true; } @@ -63826,10 +67493,13 @@ class PointsInstancingLayer { if (!this._finalized) { throw "Not finalized"; } - tempUint8Vec4[0] = color[0]; - tempUint8Vec4[1] = color[1]; - tempUint8Vec4[2] = color[2]; - this._state.colorsBuf.setData(tempUint8Vec4, portionId * 3, 3); + tempUint8Vec4$2[0] = color[0]; + tempUint8Vec4$2[1] = color[1]; + tempUint8Vec4$2[2] = color[2]; + tempUint8Vec4$2[3] = color[3]; + if (this._state.colorsBuf) { + this._state.colorsBuf.setData(tempUint8Vec4$2, portionId * 4, 4); + } } setTransparent(portionId, flags, transparent) { @@ -63942,12 +67612,14 @@ class PointsInstancingLayer { let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; - tempUint8Vec4[0] = f0; // x - normal fill - tempUint8Vec4[1] = f1; // y - emphasis fill - tempUint8Vec4[2] = f2; // z - edges - tempUint8Vec4[3] = f3; // w - pick + tempUint8Vec4$2[0] = f0; // x - normal fill + tempUint8Vec4$2[1] = f1; // y - emphasis fill + tempUint8Vec4$2[2] = f2; // z - edges + tempUint8Vec4$2[3] = f3; // w - pick - this._state.flagsBuf.setData(tempUint8Vec4, portionId * 4, 4); + if (this._state.flagsBuf) { + this._state.flagsBuf.setData(tempUint8Vec4$2, portionId * 4, 4); + } } _setFlags2(portionId, flags) { @@ -63957,9 +67629,11 @@ class PointsInstancingLayer { } const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; - tempUint8Vec4[0] = clippable; + tempUint8Vec4$2[0] = clippable; - this._state.flags2Buf.setData(tempUint8Vec4, portionId * 4, 4); + if (this._state.flags2Buf) { + this._state.flags2Buf.setData(tempUint8Vec4$2, portionId * 4, 4); + } } setOffset(portionId, offset) { @@ -63970,20 +67644,69 @@ class PointsInstancingLayer { this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled return; } - tempVec3fa[0] = offset[0]; - tempVec3fa[1] = offset[1]; - tempVec3fa[2] = offset[2]; - this._state.offsetsBuf.setData(tempVec3fa, portionId * 3, 3); + tempVec3fa$2[0] = offset[0]; + tempVec3fa$2[1] = offset[1]; + tempVec3fa$2[2] = offset[2]; + if (this._state.offsetsBuf) { + this._state.offsetsBuf.setData(tempVec3fa$2, portionId * 3, 3); + } } - // ---------------------- NORMAL RENDERING ----------------------------------- + // ---------------------- COLOR RENDERING ----------------------------------- drawColorOpaque(renderFlags, frameCtx) { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { return; } - if (this._pointsInstancingRenderers.colorRenderer) { - this._pointsInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + this._updateBackfaceCull(renderFlags, frameCtx); + const geometry = this._state.geometry; + if (frameCtx.withSAO && this.model.saoEnabled) { + if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { + if (this._instancingRenderers.pbrRendererWithSAO) { + this._instancingRenderers.pbrRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { + if (this._instancingRenderers.colorTextureRendererWithSAO) { + this._instancingRenderers.colorTextureRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (geometry.normalsBuf) { + if (this._instancingRenderers.colorRendererWithSAO) { + this._instancingRenderers.colorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else { + if (this._instancingRenderers.flatColorRendererWithSAO) { + this._instancingRenderers.flatColorRendererWithSAO.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } + } else if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { + if (this._instancingRenderers.pbrRenderer) { + this._instancingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { + if (this._instancingRenderers.colorTextureRenderer) { + this._instancingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else if (geometry.normalsBuf) { + if (this._instancingRenderers.colorRenderer) { + this._instancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } else { + if (this._instancingRenderers.flatColorRenderer) { + this._instancingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } + } + + _updateBackfaceCull(renderFlags, frameCtx) { + const backfaces = this.model.backfaces || (!this.solid) || renderFlags.sectioned; + if (frameCtx.backfaces !== backfaces) { + const gl = frameCtx.gl; + if (backfaces) { + gl.disable(gl.CULL_FACE); + } else { + gl.enable(gl.CULL_FACE); + } + frameCtx.backfaces = backfaces; } } @@ -63991,27 +67714,57 @@ class PointsInstancingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { return; } - if (this._pointsInstancingRenderers.colorRenderer) { - this._pointsInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + this._updateBackfaceCull(renderFlags, frameCtx); + if (frameCtx.pbrEnabled && this.model.pbrEnabled && this._state.pbrSupported) { + if (this._instancingRenderers.pbrRenderer) { + this._instancingRenderers.pbrRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } else if (frameCtx.colorTextureEnabled && this.model.colorTextureEnabled && this._state.colorTextureSupported) { + if (this._instancingRenderers.colorTextureRenderer) { + this._instancingRenderers.colorTextureRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } else if (this._state.normalsBuf) { + if (this._instancingRenderers.colorRenderer) { + this._instancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } else { + if (this._instancingRenderers.flatColorRenderer) { + this._instancingRenderers.flatColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } } } - // -- RENDERING SAO POST EFFECT TARGETS ---------------------------------------------------------------------------- + // ---------------------- RENDERING SAO POST EFFECT TARGETS -------------- drawDepth(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.depthRenderer) { + this._instancingRenderers.depthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses depth (eg SAO) does not apply to transparent objects + } } drawNormals(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.normalsRenderer) { + this._instancingRenderers.normalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); // Assume whatever post-effect uses normals (eg SAO) does not apply to transparent objects + } } - // ---------------------- EMPHASIS RENDERING ----------------------------------- + // ---------------------- SILHOUETTE RENDERING ----------------------------------- drawSilhouetteXRayed(renderFlags, frameCtx) { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { return; } - if (this._pointsInstancingRenderers.silhouetteRenderer) { - this._pointsInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.silhouetteRenderer) { + this._instancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); } } @@ -64019,8 +67772,9 @@ class PointsInstancingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { return; } - if (this._pointsInstancingRenderers.silhouetteRenderer) { - this._pointsInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.silhouetteRenderer) { + this._instancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); } } @@ -64028,26 +67782,57 @@ class PointsInstancingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { return; } - if (this._pointsInstancingRenderers.silhouetteRenderer) { - this._pointsInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.silhouetteRenderer) { + this._instancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); } } - //-- EDGES RENDERING ----------------------------------------------------------------------------------------------- + // ---------------------- EDGES RENDERING ----------------------------------- drawEdgesColorOpaque(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) { + return; + } + if (this._instancingRenderers.edgesColorRenderer) { + this._instancingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_OPAQUE); + } } drawEdgesColorTransparent(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numEdgesLayerPortions === 0) { + return; + } + if (this._instancingRenderers.edgesColorRenderer) { + this._instancingRenderers.edgesColorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_COLOR_TRANSPARENT); + } } - drawEdgesHighlighted(renderFlags, frameCtx) { + drawEdgesXRayed(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + return; + } + if (this._instancingRenderers.edgesRenderer) { + this._instancingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_XRAYED); + } } - drawEdgesSelected(renderFlags, frameCtx) { + drawEdgesHighlighted(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + return; + } + if (this._instancingRenderers.edgesRenderer) { + this._instancingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_HIGHLIGHTED); + } } - drawEdgesXRayed(renderFlags, frameCtx) { + drawEdgesSelected(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { + return; + } + if (this._instancingRenderers.edgesRenderer) { + this._instancingRenderers.edgesRenderer.drawLayer(frameCtx, this, RENDER_PASSES.EDGES_SELECTED); + } } // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- @@ -64056,15 +67841,23 @@ class PointsInstancingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { return; } - if (this._pointsInstancingRenderers.occlusionRenderer) { + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.occlusionRenderer) { // Only opaque, filled objects can be occluders - this._pointsInstancingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + this._instancingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); } } // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- drawShadow(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.shadowRenderer) { + this._instancingRenderers.shadowRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } } //---- PICKING ---------------------------------------------------------------------------------------------------- @@ -64073,8 +67866,9 @@ class PointsInstancingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { return; } - if (this._pointsInstancingRenderers.pickMeshRenderer) { - this._pointsInstancingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.pickMeshRenderer) { + this._instancingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); } } @@ -64082,12 +67876,130 @@ class PointsInstancingLayer { if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { return; } - if (this._pointsInstancingRenderers.pickDepthRenderer) { - this._pointsInstancingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.pickDepthRenderer) { + this._instancingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); } } drawPickNormals(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + this._updateBackfaceCull(renderFlags, frameCtx); + if (this._instancingRenderers.pickNormalsRenderer) { + this._instancingRenderers.pickNormalsRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } + } + + //----------------------------------------------------------------------------------------- + + precisionRayPickSurface(portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldNormal) { + + if (!this.model.scene.pickSurfacePrecisionEnabled) { + return false; + } + + const geometry = this._state.geometry; + const state = this._state; + const portion = this._portions[portionId]; + + if (!portion) { + this.model.error("portion not found: " + portionId); + return false; + } + + if (!portion.inverseMatrix) { + portion.inverseMatrix = math.inverseMat4(portion.matrix, math.mat4()); + } + + if (worldNormal && !portion.normalMatrix) { + portion.normalMatrix = math.transposeMat4(portion.inverseMatrix, math.mat4()); + } + + const quantizedPositions = geometry.quantizedPositions; + const indices = geometry.indices; + const origin = state.origin; + const offset = portion.offset; + + const rtcRayOrigin = tempVec3a$q; + const rtcRayDir = tempVec3b$6; + + rtcRayOrigin.set(origin ? math.subVec3(worldRayOrigin, origin, tempVec3c$4) : worldRayOrigin); // World -> RTC + rtcRayDir.set(worldRayDir); + + if (offset) { + math.subVec3(rtcRayOrigin, offset); + } + + math.transformRay(this.model.worldNormalMatrix, rtcRayOrigin, rtcRayDir, rtcRayOrigin, rtcRayDir); + + math.transformRay(portion.inverseMatrix, rtcRayOrigin, rtcRayDir, rtcRayOrigin, rtcRayDir); + + const a = tempVec3d$1; + const b = tempVec3e; + const c = tempVec3f; + + let gotIntersect = false; + let closestDist = 0; + const closestIntersectPos = tempVec3g; + + for (let i = 0, len = indices.length; i < len; i += 3) { + + const ia = indices[i + 0] * 3; + const ib = indices[i + 1] * 3; + const ic = indices[i + 2] * 3; + + a[0] = quantizedPositions[ia]; + a[1] = quantizedPositions[ia + 1]; + a[2] = quantizedPositions[ia + 2]; + + b[0] = quantizedPositions[ib]; + b[1] = quantizedPositions[ib + 1]; + b[2] = quantizedPositions[ib + 2]; + + c[0] = quantizedPositions[ic]; + c[1] = quantizedPositions[ic + 1]; + c[2] = quantizedPositions[ic + 2]; + + math.decompressPosition(a, state.positionsDecodeMatrix); + math.decompressPosition(b, state.positionsDecodeMatrix); + math.decompressPosition(c, state.positionsDecodeMatrix); + + if (math.rayTriangleIntersect(rtcRayOrigin, rtcRayDir, a, b, c, closestIntersectPos)) { + + math.transformPoint3(portion.matrix, closestIntersectPos, closestIntersectPos); + + math.transformPoint3(this.model.worldMatrix, closestIntersectPos, closestIntersectPos); + + if (offset) { + math.addVec3(closestIntersectPos, offset); + } + + if (origin) { + math.addVec3(closestIntersectPos, origin); + } + + const dist = Math.abs(math.lenVec3(math.subVec3(closestIntersectPos, worldRayOrigin, []))); + + if (!gotIntersect || dist > closestDist) { + closestDist = dist; + worldSurfacePos.set(closestIntersectPos); + if (worldNormal) { // Not that wasteful to eagerly compute - unlikely to hit >2 surfaces on most geometry + math.triangleNormal(a, b, c, worldNormal); + } + gotIntersect = true; + } + } + } + + if (gotIntersect && worldNormal) { + math.transformVec3(portion.normalMatrix, worldNormal, worldNormal); + math.transformVec3(this.model.worldNormalMatrix, worldNormal, worldNormal); + math.normalizeVec3(worldNormal); + } + + return gotIntersect; } destroy() { @@ -64096,6 +68008,10 @@ class PointsInstancingLayer { state.colorsBuf.destroy(); state.colorsBuf = null; } + if (state.metallicRoughnessBuf) { + state.metallicRoughnessBuf.destroy(); + state.metallicRoughnessBuf = null; + } if (state.flagsBuf) { state.flagsBuf.destroy(); state.flagsBuf = null; @@ -64120,6 +68036,18 @@ class PointsInstancingLayer { state.modelMatrixCol2Buf.destroy(); state.modelMatrixCol2Buf = null; } + if (state.modelNormalMatrixCol0Buf) { + state.modelNormalMatrixCol0Buf.destroy(); + state.modelNormalMatrixCol0Buf = null; + } + if (state.modelNormalMatrixCol1Buf) { + state.modelNormalMatrixCol1Buf.destroy(); + state.modelNormalMatrixCol1Buf = null; + } + if (state.modelNormalMatrixCol2Buf) { + state.modelNormalMatrixCol2Buf.destroy(); + state.modelNormalMatrixCol2Buf = null; + } if (state.pickColorsBuf) { state.pickColorsBuf.destroy(); state.pickColorsBuf = null; @@ -64128,47942 +68056,50336 @@ class PointsInstancingLayer { } } +const tempVec3a$p = math.vec3(); + /** - * Instantiated by Model#createTextureSet - * * @private */ -class VBOSceneModelTextureSet { +class LinesBatchingColorRenderer { - /** - * @param {*} cfg VBOSceneModelTextureSet properties. - * @param {String|Number} cfg.id Mandatory ID for the texture set, to refer to with {@link VBOSceneModel#createMesh}. - * @param {VBOSceneModel} cfg.model VBOSceneModel that owns this texture set. - * @param {VBOSceneModelTexture} [cfg.colorTexture] RGBA texture with base color in RGB and opacity in A. - * @param {VBOSceneModelTexture} [cfg.metallicRoughnessTexture] RGBA texture with metallic in R and roughness in G. - * @param {VBOSceneModelTexture} [cfg.normalsTexture] RGBA texture with surface normals in RGB. - * @param {VBOSceneModelTexture} [cfg.emissiveTexture] RGBA texture with emissive color in RGB. - * @param {VBOSceneModelTexture} [cfg.occlusionTexture] RGBA texture with ambient occlusion factors in RGB. - */ - constructor(cfg) { + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - /** - * ID of this VBOSceneModelTextureSet, unique within the VBOSceneModel. - * - * @property id - * @type {String} - * @final - */ - this.id = cfg.id; + getValid() { + return this._hash === this._getHash(); + }; - /** - * RGBA texture containing base color in RGB and opacity in A. - * - * @property colorTexture - * @type {VBOSceneModelTexture} - * @final - */ - this.colorTexture = cfg.colorTexture; + _getHash() { + return this._scene._sectionPlanesState.getHash(); + } - /** - * RGBA texture containing metallic and roughness factors in R and G. - * - * @property metallicRoughnessTexture - * @type {VBOSceneModelTexture} - * @final - */ - this.metallicRoughnessTexture = cfg.metallicRoughnessTexture; + drawLayer(frameCtx, batchingLayer, renderPass) { - /** - * RGBA texture with surface normals in RGB. - * - * @property normalsTexture - * @type {VBOSceneModelTexture} - * @final - */ - this.normalsTexture = cfg.normalsTexture; + const scene = this._scene; + const camera = scene.camera; + const model = batchingLayer.model; + const gl = scene.canvas.gl; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; + batchingLayer.geometry; - /** - * RGBA texture with emissive color in RGB. - * - * @property emissiveTexture - * @type {VBOSceneModelTexture} - * @final - */ - this.emissiveTexture = cfg.emissiveTexture; + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } + } - /** - * RGBA texture with ambient occlusion factors in RGB. - * - * @property occlusionTexture - * @type {VBOSceneModelTexture} - * @final - */ - this.occlusionTexture = cfg.occlusionTexture; - } + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx); + } - /** - * @private - */ - destroy() { - } -} + gl.uniform1i(this._uRenderPass, renderPass); -/** - * Instantiated by VBOSceneModel#createGeometry - * - * @private - */ -class VBOSceneModelGeometry { + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - /** - * @param {*} cfg Geometry properties. - * @param {String|Number} id Mandatory ID for the geometry, to refer to with {@link VBOSceneModel#createMesh}. - * @param {VBOSceneModel} model VBOSceneModel that owns this geometry. - * @param {*} cfg.primitive - * @param {*} cfg.positions - * @param {*} cfg.positionsCompressed - * @param {*} cfg.normals - * @param {*} cfg.normalsCompressed - * @param {*} cfg.colors - * @param {*} cfg.colorsCompressed - * @param {*} cfg.uv - * @param {*} cfg.uvCompressed - * @param {*} cfg.uvDecodeMatrix - * @param {*} cfg.indices - * @param {*} cfg.edgeIndices - */ - constructor(id, model, cfg) { + gl.lineWidth(scene.linesMaterial.lineWidth); - /////////////////////////////////////////////////////// - /////////////////////////////////////////////////////// - // TODO: optional origin param, or create from positions automatically if required - then offset from mesh origin in createMesh + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$p); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } + } - /** - * ID of this VBOSceneModelGeometry, unique within the VBOSceneModel. - * - * @property id - * @type {String} - * @final - */ - this.id = cfg.id; + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - /** - * The VBOSceneModel that contains this VBOSceneModelGeometry. - * - * @property model - * @type {VBOSceneModel} - * @final - */ - this.model = cfg.model; + this._aPosition.bindArrayBuffer(state.positionsBuf); - this.primitive = cfg.primitive; - this.positions = null; - this.positionsCompressed = null; - this.quantizedPositions = null; // If pickSurfacePrecisionEnabled is true - this.positionsDecodeMatrix = math.mat4(); - this.normals = null; - this.normalsCompressed = null; - this.colors = null; - this.colorsCompressed = null; - this.uv = null; - this.uvCompressed = null; - this.uvDecodeMatrix = null; - this.indices = null; - this.numIndices = 0; - this.obb = math.OBB3(); - this.positionsBuf = null; - this.normalsBuf = null; - this.edgeIndicesBuf = null; - this.uvBuf = null; - this.colorsBuf = null; + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); + } - const pickSurfacePrecisionEnabled = model.scene.pickSurfacePrecisionEnabled; - const gl = model.scene.canvas.gl; + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } - if (cfg.positionsCompressed && cfg.positionsCompressed.length > 0) { - const normalized = false; - this.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, cfg.positionsCompressed, cfg.positionsCompressed.length, 3, gl.STATIC_DRAW, normalized); - this.positionsDecodeMatrix.set(cfg.positionsDecodeMatrix); - const localAABB = math.collapseAABB3(); - math.expandAABB3Points3(localAABB, cfg.positionsCompressed); - geometryCompressionUtils.decompressAABB(localAABB, this.positionsDecodeMatrix); - math.AABB3ToOBB3(localAABB, this.obb); - if (pickSurfacePrecisionEnabled) { - this.quantizedPositions = cfg.positionsCompressed; - } - - } else if (cfg.positions && cfg.positions.length > 0) { - const lenPositions = cfg.positions.length; - const localAABB = math.collapseAABB3(); - math.expandAABB3Points3(localAABB, cfg.positions); - math.AABB3ToOBB3(localAABB, this.obb); - const quantizedPositions = quantizePositions(cfg.positions, localAABB, this.positionsDecodeMatrix); - let normalized = false; - this.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, lenPositions, 3, gl.STATIC_DRAW, normalized); - if (pickSurfacePrecisionEnabled) { - this.quantizedPositions = quantizedPositions; - } + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - if (cfg.normalsCompressed && cfg.normalsCompressed.length > 0) { - const normalized = true; // For oct-encoded UInt8 - this.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, cfg.normalsCompressed, cfg.normalsCompressed.length, 3, gl.STATIC_DRAW, normalized); - - } else if (cfg.normals && cfg.normals.length > 0) { - const compressedNormals = octEncodeNormals(cfg.normals); - const normalized = true; // For oct-encoded UInt8 - this.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, compressedNormals, compressedNormals.length, 3, gl.STATIC_DRAW, normalized); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - if (cfg.colorsCompressed && cfg.colorsCompressed.length > 0) { - const colorsCompressed = new Uint8Array(cfg.colorsCompressed); - const notNormalized = false; - this.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colorsCompressed, colorsCompressed.length, 4, gl.STATIC_DRAW, notNormalized); + state.indicesBuf.bind(); - } else if (cfg.colors && cfg.colors.length > 0) { - const colors = cfg.colors; - const colorsCompressed = new Uint8Array(colors.length); - for (let i = 0, len = colors.length; i < len; i++) { - colorsCompressed[i] = colors[i] * 255; - } - const notNormalized = false; - this.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colorsCompressed, colorsCompressed.length, 4, gl.STATIC_DRAW, notNormalized); - } + gl.drawElements(gl.LINES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); - if (cfg.uvCompressed && cfg.uvCompressed.length > 0) { - const uvCompressed = new Uint16Array(cfg.uvCompressed); - this.uvDecodeMatrix = math.mat4(cfg.uvDecodeMatrix); - this.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, cfg.uvCompressed, uvCompressed.length, 2, gl.STATIC_DRAW, false); + frameCtx.drawElements++; + } - } else if (cfg.uv && cfg.uv.length > 0) { - const bounds = geometryCompressionUtils.getUVBounds(cfg.uv); - const result = geometryCompressionUtils.compressUVs(cfg.uv, bounds.min, bounds.max); - const uvCompressed = result.quantized; - this.uvDecodeMatrix = result.decodeMatrix; - this.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uvCompressed, uvCompressed.length, 2, gl.STATIC_DRAW, false); - } + _allocate() { - if (cfg.indices && cfg.indices.length > 0) { - this.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(cfg.indices), cfg.indices.length, 1, gl.STATIC_DRAW); - if (pickSurfacePrecisionEnabled) { - this.indices = cfg.indices; - } - this.numIndices = cfg.indices.length; - } + const scene = this._scene; + const gl = scene.canvas.gl; - if (cfg.primitive === "triangles" || cfg.primitive === "solid" || cfg.primitive === "surface") { - let edgeIndices = cfg.edgeIndices; - if (!edgeIndices) { - edgeIndices = buildEdgeIndices(cfg.positions, cfg.indices, null, cfg.edgeThreshold || 10); - } - this.edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(edgeIndices), edgeIndices.length, 1, gl.STATIC_DRAW); + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; + return; } - } - /** - * @private - */ - destroy() { - } -} + const program = this._program; -/** - * @private - */ -function convertConstant(gl, constantVal, encoding = null) { + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - let extension; - const p = constantVal; + this._uSectionPlanes = []; - if (p === UnsignedByteType) return gl.UNSIGNED_BYTE; - if (p === UnsignedShort4444Type) return gl.UNSIGNED_SHORT_4_4_4_4; - if (p === UnsignedShort5551Type) return gl.UNSIGNED_SHORT_5_5_5_1; + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } - if (p === ByteType) return gl.BYTE; - if (p === ShortType) return gl.SHORT; - if (p === UnsignedShortType) return gl.UNSIGNED_SHORT; - if (p === IntType) return gl.INT; - if (p === UnsignedIntType) return gl.UNSIGNED_INT; - if (p === FloatType) return gl.FLOAT; + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - if (p === HalfFloatType) { - return gl.HALF_FLOAT; + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - if (p === AlphaFormat) return gl.ALPHA; - if (p === RGBAFormat) return gl.RGBA; - if (p === LuminanceFormat) return gl.LUMINANCE; - if (p === LuminanceAlphaFormat) return gl.LUMINANCE_ALPHA; - if (p === DepthFormat) return gl.DEPTH_COMPONENT; - if (p === DepthStencilFormat) return gl.DEPTH_STENCIL; - if (p === RedFormat) return gl.RED; - - if (p === RGBFormat) { - return gl.RGBA; - } + _bindProgram(frameCtx) { - // WebGL2 formats. + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + const project = scene.camera.project; - if (p === RedIntegerFormat) return gl.RED_INTEGER; - if (p === RGFormat) return gl.RG; - if (p === RGIntegerFormat) return gl.RG_INTEGER; - if (p === RGBAIntegerFormat) return gl.RGBA_INTEGER; + program.bind(); - // S3TC + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - if (p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format) { - if (encoding === sRGBEncoding) { - const extension = getExtension(gl, 'WEBGL_compressed_texture_s3tc_srgb'); - if (extension !== null) { - if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT; - if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; - if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; - if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; - } else { - return null; - } - } else { - extension = getExtension(gl, 'WEBGL_compressed_texture_s3tc'); - if (extension !== null) { - if (p === RGB_S3TC_DXT1_Format) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT; - if (p === RGBA_S3TC_DXT1_Format) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT; - if (p === RGBA_S3TC_DXT3_Format) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT; - if (p === RGBA_S3TC_DXT5_Format) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT; - } else { - return null; - } + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } } - // PVRTC - - if (p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format) { - const extension = getExtension(gl, 'WEBGL_compressed_texture_pvrtc'); - if (extension !== null) { - if (p === RGB_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - if (p === RGB_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - if (p === RGBA_PVRTC_4BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - if (p === RGBA_PVRTC_2BPPV1_Format) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - } else { - return null; - } + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - // ETC1 - - if (p === RGB_ETC1_Format) { - const extension = getExtension(gl, 'WEBGL_compressed_texture_etc1'); - if (extension !== null) { - return extension.COMPRESSED_RGB_ETC1_WEBGL; - } else { - return null; + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines batching color vertex shader"); + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - } - - // ETC2 - - if (p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format) { - const extension = getExtension(gl, 'WEBGL_compressed_texture_etc'); - if (extension !== null) { - if (p === RGB_ETC2_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if (p === RGBA_ETC2_EAC_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; - } else { - return null; + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); } - } - - // ASTC - - if (p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format || - p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format || - p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format || - p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format || - p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format) { - const extension = getExtension(gl, 'WEBGL_compressed_texture_astc'); - if (extension !== null) { - if (p === RGBA_ASTC_4x4_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if (p === RGBA_ASTC_5x4_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if (p === RGBA_ASTC_5x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if (p === RGBA_ASTC_6x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if (p === RGBA_ASTC_6x6_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if (p === RGBA_ASTC_8x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if (p === RGBA_ASTC_8x6_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if (p === RGBA_ASTC_8x8_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if (p === RGBA_ASTC_10x5_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if (p === RGBA_ASTC_10x6_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if (p === RGBA_ASTC_10x8_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if (p === RGBA_ASTC_10x10_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if (p === RGBA_ASTC_12x10_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if (p === RGBA_ASTC_12x12_Format) return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; - } else { - return null; + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } + src.push("out vec4 vColor;"); + src.push("void main(void) {"); + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); + src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push("worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } + src.push("gl_Position = clipPos;"); + src.push("}"); + src.push("}"); + return src; } - // BPTC - - if (p === RGBA_BPTC_Format) { - const extension = getExtension(gl, 'EXT_texture_compression_bptc'); - if (extension !== null) { - if (p === RGBA_BPTC_Format) { - return (encoding === sRGBEncoding) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines batching color fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } - } else { - return null; } + src.push("in vec4 vColor;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); + } + src.push(" outColor = vColor;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("}"); + return src; } - // - - if (p === UnsignedInt248Type) { - return gl.UNSIGNED_INT_24_8; - } - if (p === RepeatWrapping) { - return gl.REPEAT; - } - if (p === ClampToEdgeWrapping) { - return gl.CLAMP_TO_EDGE; - } - if (p === NearestMipMapNearestFilter) { - return gl.NEAREST_MIPMAP_LINEAR; - } - if (p === NearestMipMapLinearFilter) { - return gl.NEAREST_MIPMAP_LINEAR; - } - if (p === LinearMipMapNearestFilter) { - return gl.LINEAR_MIPMAP_NEAREST; - } - if (p === LinearMipMapLinearFilter) { - return gl.LINEAR_MIPMAP_LINEAR; - } - if (p === NearestFilter) { - return gl.NEAREST; - } - if (p === LinearFilter) { - return gl.LINEAR; + webglContextRestored() { + this._program = null; } - return null; + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; + } } -const color$2 = new Uint8Array([0, 0, 0, 1]); +const defaultColor$1 = new Float32Array([1, 1, 1]); +const tempVec3a$o = math.vec3(); /** - * @desc A low-level component that represents a 2D WebGL texture. - * * @private */ -class Texture2D { - - constructor({gl, target, format, type, wrapS, wrapT, wrapR, preloadColor, premultiplyAlpha, flipY}) { +class LinesBatchingSilhouetteRenderer { - this.gl = gl; + constructor(scene, primitiveType) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - this.target = target || gl.TEXTURE_2D; - this.format = format || RGBAFormat; - this.type = type || UnsignedByteType; - this.internalFormat = null; - this.premultiplyAlpha = !!premultiplyAlpha; - this.flipY = !!flipY; - this.unpackAlignment = 4; - this.wrapS = wrapS || RepeatWrapping; - this.wrapT = wrapT || RepeatWrapping; - this.wrapR = wrapR || RepeatWrapping; + getValid() { + return this._hash === this._getHash(); + }; - this.texture = gl.createTexture(); + _getHash() { + return this._scene._sectionPlanesState.getHash(); + } - if (preloadColor) { - this.setPreloadColor(preloadColor); // Prevents "there is no texture bound to the unit 0" error - } + drawLayer(frameCtx, batchingLayer, renderPass) { - this.allocated = true; - } + const model = batchingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = batchingLayer._state; + const origin = batchingLayer._state.origin; + batchingLayer.geometry; - setPreloadColor(value) { - if (!value) { - color$2[0] = 0; - color$2[1] = 0; - color$2[2] = 0; - color$2[3] = 255; - } else { - color$2[0] = Math.floor(value[0] * 255); - color$2[1] = Math.floor(value[1] * 255); - color$2[2] = Math.floor(value[2] * 255); - color$2[3] = Math.floor((value[3] !== undefined ? value[3] : 1) * 255); - } - const gl = this.gl; - gl.bindTexture(this.target, this.texture); - if (this.target === gl.TEXTURE_CUBE_MAP) { - const faces = [ - gl.TEXTURE_CUBE_MAP_POSITIVE_X, - gl.TEXTURE_CUBE_MAP_NEGATIVE_X, - gl.TEXTURE_CUBE_MAP_POSITIVE_Y, - gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, - gl.TEXTURE_CUBE_MAP_POSITIVE_Z, - gl.TEXTURE_CUBE_MAP_NEGATIVE_Z - ]; - for (let i = 0, len = faces.length; i < len; i++) { - gl.texImage2D(faces[i], 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, color$2); + if (!this._program) { + this._allocate(); + if (this.errors) { + return; } - } else { - gl.texImage2D(this.target, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, color$2); } - gl.bindTexture(this.target, null); - } - setTarget(target) { - this.target = target || this.gl.TEXTURE_2D; - } + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - setImage(image, props = {}) { + gl.uniform1i(this._uRenderPass, renderPass); - const gl = this.gl; + if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + const material = scene.xrayMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - if (props.format !== undefined) { - this.format = props.format; - } - if (props.internalFormat !== undefined) { - this.internalFormat = props.internalFormat; - } - if (props.encoding !== undefined) { - this.encoding = props.encoding; - } - if (props.type !== undefined) { - this.type = props.type; - } - if (props.flipY !== undefined) { - this.flipY = props.flipY; - } - if (props.premultiplyAlpha !== undefined) { - this.premultiplyAlpha = props.premultiplyAlpha; - } - if (props.unpackAlignment !== undefined) { - this.unpackAlignment = props.unpackAlignment; - } - if (props.minFilter !== undefined) { - this.minFilter = props.minFilter; - } - if (props.magFilter !== undefined) { - this.magFilter = props.magFilter; - } - if (props.wrapS !== undefined) { - this.wrapS = props.wrapS; - } - if (props.wrapT !== undefined) { - this.wrapT = props.wrapT; - } - if (props.wrapR !== undefined) { - this.wrapR = props.wrapR; + } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + const material = scene.selectedMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else { + gl.uniform4fv(this._uColor, defaultColor$1); } - let generateMipMap = false; + const viewMat = (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMat); - gl.bindTexture(this.target, this.texture); - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flipY); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); - gl.pixelStorei(gl.UNPACK_ALIGNMENT, this.unpackAlignment); - gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - const minFilter = convertConstant(gl, this.minFilter); - gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, minFilter); + gl.lineWidth(scene.linesMaterial.lineWidth); - if (minFilter === gl.NEAREST_MIPMAP_NEAREST - || minFilter === gl.LINEAR_MIPMAP_NEAREST - || minFilter === gl.NEAREST_MIPMAP_LINEAR - || minFilter === gl.LINEAR_MIPMAP_LINEAR) { - generateMipMap = true; + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = batchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$o); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - const magFilter = convertConstant(gl, this.magFilter); - if (magFilter) { - gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, magFilter); - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, batchingLayer._state.positionsDecodeMatrix); - const wrapS = convertConstant(gl, this.wrapS); - if (wrapS) { - gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS); - } + this._aPosition.bindArrayBuffer(state.positionsBuf); - const wrapT = convertConstant(gl, this.wrapT); - if (wrapT) { - gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - const glFormat = convertConstant(gl, this.format, this.encoding); - const glType = convertConstant(gl, this.type); - const glInternalFormat = getInternalFormat(gl, this.internalFormat, glFormat, glType, this.encoding, false); - - if (this.target === gl.TEXTURE_CUBE_MAP) { - if (utils.isArray(image)) { - const images = image; - const faces = [ - gl.TEXTURE_CUBE_MAP_POSITIVE_X, - gl.TEXTURE_CUBE_MAP_NEGATIVE_X, - gl.TEXTURE_CUBE_MAP_POSITIVE_Y, - gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, - gl.TEXTURE_CUBE_MAP_POSITIVE_Z, - gl.TEXTURE_CUBE_MAP_NEGATIVE_Z - ]; - for (let i = 0, len = faces.length; i < len; i++) { - gl.texImage2D(faces[i], 0, glInternalFormat, glFormat, glType, images[i]); - } - } - } else { - gl.texImage2D(gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image); + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - if (generateMipMap) { - gl.generateMipmap(this.target); + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - gl.bindTexture(this.target, null); + state.indicesBuf.bind(); + + gl.drawElements(gl.LINES, state.indicesBuf.numItems, state.indicesBuf.itemType, 0); } - setCompressedData({mipmaps, props = {}}) { + _allocate() { - const gl = this.gl; - const levels = mipmaps.length; + const scene = this._scene; + const gl = scene.canvas.gl; - // Cache props + this._program = new Program(gl, this._buildShader()); - if (props.format !== undefined) { - this.format = props.format; - } - if (props.internalFormat !== undefined) { - this.internalFormat = props.internalFormat; - } - if (props.encoding !== undefined) { - this.encoding = props.encoding; - } - if (props.type !== undefined) { - this.type = props.type; - } - if (props.flipY !== undefined) { - this.flipY = props.flipY; - } - if (props.premultiplyAlpha !== undefined) { - this.premultiplyAlpha = props.premultiplyAlpha; - } - if (props.unpackAlignment !== undefined) { - this.unpackAlignment = props.unpackAlignment; - } - if (props.minFilter !== undefined) { - this.minFilter = props.minFilter; - } - if (props.magFilter !== undefined) { - this.magFilter = props.magFilter; - } - if (props.wrapS !== undefined) { - this.wrapS = props.wrapS; + if (this._program.errors) { + this.errors = this._program.errors; + return; } - if (props.wrapT !== undefined) { - this.wrapT = props.wrapT; + + const program = this._program; + + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uColor = program.getLocation("color"); + this._uSectionPlanes = []; + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - if (props.wrapR !== undefined) { - this.wrapR = props.wrapR; + + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } + } - gl.activeTexture(gl.TEXTURE0 + 0); - gl.bindTexture(this.target, this.texture); + _bindProgram() { - let supportsMips = mipmaps.length > 1; + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, this.flipY); - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); - gl.pixelStorei(gl.UNPACK_ALIGNMENT, this.unpackAlignment); - gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE); + this._program.bind(); - const wrapS = convertConstant(gl, this.wrapS); - if (wrapS) { - gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS); - } + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - const wrapT = convertConstant(gl, this.wrapT); - if (wrapT) { - gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } + } - if (this.type === gl.TEXTURE_3D || this.type === gl.TEXTURE_2D_ARRAY) { - const wrapR = convertConstant(gl, this.wrapR); - if (wrapR) { - gl.texParameteri(this.target, gl.TEXTURE_WRAP_R, wrapR); - } - gl.texParameteri(this.type, gl.TEXTURE_WRAP_R, wrapR); - } + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - if (supportsMips) { - gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, filterFallback(gl, this.minFilter)); - gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, filterFallback(gl, this.magFilter)); + _buildVertexShader() { - } else { - gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, convertConstant(gl, this.minFilter)); - gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, convertConstant(gl, this.magFilter)); - } + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; - const glFormat = convertConstant(gl, this.format, this.encoding); - const glType = convertConstant(gl, this.type); - const glInternalFormat = getInternalFormat(gl, this.internalFormat, glFormat, glType, this.encoding, false); + const src = []; + src.push('#version 300 es'); + src.push("// Lines batching silhouette vertex shader"); - gl.texStorage2D(gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[0].width, mipmaps[0].height); + src.push("uniform int renderPass;"); - for (let i = 0, len = mipmaps.length; i < len; i++) { + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + src.push("uniform vec4 color;"); - const mipmap = mipmaps[i]; + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - if (this.format !== RGBAFormat) { - if (glFormat !== null) { - gl.compressedTexSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data); - } else { - console.warn('Attempt to load unsupported compressed texture format in .setCompressedData()'); - } - } else { - gl.texSubImage2D(gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data); - } + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - // if (generateMipMap) { - // // gl.generateMipmap(this.target); // Only for roughness textures? - // } + src.push("void main(void) {"); - gl.bindTexture(this.target, null); - } + // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | SILHOUETTE_XRAYED + // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - setProps(props) { - const gl = this.gl; - gl.bindTexture(this.target, this.texture); - this._uploadProps(props); - gl.bindTexture(this.target, null); - } + src.push(`if (int(flags.y) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); - _uploadProps(props) { - const gl = this.gl; - if (props.format !== undefined) { - this.format = props.format; + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - if (props.internalFormat !== undefined) { - this.internalFormat = props.internalFormat; + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } - if (props.encoding !== undefined) { - this.encoding = props.encoding; + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } - if (props.type !== undefined) { - this.type = props.type; + src.push("gl_Position = clipPos;"); + src.push("}"); + src.push("}"); + return src; + } + + _buildFragmentShader() { + + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines batching silhouette fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - if (props.minFilter !== undefined) { - const minFilter = convertConstant(gl, props.minFilter); - if (minFilter) { - this.minFilter = props.minFilter; - gl.texParameteri(this.target, gl.TEXTURE_MIN_FILTER, minFilter); - if (minFilter === gl.NEAREST_MIPMAP_NEAREST || minFilter === gl.LINEAR_MIPMAP_NEAREST || minFilter === gl.NEAREST_MIPMAP_LINEAR || minFilter === gl.LINEAR_MIPMAP_LINEAR) { - gl.generateMipmap(this.target); - } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - if (props.magFilter !== undefined) { - const magFilter = convertConstant(gl, props.magFilter); - if (magFilter) { - this.magFilter = props.magFilter; - gl.texParameteri(this.target, gl.TEXTURE_MAG_FILTER, magFilter); + src.push("uniform vec4 color;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); } - if (props.wrapS !== undefined) { - const wrapS = convertConstant(gl, props.wrapS); - if (wrapS) { - this.wrapS = props.wrapS; - gl.texParameteri(this.target, gl.TEXTURE_WRAP_S, wrapS); - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - if (props.wrapT !== undefined) { - const wrapT = convertConstant(gl, props.wrapT); - if (wrapT) { - this.wrapT = props.wrapT; - gl.texParameteri(this.target, gl.TEXTURE_WRAP_T, wrapT); - } + src.push("outColor = color;"); + src.push("}"); + return src; + } + + webglContextRestored() { + this._program = null; + } + + destroy() { + if (this._program) { + this._program.destroy(); } + this._program = null; + } +} + +/** + * @private + */ +class LinesBatchingRenderers { + + constructor(scene) { + this._scene = scene; } - bind(unit) { - if (!this.allocated) { - return; + _compile() { + if (this._colorRenderer && (!this._colorRenderer.getValid())) { + this._colorRenderer.destroy(); + this._colorRenderer = null; } - if (this.texture) { - const gl = this.gl; - gl.activeTexture(gl["TEXTURE" + unit]); - gl.bindTexture(this.target, this.texture); - return true; + if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { + this._silhouetteRenderer.destroy(); + this._silhouetteRenderer = null; } - return false; } - unbind(unit) { - if (!this.allocated) { - return; + get colorRenderer() { + if (!this._colorRenderer) { + this._colorRenderer = new LinesBatchingColorRenderer(this._scene, false); } - if (this.texture) { - const gl = this.gl; - gl.activeTexture(gl["TEXTURE" + unit]); - gl.bindTexture(this.target, null); + return this._colorRenderer; + } + + get silhouetteRenderer() { + if (!this._silhouetteRenderer) { + this._silhouetteRenderer = new LinesBatchingSilhouetteRenderer(this._scene); } + return this._silhouetteRenderer; } - destroy() { - if (!this.allocated) { - return; + _destroy() { + if (this._colorRenderer) { + this._colorRenderer.destroy(); } - if (this.texture) { - this.gl.deleteTexture(this.texture); - this.texture = null; + if (this._silhouetteRenderer) { + this._silhouetteRenderer.destroy(); } } } -function getInternalFormat(gl, internalFormatName, glFormat, glType, encoding, isVideoTexture = false) { - if (internalFormatName !== null) { - if (gl[internalFormatName] !== undefined) { - return gl[internalFormatName]; - } - console.warn('Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\''); - } - let internalFormat = glFormat; - if (glFormat === gl.RED) { - if (glType === gl.FLOAT) internalFormat = gl.R32F; - if (glType === gl.HALF_FLOAT) internalFormat = gl.R16F; - if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.R8; - } - if (glFormat === gl.RG) { - if (glType === gl.FLOAT) internalFormat = gl.RG32F; - if (glType === gl.HALF_FLOAT) internalFormat = gl.RG16F; - if (glType === gl.UNSIGNED_BYTE) internalFormat = gl.RG8; - } - if (glFormat === gl.RGBA) { - if (glType === gl.FLOAT) internalFormat = gl.RGBA32F; - if (glType === gl.HALF_FLOAT) internalFormat = gl.RGBA16F; - if (glType === gl.UNSIGNED_BYTE) internalFormat = (encoding === sRGBEncoding && isVideoTexture === false) ? gl.SRGB8_ALPHA8 : gl.RGBA8; - if (glType === gl.UNSIGNED_SHORT_4_4_4_4) internalFormat = gl.RGBA4; - if (glType === gl.UNSIGNED_SHORT_5_5_5_1) internalFormat = gl.RGB5_A1; - } - if (internalFormat === gl.R16F || internalFormat === gl.R32F || - internalFormat === gl.RG16F || internalFormat === gl.RG32F || - internalFormat === gl.RGBA16F || internalFormat === gl.RGBA32F) { - getExtension(gl, 'EXT_color_buffer_float'); +const cachedRenderers$3 = {}; + +/** + * @private + */ +function getBatchingRenderers(scene) { + const sceneId = scene.id; + let batchingRenderers = cachedRenderers$3[sceneId]; + if (!batchingRenderers) { + batchingRenderers = new LinesBatchingRenderers(scene); + cachedRenderers$3[sceneId] = batchingRenderers; + batchingRenderers._compile(); + scene.on("compile", () => { + batchingRenderers._compile(); + }); + scene.on("destroyed", () => { + delete cachedRenderers$3[sceneId]; + batchingRenderers._destroy(); + }); } - return internalFormat; + return batchingRenderers; } -function filterFallback(gl, f) { - if (f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter) { - return gl.NEAREST; - } - return gl.LINEAR; +/** + * @private + */ +class LinesBatchingBuffer { + constructor(maxGeometryBatchSize = 5000000) { + + if (maxGeometryBatchSize > 5000000) { + maxGeometryBatchSize = 5000000; + } + + this.maxVerts = maxGeometryBatchSize; + this.maxIndices = maxGeometryBatchSize * 3; // Rough rule-of-thumb + this.positions = []; + this.colors = []; + this.flags = []; + this.flags2 = []; + this.offsets = []; + this.indices = []; + } } +const tempVec4a$8 = math.vec4([0, 0, 0, 1]); +const tempVec4b$8 = math.vec4([0, 0, 0, 1]); +const tempVec4c$5 = math.vec4([0, 0, 0, 1]); +const tempOBB3$1 = math.OBB3(); + /** - * Instantiated by VBOSceneModel#createTexture - * * @private */ -class VBOSceneModelTexture { +class LinesBatchingLayer { /** - * @param {*} cfg Texture properties. - * @param {String|Number} cfg.id Mandatory ID for the texture, to refer to with {@link VBOSceneModel#createTexture}. - * @param {String} [cfg.model] VBOSceneModel that owns this texture. - * @param {*} [cfg.image] Texture image data. - * @param {String} [cfg.src] Texture image source. - * @param {Boolean} [cfg.flipY] Whether to flip on Y-axis. - * @param {number[]} [cfg.preloadColor] Texture preload color. - */ + * @param model + * @param cfg + * @param cfg.layerIndex + * @param cfg.positionsDecodeMatrix + * @param cfg.maxGeometryBatchSize + * @param cfg.origin + * @param cfg.scratchMemory + */ constructor(cfg) { /** - * ID of this VBOSceneModelTexture, unique within the VBOSceneModel. - * - * @property id - * @type {String} + * Index of this LinesBatchingLayer in {@link VBOSceneModel#_layerList}. + * @type {Number} */ - this.id = cfg.id; + this.layerIndex = cfg.layerIndex; - /** - * The texture. - * - * @property texture - * @type {Texture2D} - */ - this.texture = cfg.texture; - } + this._batchingRenderers = getBatchingRenderers(cfg.model.scene); + this.model = cfg.model; + this._buffer = new LinesBatchingBuffer(cfg.maxGeometryBatchSize); + this._scratchMemory = cfg.scratchMemory; - /** - * @private - */ - destroy() { - if (this.texture) { - this.texture.destroy(); - this.texture = null; + this._state = new RenderState({ + positionsBuf: null, + offsetsBuf: null, + colorsBuf: null, + flagsBuf: null, + flags2Buf: null, + indicesBuf: null, + positionsDecodeMatrix: math.mat4(), + origin: null + }); + + // These counts are used to avoid unnecessary render passes + this._numPortions = 0; + this._numVisibleLayerPortions = 0; + this._numTransparentLayerPortions = 0; + this._numXRayedLayerPortions = 0; + this._numSelectedLayerPortions = 0; + this._numHighlightedLayerPortions = 0; + this._numClippableLayerPortions = 0; + this._numEdgesLayerPortions = 0; + this._numPickableLayerPortions = 0; + this._numCulledLayerPortions = 0; + + this._modelAABB = math.collapseAABB3(); // Model-space AABB + this._portions = []; + + this._numVerts = 0; + + this._finalized = false; + + if (cfg.positionsDecodeMatrix) { + this._state.positionsDecodeMatrix.set(cfg.positionsDecodeMatrix); + this._preCompressedPositionsExpected = true; + } else { + this._preCompressedPositionsExpected = false; } - } -} -/** - * @desc Abstract base class for buildable 3D scene model classes. - * - * Defines methods to build geometries, textures, meshes and entities within the model. - * - * Implementations: - * - * * {@link VBOSceneModel} - WebGL2-based model representation that stores geometry as vertex buffer objects (VBOs). - * - * @interface - * @abstract - */ -class SceneModel { + if (cfg.origin) { + this._state.origin = math.vec3(cfg.origin); + } - /** - * Returns the {@link Entity}s in this SceneModel. - * @returns {*|{}} - * @abstract - */ - get objects() { + /** + * The axis-aligned World-space boundary of this LinesBatchingLayer's positions. + * @type {*|Float64Array} + */ + this.aabb = math.collapseAABB3(); } /** - * Gets the 3D World-space origin for this SceneModel. - * - * Each geometry or mesh origin, if supplied, is relative to this origin. - * - * Default value is ````[0,0,0]````. + * Tests if there is room for another portion in this LinesBatchingLayer. * - * @type {Float64Array} - * @abstract - * @abstract + * @param lenPositions Number of positions we'd like to create in the portion. + * @param lenIndices Number of indices we'd like to create in this portion. + * @returns {Boolean} True if OK to create another portion. */ - get origin() { + canCreatePortion(lenPositions, lenIndices) { + if (this._finalized) { + throw "Already finalized"; + } + return ((this._buffer.positions.length + lenPositions) < (this._buffer.maxVerts * 3) && (this._buffer.indices.length + lenIndices) < (this._buffer.maxIndices)); } /** - * Gets the SceneModel's local translation. + * Creates a new portion within this LinesBatchingLayer, returns the new portion ID. * - * Default value is ````[0,0,0]````. + * Gives the portion the specified geometry, color and matrix. * - * @type {Number[]} - * @abstract + * @param cfg.positions Flat float Local-space positions array. + * @param cfg.positionsCompressed Flat quantized positions array - decompressed with TrianglesBatchingLayer positionsDecodeMatrix + * @param cfg.indices Flat int indices array. + * @param cfg.color Quantized RGB color [0..255,0..255,0..255,0..255] + * @param cfg.opacity Opacity [0..255] + * @param [cfg.meshMatrix] Flat float 4x4 matrix + * @param [cfg.worldMatrix] Flat float 4x4 matrix + * @param cfg.worldAABB Flat float AABB World-space AABB + * @param cfg.pickColor Quantized pick color + * @returns {number} Portion ID */ - get position() { - } + createPortion(cfg) { - /** - * Gets the SceneModel's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - * @abstract - */ - get rotation() { - } + if (this._finalized) { + throw "Already finalized"; + } - /** - * Gets the SceneModels's local rotation quaternion. - * - * Default value is ````[0,0,0,1]````. - * - * @type {Number[]} - * @abstract - */ - get quaternion() { + const positions = cfg.positions; + const positionsCompressed = cfg.positionsCompressed; + const indices = cfg.indices; + const color = cfg.color; + const opacity = cfg.opacity; + const meshMatrix = cfg.meshMatrix; + const worldMatrix = cfg.worldMatrix; + const worldAABB = cfg.worldAABB; + cfg.pickColor; + + const buffer = this._buffer; + const positionsIndex = buffer.positions.length; + const vertsIndex = positionsIndex / 3; + + let numVerts; + + + if (this._preCompressedPositionsExpected) { + + if (!positionsCompressed) { + throw "positionsCompressed expected"; + } + + numVerts = positionsCompressed.length / 3; + + for (let i = 0, len = positionsCompressed.length; i < len; i++) { + buffer.positions.push(positionsCompressed[i]); + } + + const bounds = geometryCompressionUtils.getPositionsBounds(positionsCompressed); + + const min = geometryCompressionUtils.decompressPosition(bounds.min, this._state.positionsDecodeMatrix, []); + const max = geometryCompressionUtils.decompressPosition(bounds.max, this._state.positionsDecodeMatrix, []); + + worldAABB[0] = min[0]; + worldAABB[1] = min[1]; + worldAABB[2] = min[2]; + worldAABB[3] = max[0]; + worldAABB[4] = max[1]; + worldAABB[5] = max[2]; + + if (worldMatrix) { + math.AABB3ToOBB3(worldAABB, tempOBB3$1); + math.transformOBB3(worldMatrix, tempOBB3$1); + math.OBB3ToAABB3(tempOBB3$1, worldAABB); + } + + } else { + + if (!positions) { + throw "positions expected"; + } + + numVerts = positions.length / 3; + + const lenPositions = positions.length; + + const positionsBase = buffer.positions.length; + + for (let i = 0, len = positions.length; i < len; i++) { + buffer.positions.push(positions[i]); + } + + if (meshMatrix) { + + for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { + + tempVec4a$8[0] = buffer.positions[i + 0]; + tempVec4a$8[1] = buffer.positions[i + 1]; + tempVec4a$8[2] = buffer.positions[i + 2]; + + math.transformPoint4(meshMatrix, tempVec4a$8, tempVec4b$8); + + buffer.positions[i + 0] = tempVec4b$8[0]; + buffer.positions[i + 1] = tempVec4b$8[1]; + buffer.positions[i + 2] = tempVec4b$8[2]; + + math.expandAABB3Point3(this._modelAABB, tempVec4b$8); + + if (worldMatrix) { + math.transformPoint4(worldMatrix, tempVec4b$8, tempVec4c$5); + math.expandAABB3Point3(worldAABB, tempVec4c$5); + } else { + math.expandAABB3Point3(worldAABB, tempVec4b$8); + } + } + + } else { + + for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { + + tempVec4a$8[0] = buffer.positions[i + 0]; + tempVec4a$8[1] = buffer.positions[i + 1]; + tempVec4a$8[2] = buffer.positions[i + 2]; + + math.expandAABB3Point3(this._modelAABB, tempVec4a$8); + + if (worldMatrix) { + math.transformPoint4(worldMatrix, tempVec4a$8, tempVec4b$8); + math.expandAABB3Point3(worldAABB, tempVec4b$8); + } else { + math.expandAABB3Point3(worldAABB, tempVec4a$8); + } + } + } + } + + if (this._state.origin) { + const origin = this._state.origin; + worldAABB[0] += origin[0]; + worldAABB[1] += origin[1]; + worldAABB[2] += origin[2]; + worldAABB[3] += origin[0]; + worldAABB[4] += origin[1]; + worldAABB[5] += origin[2]; + } + + math.expandAABB3(this.aabb, worldAABB); + + if (color) { + + const r = color[0]; // Color is pre-quantized by VBOSceneModel + const g = color[1]; + const b = color[2]; + const a = opacity; + + for (let i = 0; i < numVerts; i++) { + buffer.colors.push(r); + buffer.colors.push(g); + buffer.colors.push(b); + buffer.colors.push(a); + } + } + + if (indices) { + for (let i = 0, len = indices.length; i < len; i++) { + buffer.indices.push(indices[i] + vertsIndex); + } + } + + if (this.model.scene.entityOffsetsEnabled) { + for (let i = 0; i < numVerts; i++) { + buffer.offsets.push(0); + buffer.offsets.push(0); + buffer.offsets.push(0); + } + } + + const portionId = this._portions.length / 2; + + this._portions.push(vertsIndex); + this._portions.push(numVerts); + + this._numPortions++; + this.model.numPortions++; + + this._numVerts += numVerts; + + return portionId; } /** - * Gets the SceneModel's local scale. - * - * Default value is ````[1,1,1]````. - * - * @type {Number[]} - * @abstract + * Builds batch VBOs from appended geometries. + * No more portions can then be created. */ - get scale() { + finalize() { + + if (this._finalized) { + this.model.error("Already finalized"); + return; + } + + const state = this._state; + const gl = this.model.scene.canvas.gl; + const buffer = this._buffer; + + if (buffer.positions.length > 0) { + if (this._preCompressedPositionsExpected) { + const positions = new Uint16Array(buffer.positions); + state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, positions, buffer.positions.length, 3, gl.STATIC_DRAW); + } else { + const positions = new Float32Array(buffer.positions); + const quantizedPositions = quantizePositions(positions, this._modelAABB, state.positionsDecodeMatrix); + state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, buffer.positions.length, 3, gl.STATIC_DRAW); + } + } + + if (buffer.colors.length > 0) { + const colors = new Uint8Array(buffer.colors); + let normalized = false; + state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, buffer.colors.length, 4, gl.DYNAMIC_DRAW, normalized); + } + + if (buffer.colors.length > 0) { // Because we build flags arrays here, get their length from the colors array + const flagsLength = buffer.colors.length; + const flags = new Uint8Array(flagsLength); + const flags2 = new Uint8Array(flagsLength); + let notNormalized = false; + let normalized = true; + state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags, flags.length, 4, gl.DYNAMIC_DRAW, notNormalized); + state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags2, flags2.length, 4, gl.DYNAMIC_DRAW, normalized); + } + + if (this.model.scene.entityOffsetsEnabled) { + if (buffer.offsets.length > 0) { + const offsets = new Float32Array(buffer.offsets); + state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, offsets, buffer.offsets.length, 3, gl.DYNAMIC_DRAW); + } + } + + if (buffer.indices.length > 0) { + const indices = new Uint32Array(buffer.indices); + state.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, indices, buffer.indices.length, 1, gl.STATIC_DRAW); + } + + this._buffer = null; + this._finalized = true; } - /** - * Gets the SceneModel's local modeling transform matrix. - * - * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. - * - * @type {Number[]} - * @abstract - */ - get matrix() { + initFlags(portionId, flags, meshTransparent) { + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } + if (flags & ENTITY_FLAGS.EDGES) { + this._numEdgesLayerPortions++; + this.model.numEdgesLayerPortions++; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } + if (meshTransparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } + const deferred = true; + this._setFlags(portionId, flags, meshTransparent, deferred); + this._setFlags2(portionId, flags, deferred); } - /** - * Gets the SceneModel's World matrix. - * - * @property worldMatrix - * @type {Number[]} - * @abstract - */ - get worldMatrix() { + flushInitFlags() { + this._setDeferredFlags(); + this._setDeferredFlags2(); } - /** - * Gets the SceneModel's World normal matrix. - * - * @type {Number[]} - * @abstract - */ - get worldNormalMatrix() { + setVisible(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } else { + this._numVisibleLayerPortions--; + this.model.numVisibleLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Called by private renderers in ./lib, returns the view matrix with which to - * render this SceneModel. The view matrix is the concatenation of the - * Camera view matrix with the Performance model's world (modeling) matrix. - * - * @private - * @abstract - */ - get viewMatrix() { + setHighlighted(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } else { + this._numHighlightedLayerPortions--; + this.model.numHighlightedLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Called by private renderers in ./lib, returns the view normal matrix with which to render this SceneModel. - * - * @private - * @abstract - */ - get viewNormalMatrix() { + setXRayed(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } else { + this._numXRayedLayerPortions--; + this.model.numXRayedLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Sets if backfaces are rendered for this SceneModel. - * - * Default is ````false````. - * - * @type {Boolean} - * @abstract - */ - get backfaces() { + setSelected(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } else { + this._numSelectedLayerPortions--; + this.model.numSelectedLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Sets if backfaces are rendered for this SceneModel. - * - * Default is ````false````. - * - * When we set this ````true````, then backfaces are always rendered for this SceneModel. - * - * When we set this ````false````, then we allow the Viewer to decide whether to render backfaces. In this case, - * the Viewer will: - * - * * hide backfaces on watertight meshes, - * * show backfaces on open meshes, and - * * always show backfaces on meshes when we slice them open with {@link SectionPlane}s. - * - * @type {Boolean} - * @abstract - */ - set backfaces(backfaces) { + setEdges(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.EDGES) { + this._numEdgesLayerPortions++; + this.model.numEdgesLayerPortions++; + } else { + this._numEdgesLayerPortions--; + this.model.numEdgesLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Gets the list of {@link Entity}s within this SceneModel. - * - * @returns {Entity[]} - * @abstract - */ - get entityList() { + setClippable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } else { + this._numClippableLayerPortions--; + this.model.numClippableLayerPortions--; + } + this._setFlags2(portionId, flags); } - /** - * Returns true to indicate that SceneModel is an {@link Entity}. - * @type {Boolean} - * @abstract - */ - get isEntity() { + setCulled(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } else { + this._numCulledLayerPortions--; + this.model.numCulledLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Returns ````true```` if this SceneModel represents a model. - * - * When ````true```` the SceneModel will be registered by {@link SceneModel#id} in - * {@link Scene#models} and may also have a {@link MetaObject} with matching {@link MetaObject#id}. - * - * @type {Boolean} - * @abstract - */ - get isModel() { + setCollidable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } } - /** - * Returns ````false```` to indicate that SceneModel never represents an object. - * - * @type {Boolean} - * @abstract - */ - get isObject() { + setPickable(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } else { + this._numPickableLayerPortions--; + this.model.numPickableLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Gets the SceneModel's World-space 3D axis-aligned bounding box. - * - * Represented by a six-element Float64Array containing the min/max extents of the - * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. - * - * @type {Number[]} - * @abstract - */ - get aabb() { + setColor(portionId, color) { + if (!this._finalized) { + throw "Not finalized"; + } + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstColor = vertexBase * 4; + const lenColor = numVerts * 4; + const tempArray = this._scratchMemory.getUInt8Array(lenColor); + const r = color[0]; + const g = color[1]; + const b = color[2]; + const a = color[3]; + for (let i = 0; i < lenColor; i += 4) { + tempArray[i + 0] = r; + tempArray[i + 1] = g; + tempArray[i + 2] = b; + tempArray[i + 3] = a; + } + this._state.colorsBuf.setData(tempArray, firstColor, lenColor); } - /** - * The approximate number of triangle primitives in this SceneModel. - * - * @type {Number} - * @abstract - */ - get numTriangles() { + setTransparent(portionId, flags, transparent) { + if (transparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } else { + this._numTransparentLayerPortions--; + this.model.numTransparentLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * The approximate number of line primitives in this SceneModel. - * - * @type {Number} - * @abstract - */ - get numLines() { + _setFlags(portionId, flags, transparent, deferred = false) { + + if (!this._finalized) { + throw "Not finalized"; + } + + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstFlag = vertexBase * 4; + const lenFlags = numVerts * 4; + this._scratchMemory.getUInt8Array(lenFlags); + + const visible = !!(flags & ENTITY_FLAGS.VISIBLE); + const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); + const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); + const selected = !!(flags & ENTITY_FLAGS.SELECTED); + const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); + const culled = !!(flags & ENTITY_FLAGS.CULLED); + + // Color + + let f0; + if (!visible || culled || xrayed + || (highlighted && !this.model.scene.highlightMaterial.glowThrough) + || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { + f0 = RENDER_PASSES.NOT_RENDERED; + } else { + if (transparent) { + f0 = RENDER_PASSES.COLOR_TRANSPARENT; + } else { + f0 = RENDER_PASSES.COLOR_OPAQUE; + } + } + + // Silhouette + + let f1; + if (!visible || culled) { + f1 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f1 = RENDER_PASSES.SILHOUETTE_SELECTED; + } else if (highlighted) { + f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; + } else if (xrayed) { + f1 = RENDER_PASSES.SILHOUETTE_XRAYED; + } else { + f1 = RENDER_PASSES.NOT_RENDERED; + } + + // Pick + + let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; + if (deferred) { + if (!this._deferredFlagValues) { + this._deferredFlagValues = new Uint8Array(this._numVerts * 4); + } + for (let i = firstFlag, len = (firstFlag + lenFlags); i < len; i += 4) { + this._deferredFlagValues[i + 0] = f0; + this._deferredFlagValues[i + 1] = f1; + this._deferredFlagValues[i + 2] = 0; + this._deferredFlagValues[i + 3] = f3; + } + } else if (this._state.flagsBuf) { + const tempArray = this._scratchMemory.getUInt8Array(lenFlags); + for (let i = 0; i < lenFlags; i += 4) { + tempArray[i + 0] = f0; // x - color + tempArray[i + 1] = f1; // y - silhouette - select/highlight/xray + tempArray[i + 2] = 0; // z - edges + tempArray[i + 3] = f3; // w - pickable + } + this._state.flagsBuf.setData(tempArray, firstFlag, lenFlags); + } } - /** - * The approximate number of point primitives in this SceneModel. - * - * @type {Number} - * @abstract - */ - get numPoints() { + _setDeferredFlags() { + if (this._deferredFlagValues) { + this._state.flagsBuf.setData(this._deferredFlagValues); + this._deferredFlagValues = null; + } } - /** - * Gets if any {@link Entity}s in this SceneModel are visible. - * - * The SceneModel is only rendered when {@link SceneModel#visible} is ````true```` and {@link SceneModel#culled} is ````false````. - * - * @type {Boolean} - * @abstract - */ - get visible() { + _setFlags2(portionId, flags, deferred = false) { + if (!this._finalized) { + throw "Not finalized"; + } + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstFlag = vertexBase * 4; + const lenFlags = numVerts * 4; + const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; + if (deferred) { + if (!this._setDeferredFlag2Values) { + this._setDeferredFlag2Values = new Uint8Array(this._numVerts * 4); + } + for (let i = firstFlag, len = (firstFlag + lenFlags); i < len; i += 4) { + this._setDeferredFlag2Values[i] = clippable; + } + } else { + const tempArray = this._scratchMemory.getUInt8Array(lenFlags); + for (let i = 0; i < lenFlags; i += 4) { + tempArray[i + 0] = clippable; + } + this._state.flags2Buf.setData(tempArray, firstFlag, lenFlags); + } } - /** - * Sets if this SceneModel is visible. - * - * The SceneModel is only rendered when {@link SceneModel#visible} is ````true```` and {@link SceneModel#culled} is ````false````. - ** - * @type {Boolean} - * @abstract - */ - set visible(visible) { + _setDeferredFlags2() { + if (this._setDeferredFlag2Values) { + this._state.flags2Buf.setData(this._setDeferredFlag2Values); + this._setDeferredFlag2Values = null; + } } - /** - * Gets if any {@link Entity}s in this SceneModel are xrayed. - * - * @type {Boolean} - * @abstract - */ - get xrayed() { + setOffset(portionId, offset) { + if (!this._finalized) { + throw "Not finalized"; + } + if (!this.model.scene.entityOffsetsEnabled) { + this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled + return; + } + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstOffset = vertexBase * 3; + const lenOffsets = numVerts * 3; + const tempArray = this._scratchMemory.getFloat32Array(lenOffsets); + const x = offset[0]; + const y = offset[1]; + const z = offset[2]; + for (let i = 0; i < lenOffsets; i += 3) { + tempArray[i + 0] = x; + tempArray[i + 1] = y; + tempArray[i + 2] = z; + } + this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets); } - /** - * Sets if all {@link Entity}s in this SceneModel are xrayed. - * - * @type {Boolean} - * @abstract - */ - set xrayed(xrayed) { + //-- RENDERING ---------------------------------------------------------------------------------------------- + + drawColorOpaque(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + if (this._batchingRenderers.colorRenderer) { + this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } } - /** - * Gets if any {@link Entity}s in this SceneModel are highlighted. - * - * @type {Boolean} - * @abstract - */ - get highlighted() { + drawColorTransparent(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { + return; + } + if (this._batchingRenderers.colorRenderer) { + this._batchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } } - /** - * Sets if all {@link Entity}s in this SceneModel are highlighted. - * - * @type {Boolean} - * @abstract - */ - set highlighted(highlighted) { + drawDepth(renderFlags, frameCtx) { } - /** - * Gets if any {@link Entity}s in this SceneModel are selected. - * - * @type {Boolean} - * @abstract - */ - get selected() { + drawNormals(renderFlags, frameCtx) { } - /** - * Sets if all {@link Entity}s in this SceneModel are selected. - * - * @type {Boolean} - * @abstract - */ - set selected(selected) { + drawSilhouetteXRayed(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + return; + } + if (this._batchingRenderers.silhouetteRenderer) { + this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); + } } - /** - * Gets if any {@link Entity}s in this SceneModel have edges emphasised. - * - * @type {Boolean} - * @abstract - */ - get edges() { + drawSilhouetteHighlighted(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + return; + } + if (this._batchingRenderers.silhouetteRenderer) { + this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); + } } - /** - * Sets if all {@link Entity}s in this SceneModel have edges emphasised. - * - * @type {Boolean} - * @abstract - */ - set edges(edges) { + drawSilhouetteSelected(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { + return; + } + if (this._batchingRenderers.silhouetteRenderer) { + this._batchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); + } } - /** - * Gets if this SceneModel is culled from view. - * - * The SceneModel is only rendered when {@link SceneModel#visible} is true and {@link SceneModel#culled} is false. - * - * @type {Boolean} - * @abstract - */ - get culled() { + drawEdgesColorOpaque(renderFlags, frameCtx) { } - /** - * Sets if this SceneModel is culled from view. - * - * The SceneModel is only rendered when {@link SceneModel#visible} is true and {@link SceneModel#culled} is false. - * - * @type {Boolean} - * @abstract - */ - set culled(culled) { + drawEdgesColorTransparent(renderFlags, frameCtx) { } - /** - * Gets if {@link Entity}s in this SceneModel are clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * @type {Boolean} - * @abstract - */ - get clippable() { + drawEdgesHighlighted(renderFlags, frameCtx) { } - /** - * Sets if {@link Entity}s in this SceneModel are clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * @type {Boolean} - * @abstract - */ - set clippable(clippable) { + drawEdgesSelected(renderFlags, frameCtx) { } - /** - * Gets if this SceneModel is collidable. - * - * @type {Boolean} - * @abstract - */ - get collidable() { + drawEdgesXRayed(renderFlags, frameCtx) { } - /** - * Sets if {@link Entity}s in this SceneModel are collidable. - * - * @type {Boolean} - * @abstract - */ - set collidable(collidable) { + drawPickMesh(frameCtx) { } - /** - * Gets if this SceneModel is pickable. - * - * Picking is done via calls to {@link Scene#pick}. - * - * @type {Boolean} - * @abstract - */ - get pickable() { + drawPickDepths(frameCtx) { } - /** - * Sets if {@link Entity}s in this SceneModel are pickable. - * - * Picking is done via calls to {@link Scene#pick}. - * - * @type {Boolean} - * @abstract - */ - set pickable(pickable) { + drawPickNormals(frameCtx) { } - /** - * Gets the RGB colorize color for this SceneModel. - * - * Each element of the color is in range ````[0..1]````. - * - * @type {Number[]} - * @abstract - */ - get colorize() { + drawOcclusion(frameCtx) { } - /** - * Sets the RGB colorize color for this SceneModel. - * - * Multiplies by rendered fragment colors. - * - * Each element of the color is in range ````[0..1]````. - * - * @type {Number[]} - * @abstract - */ - set colorize(colorize) { + drawShadow(frameCtx) { } - /** - * Gets this SceneModel's opacity factor. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - * @abstract - */ - get opacity() { - } - - /** - * Sets the opacity factor for this SceneModel. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - * @abstract - */ - set opacity(opacity) { - } - - /** - * Gets if this SceneModel casts a shadow. - * - * @type {Boolean} - * @abstract - */ - get castsShadow() { + destroy() { + const state = this._state; + if (state.positionsBuf) { + state.positionsBuf.destroy(); + state.positionsBuf = null; + } + if (state.offsetsBuf) { + state.offsetsBuf.destroy(); + state.offsetsBuf = null; + } + if (state.colorsBuf) { + state.colorsBuf.destroy(); + state.colorsBuf = null; + } + if (state.flagsBuf) { + state.flagsBuf.destroy(); + state.flagsBuf = null; + } + if (state.flags2Buf) { + state.flags2Buf.destroy(); + state.flags2Buf = null; + } + if (state.indicesBuf) { + state.indicesBuf.destroy(); + state.indicessBuf = null; + } + state.destroy(); } +} - /** - * Sets if this SceneModel casts a shadow. - * - * @type {Boolean} - * @abstract - */ - set castsShadow(castsShadow) { - } +const tempVec3a$n = math.vec3(); - /** - * Sets if this SceneModel can have shadow cast upon it. - * - * @type {Boolean} - * @abstract - */ - get receivesShadow() { - } +/** + * @private + */ +class LinesInstancingColorRenderer { - /** - * Sets if this SceneModel can have shadow cast upon it. - * - * @type {Boolean} - * @abstract - */ - set receivesShadow(receivesShadow) { + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - /** - * Gets if Scalable Ambient Obscurance (SAO) will apply to this SceneModel. - * - * SAO is configured by the Scene's {@link SAO} component. - * - * Only works when {@link SAO#enabled} is also true. - * - * @type {Boolean} - * @abstract - */ - get saoEnabled() { - } + getValid() { + return this._hash === this._getHash(); + }; - /** - * Gets if physically-based rendering (PBR) is enabled for this SceneModel. - * - * Only works when {@link Scene#pbrEnabled} is also true. - * - * @type {Boolean} - * @abstract - */ - get pbrEnabled() { + _getHash() { + return this._scene._sectionPlanesState.getHash(); } - /** - * Gets if color textures are enabled for this SceneModel. - * - * Only works when {@link Scene#colorTextureEnabled} is also true. - * - * @type {Boolean} - * @abstract - */ - get colorTextureEnabled() { - } + drawLayer(frameCtx, instancingLayer, renderPass) { - /** - * Returns true to indicate that SceneModel is implements {@link Drawable}. - * - * @type {Boolean} - * @abstract - */ - get isDrawable() { - } + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const geometry = instancingLayer.geometry; - /** @private - * @abstract - */ - get isStateSortable() { - } + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } + } - /** - * Configures the appearance of xrayed {@link Entity}s within this SceneModel. - * - * This is the {@link Scene#xrayMaterial}. - * - * @type {EmphasisMaterial} - * @abstract - */ - get xrayMaterial() { - } + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx); + } - /** - * Configures the appearance of highlighted {@link Entity}s within this SceneModel. - * - * This is the {@link Scene#highlightMaterial}. - * - * @type {EmphasisMaterial} - * @abstract - */ - get highlightMaterial() { - } + gl.uniform1i(this._uRenderPass, renderPass); - /** - * Configures the appearance of selected {@link Entity}s within this SceneModel. - * - * This is the {@link Scene#selectedMaterial}. - * - * @type {EmphasisMaterial} - * @abstract - */ - get selectedMaterial() { - } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - /** - * Configures the appearance of edges of {@link Entity}s within this SceneModel. - * - * This is the {@link Scene#edgeMaterial}. - * - * @type {EdgeMaterial} - * @abstract - */ - get edgeMaterial() { - } + gl.lineWidth(scene.linesMaterial.lineWidth); - /** - * Called by private renderers in ./lib, returns the picking view matrix with which to - * ray-pick on this SceneModel. - * - * @private - * @abstract - */ - getPickViewMatrix(pickViewMatrix) { - } + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$n); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } + } - /** - * Creates a reusable geometry within this SceneModel. - * - * We can then supply the geometry ID to {@link SceneModel#createMesh} when we want to create meshes that instance the geometry. - * - * @param {*} cfg Geometry properties. - * @param {String|Number} cfg.id Mandatory ID for the geometry, to refer to with {@link SceneModel#createMesh}. - * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. - * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. - * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. - * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. - * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. - * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. - * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. - * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. - * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````SceneModel```` constructor. - * @param {Number[]} [cfg.origin] Optional geometry origin, relative to {@link SceneModel#origin}. When this is given, then ````positions```` are assumed to be relative to this. - * @abstract - */ - createGeometry(cfg) { - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - /** - * Creates a texture within this SceneModel. - * - * We can then supply the texture ID to {@link SceneModel#createTextureSet} when we want to create texture sets that use the texture. - * - * @param {*} cfg Texture properties. - * @param {String|Number} cfg.id Mandatory ID for the texture, to refer to with {@link SceneModel#createTextureSet}. - * @param {String} [cfg.src] Image source for the texture. - * @param {HTMLImageElement} [cfg.image] HTML Image object to load into this Texture. - * @param {String} [cfg.minFilter="linearMipmapLinear"] How the texture is sampled when a texel covers less than one pixel. Supported values are 'linear', 'linearMipmapNearest', 'nearestMipmapNearest', 'nearestMipmapLinear' and 'linearMipmapLinear'. Defaulting to 'linearMipmapLinear'. - * @param {String} [cfg.magFilter="linear"] How the texture is sampled when a texel covers more than one pixel. Supported values are 'linear' and 'nearest'. - * @param {String} [cfg.wrapS="repeat"] Wrap parameter for texture coordinate *S*. Supported values are 'clampToEdge', 'mirroredRepeat' and 'repeat'. - * @param {String} [cfg.wrapT="repeat"] Wrap parameter for texture coordinate *T*. Supported values are 'clampToEdge', 'mirroredRepeat' and 'repeat'. - * @param {Boolean} [cfg.flipY=false] Flips this Texture's source data along its vertical axis when ````true````. - * @param {String} [cfg.encoding="linear"] Encoding format. Supported values are 'linear', 'sRGB', 'gamma' - * @abstract - */ - createTexture(cfg) { - } + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - /** - * Creates a texture set within this SceneModel. - * - * A texture set is a collection of textures that can be shared among meshes. We can then supply the texture set - * ID to {@link SceneModel#createMesh} when we want to create meshes that use the texture set. - * - * The textures can work as a texture atlas, where each mesh can have geometry UVs that index - * a different part of the textures. This allows us to minimize the number of textures in our models, which - * means faster rendering. - * - * @param {*} cfg Texture set properties. - * @param {String|Number} cfg.id Mandatory ID for the texture set, to refer to with {@link SceneModel#createMesh}. - * @param {*} [cfg.colorTextureId] ID of *RGBA* base color texture, with color in *RGB* and alpha in *A*. - * @param {*} [cfg.metallicRoughnessTextureId] ID of *RGBA* metal-roughness texture, with the metallic factor in *R*, and roughness factor in *G*. - * @param {*} [cfg.normalsTextureId] ID of *RGBA* normal map texture, with normal map vectors in *RGB*. - * @param {*} [cfg.emissiveTextureId] ID of *RGBA* emissive map texture, with emissive color in *RGB*. - * @param {*} [cfg.occlusionTextureId] ID of *RGBA* occlusion map texture, with occlusion factor in *R*. - * @abstract - */ - createTextureSet(cfg) { - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - /** - * Creates a mesh within this SceneModel. - * - * A mesh can either define its own geometry or share it with other meshes. To define own geometry, provide the - * various geometry arrays to this method. To share a geometry, provide the ID of a geometry created earlier - * with {@link SceneModel#createGeometry}. - * - * Internally, SceneModel will batch all unique mesh geometries into the same arrays, which improves - * rendering performance. - * - * If you accompany the arrays with an ````origin````, then ````createMesh()```` will assume - * that the ````positions```` are in relative-to-center (RTC) coordinates, with ````origin```` being the origin of their - * RTC coordinate system. - * - * @param {object} cfg Object properties. - * @param {String} cfg.id Mandatory ID for the new mesh. Must not clash with any existing components within the {@link Scene}. - * @param {String|Number} [cfg.textureSetId] ID of a texture set previously created with {@link SceneModel#createTextureSet"}. - * @param {String|Number} [cfg.geometryId] ID of a geometry to instance, previously created with {@link SceneModel#createGeometry"}. Overrides all other geometry parameters given to this method. - * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. - * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. - * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. - * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. - * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. - * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. - * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. - * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. - * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````SceneModel```` constructor. - * @param {Number[]} [cfg.origin] Optional geometry origin, relative to {@link SceneModel#origin}. When this is given, then ````positions```` are assumed to be relative to this. - * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position of the mesh. - * @param {Number[]} [cfg.scale=[1,1,1]] Scale of the mesh. - * @param {Number[]} [cfg.rotation=[0,0,0]] Rotation of the mesh as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Mesh modelling transform matrix. Overrides the ````position````, ````scale```` and ````rotation```` parameters. - * @param {Number[]} [cfg.color=[1,1,1]] RGB color in range ````[0..1, 0..1, 0..1]````. Overridden by texture set ````colorTexture````. Overrides ````colors```` and ````colorsCompressed````. - * @param {Number} [cfg.opacity=1] Opacity in range ````[0..1]````. Overridden by texture set ````colorTexture````. - * @param {Number} [cfg.metallic=0] Metallic factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. - * @param {Number} [cfg.roughness=1] Roughness factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. - * @abstract - */ - createMesh(cfg) { - } + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - /** - * Creates an {@link Entity} within this SceneModel, giving it one or more meshes previously created with {@link SceneModel#createMesh}. - * - * A mesh can only belong to one {@link Entity}, so you'll get an error if you try to reuse a mesh among multiple {@link Entity}s. - * - * @param {Object} cfg Entity configuration. - * @param {String} cfg.id Optional ID for the new Entity. Must not clash with any existing components within the {@link Scene}. - * @param {String[]} cfg.meshIds IDs of one or more meshes created previously with {@link SceneModel@createMesh}. - * @param {Boolean} [cfg.isObject] Set ````true```` if the {@link Entity} represents an object, in which case it will be registered by {@link Entity#id} in {@link Scene#objects} and can also have a corresponding {@link MetaObject} with matching {@link MetaObject#id}, registered by that ID in {@link MetaScene#metaObjects}. - * @param {Boolean} [cfg.visible=true] Indicates if the Entity is initially visible. - * @param {Boolean} [cfg.culled=false] Indicates if the Entity is initially culled from view. - * @param {Boolean} [cfg.pickable=true] Indicates if the Entity is initially pickable. - * @param {Boolean} [cfg.clippable=true] Indicates if the Entity is initially clippable. - * @param {Boolean} [cfg.collidable=true] Indicates if the Entity is initially included in boundary calculations. - * @param {Boolean} [cfg.castsShadow=true] Indicates if the Entity initially casts shadows. - * @param {Boolean} [cfg.receivesShadow=true] Indicates if the Entity initially receives shadows. - * @param {Boolean} [cfg.xrayed=false] Indicates if the Entity is initially xrayed. XRayed appearance is configured by {@link SceneModel#xrayMaterial}. - * @param {Boolean} [cfg.highlighted=false] Indicates if the Entity is initially highlighted. Highlighted appearance is configured by {@link SceneModel#highlightMaterial}. - * @param {Boolean} [cfg.selected=false] Indicates if the Entity is initially selected. Selected appearance is configured by {@link SceneModel#selectedMaterial}. - * @param {Boolean} [cfg.edges=false] Indicates if the Entity's edges are initially emphasized. Edges appearance is configured by {@link SceneModel#edgeMaterial}. - * @returns {Entity} - * @abstract - */ - createEntity(cfg) { - } + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); - /** - * Finalizes this SceneModel. - * - * Immediately creates the SceneModel's {@link Entity}s within the {@link Scene}. - * - * Once finalized, you can't add anything more to this SceneModel. - * @abstract - */ - finalize() { - } + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); - /** @private - * @abstract - */ - stateSortCompare(drawable1, drawable2) { - } + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } - /** @private - * @abstract - */ - drawColorOpaque(frameCtx) { - } + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - /** @private - * @abstract - */ - drawColorTransparent(frameCtx) { - } + geometry.indicesBuf.bind(); - /** @private - * @abstract - */ - drawDepth(frameCtx) { - } + gl.drawElementsInstanced(gl.LINES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - /** @private - * @abstract - */ - drawNormals(frameCtx) { - } + frameCtx.drawElements++; - /** @private - * @abstract - */ - drawSilhouetteXRayed(frameCtx) { - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - /** @private - * @abstract - */ - drawSilhouetteHighlighted(frameCtx) { - } + gl.vertexAttribDivisor(this._aColor.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); - /** @private - * @abstract - */ - drawSilhouetteSelected(frameCtx) { - } + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); + } - /** @private - * @abstract - */ - drawEdgesColorOpaque(frameCtx) { + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } } - /** @private - * @abstract - */ - drawEdgesColorTransparent(frameCtx) { - } + _allocate() { - /** @private - * @abstract - */ - drawEdgesXRayed(frameCtx) { - } + const scene = this._scene; + const gl = scene.canvas.gl; - /** @private - * @abstract - */ - drawEdgesHighlighted(frameCtx) { - } + this._program = new Program(gl, this._buildShader()); - /** @private - * @abstract - */ - drawEdgesSelected(frameCtx) { - } + if (this._program.errors) { + this.errors = this._program.errors; + return; + } - /** - * @private - * @abstract - */ - drawOcclusion(frameCtx) { - } + const program = this._program; - /** - * @private - * @abstract - */ - drawShadow(frameCtx) { - } + this._uRenderPass = program.getLocation("renderPass"); - /** @private - * @abstract - */ - drawPickMesh(frameCtx) { - } + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - /** - * Called by VBOSceneModelMesh.drawPickDepths() - * @private - * @abstract - */ - drawPickDepths(frameCtx) { - } + this._uWorldMatrix = program.getLocation("worldMatrix"); - /** - * Called by VBOSceneModelMesh.drawPickNormals() - * @private - * @abstract - */ - drawPickNormals(frameCtx) { - } + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - /** - * Destroys this SceneModel. - * @abstract - */ - destroy() { - } -} + this._uSectionPlanes = []; -class LoadingManager { + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } - constructor(onLoad, onProgress, onError) { + this._aPosition = program.getAttribute("position"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aOffset = program.getAttribute("offset"); - this.isLoading = false; - this.itemsLoaded = 0; - this.itemsTotal = 0; - this.urlModifier = undefined; - this.handlers = []; + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - this.onStart = undefined; - this.onLoad = onLoad; - this.onProgress = onProgress; - this.onError = onError; - } + this._uOcclusionTexture = "uOcclusionTexture"; - itemStart(url) { - this.itemsTotal++; - if (this.isLoading === false) { - if (this.onStart !== undefined) { - this.onStart(url, this.itemsLoaded, this.itemsTotal); - } + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } - this.isLoading = true; } - itemEnd(url) { - this.itemsLoaded++; - if (this.onProgress !== undefined) { - this.onProgress(url, this.itemsLoaded, this.itemsTotal); - } - if (this.itemsLoaded === this.itemsTotal) { - this.isLoading = false; - if (this.onLoad !== undefined) { - this.onLoad(); - } + _bindProgram() { + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; + this._program.bind(); + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } } - itemError(url) { - if (this.onError !== undefined) { - this.onError(url); - } + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - resolveURL(url) { - if (this.urlModifier) { - return this.urlModifier(url); + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines instancing color vertex shader"); + src.push("uniform int renderPass;"); + + src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - return url; - } - setURLModifier(transform) { - this.urlModifier = transform; - return this; - } + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); - addHandler(regex, loader) { - this.handlers.push(regex, loader); - return this; - } + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - removeHandler(regex) { - const index = this.handlers.indexOf(regex); - if (index !== -1) { - this.handlers.splice(index, 2); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); } - return this; - } - getHandler(file) { - for (let i = 0, l = this.handlers.length; i < l; i += 2) { - const regex = this.handlers[i]; - const loader = this.handlers[i + 1]; - if (regex.global) regex.lastIndex = 0; // see #17920 - if (regex.test(file)) { - return loader; - } + src.push("uniform vec4 lightAmbient;"); + + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - return null; - } -} + src.push("out vec4 vColor;"); -const DefaultLoadingManager = new LoadingManager(); + src.push("void main(void) {"); -class Loader { + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT - constructor(manager) { + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - this.manager = (manager !== undefined) ? manager : DefaultLoadingManager; + src.push("} else {"); - this.crossOrigin = 'anonymous'; - this.withCredentials = false; - this.path = ''; - this.resourcePath = ''; - this.requestHeader = {}; - } + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } - load( /* url, onLoad, onProgress, onError */) { - } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - loadAsync(url, onProgress) { - const scope = this; - return new Promise(function (resolve, reject) { - scope.load(url, resolve, onProgress, reject); - }); - } + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, float(color.a) / 255.0);"); - parse( /* data */) { + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + src.push("gl_Position = clipPos;"); + src.push("}"); + src.push("}"); + return src; } - setCrossOrigin(crossOrigin) { - this.crossOrigin = crossOrigin; - return this; - } + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + let i; + let len; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines instancing color fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } + src.push("in vec4 vColor;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } - setWithCredentials(value) { - this.withCredentials = value; - return this; - } + // Doing SAO blend in the main solid fill draw shader just so that edge lines can be drawn over the top + // Would be more efficient to defer this, then render lines later, using same depth buffer for Z-reject - setPath(path) { - this.path = path; - return this; + if (this._withSAO) { + src.push(" float viewportWidth = uSAOParams[0];"); + src.push(" float viewportHeight = uSAOParams[1];"); + src.push(" float blendCutoff = uSAOParams[2];"); + src.push(" float blendFactor = uSAOParams[3];"); + src.push(" vec2 uv = vec2(gl_FragCoord.x / viewportWidth, gl_FragCoord.y / viewportHeight);"); + src.push(" float ambient = smoothstep(blendCutoff, 1.0, unpackRGBAToDepth(texture(uOcclusionTexture, uv))) * blendFactor;"); + src.push(" outColor = vec4(vColor.rgb * ambient, vColor.a);"); + } else { + src.push(" outColor = vColor;"); + } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("}"); + return src; } - setResourcePath(resourcePath) { - this.resourcePath = resourcePath; - return this; + webglContextRestored() { + this._program = null; } - setRequestHeader(requestHeader) { - this.requestHeader = requestHeader; - return this; + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; } } +const tempVec3a$m = math.vec3(); + /** - * @author Deepkolos / https://github.com/deepkolos + * @private */ +class LinesInstancingSilhouetteRenderer { -class WorkerPool$1 { + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - constructor(pool = 4) { - this.pool = pool; - this.queue = []; - this.workers = []; - this.workersResolve = []; - this.workerStatus = 0; + getValid() { + return this._hash === this._getHash(); + }; + + _getHash() { + return this._scene._sectionPlanesState.getHash(); } - _initWorker(workerId) { - if (!this.workers[workerId]) { - const worker = this.workerCreator(); - worker.addEventListener('message', this._onMessage.bind(this, workerId)); - this.workers[workerId] = worker; + drawLayer(frameCtx, instancingLayer, renderPass) { + + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const geometry = instancingLayer.geometry; + + if (!this._program) { + this._allocate(instancingLayer.model.scene); + if (this.errors) { + return; + } } - } - _getIdleWorker() { - for (let i = 0; i < this.pool; i++) - if (!(this.workerStatus & (1 << i))) return i; - return -1; - } + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } + + gl.uniform1i(this._uRenderPass, renderPass); + + if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + const material = scene.xrayMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + const material = scene.selectedMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); - _onMessage(workerId, msg) { - const resolve = this.workersResolve[workerId]; - resolve && resolve(msg); - if (this.queue.length) { - const {resolve, msg, transfer} = this.queue.shift(); - this.workersResolve[workerId] = resolve; - this.workers[workerId].postMessage(msg, transfer); } else { - this.workerStatus ^= 1 << workerId; + gl.uniform4fv(this._uColor, math.vec3([1, 1, 1])); } - } - setWorkerCreator(workerCreator) { - this.workerCreator = workerCreator; - } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - setWorkerLimit(pool) { - this.pool = pool; - } + gl.lineWidth(scene.linesMaterial.lineWidth); - postMessage(msg, transfer) { - return new Promise((resolve) => { - const workerId = this._getIdleWorker(); - if (workerId !== -1) { - this._initWorker(workerId); - this.workerStatus |= 1 << workerId; - this.workersResolve[workerId] = resolve; - this.workers[workerId].postMessage(msg, transfer); - } else { - this.queue.push({resolve, msg, transfer}); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$m); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } } - }); - } + } - destroy() { + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - this.workers.forEach((worker) => worker.terminate()); - this.workersResolve.length = 0; - this.workers.length = 0; - this.queue.length = 0; - this.workerStatus = 0; + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); -} + this._aPosition.bindArrayBuffer(state.positionsBuf); -/** - * Transcodes texture data. - * - * A {@link SceneModel} configured with an appropriate TextureTranscoder will allow us to add textures from - * transcoded buffers or files. For a concrete example, see {@link VBOSceneModel}, which can be configured with - * a {@link KTX2TextureTranscoder}, which allows us to add textures from KTX2 buffers and files. - * - * @interface - */ -class TextureTranscoder { + this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags.location, 1); - /** - * Transcodes texture data from transcoded buffers into a {@link Texture2D}. - * - * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support - * multi-image textures, such as cube maps. - * @param {*} config Transcoding options. - * @param {Texture2D} texture The texture to load. - * @returns {Promise} Resolves when the texture has loaded. - */ - transcode(buffers, texture, config = {}) { - } + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } - /** - * Destroys this transcoder. - */ - destroy() { - } -} + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } -const Cache = { + geometry.indicesBuf.bind(); - enabled: false, - files: {}, + gl.drawElementsInstanced(gl.LINES, geometry.indicesBuf.numItems, geometry.indicesBuf.itemType, 0, state.numInstances); - add: function (key, file) { - if (this.enabled === false) { - return; + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + + gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - this.files[key] = file; - }, + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } + } - get: function (key) { - if (this.enabled === false) { + _allocate() { + + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; + + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; return; } - return this.files[key]; - }, - remove: function (key) { - delete this.files[key]; - }, + const program = this._program; - clear: function () { - this.files = {}; - } -}; + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uColor = program.getLocation("color"); + this._uSectionPlanes = []; -const loading = {}; + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } -class FileLoader extends Loader { + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - constructor(manager) { - super(manager); + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - load(url, onLoad, onProgress, onError) { - if (url === undefined) { - url = ''; - } - if (this.path !== undefined) { - url = this.path + url; - } - url = this.manager.resolveURL(url); - const cached = Cache.get(url); - if (cached !== undefined) { - this.manager.itemStart(url); - setTimeout(() => { - if (onLoad) { - onLoad(cached); - } - this.manager.itemEnd(url); - }, 0); - return cached; - } - if (loading[url] !== undefined) { - loading[url].push({onLoad, onProgress, onError}); - return; - } - loading[url] = []; - loading[url].push({onLoad, onProgress, onError}); - const req = new Request(url, { - headers: new Headers(this.requestHeader), - credentials: this.withCredentials ? 'include' : 'same-origin' - }); - const mimeType = this.mimeType; - const responseType = this.responseType; - fetch(req).then(response => { - if (response.status === 200 || response.status === 0) { - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. - if (response.status === 0) { - console.warn('FileLoader: HTTP Status 0 received.'); - } - if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) { - return response; - } - const callbacks = loading[url]; - const reader = response.body.getReader(); - const contentLength = response.headers.get('Content-Length'); - const total = contentLength ? parseInt(contentLength) : 0; - const lengthComputable = total !== 0; - let loaded = 0; - const stream = new ReadableStream({ - start(controller) { - readData(); + _bindProgram() { - function readData() { - reader.read().then(({done, value}) => { - if (done) { - controller.close(); - } else { - loaded += value.byteLength; - const event = new ProgressEvent('progress', {lengthComputable, loaded, total}); - for (let i = 0, il = callbacks.length; i < il; i++) { - const callback = callbacks[i]; - if (callback.onProgress) { - callback.onProgress(event); - } - } - controller.enqueue(value); - readData(); - } - }); - } - } - }); - return new Response(stream); - } else { - throw Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`); - } - }).then(response => { - switch (responseType) { - case 'arraybuffer': - return response.arrayBuffer(); - case 'blob': - return response.blob(); - case 'document': - return response.text() - .then(text => { - const parser = new DOMParser(); - return parser.parseFromString(text, mimeType); - }); - case 'json': - return response.json(); - default: - if (mimeType === undefined) { - return response.text(); - } else { - // sniff encoding - const re = /charset="?([^;"\s]*)"?/i; - const exec = re.exec(mimeType); - const label = exec && exec[1] ? exec[1].toLowerCase() : undefined; - const decoder = new TextDecoder(label); - return response.arrayBuffer().then(ab => decoder.decode(ab)); - } - } - }).then(data => { - // Add to cache only on HTTP success, so that we do not cache - // error response bodies as proper responses to requests. - Cache.add(url, data); - const callbacks = loading[url]; - delete loading[url]; - for (let i = 0, il = callbacks.length; i < il; i++) { - const callback = callbacks[i]; - if (callback.onLoad) { - callback.onLoad(data); - } - } - }).catch(err => { - // Abort errors and other errors are handled the same - const callbacks = loading[url]; - if (callbacks === undefined) { - // When onLoad was called and url was deleted in `loading` - this.manager.itemError(url); - throw err; + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - } - delete loading[url]; - for (let i = 0, il = callbacks.length; i < il; i++) { - const callback = callbacks[i]; - if (callback.onError) { - callback.onError(err); - } - } - this.manager.itemError(url); - }).finally(() => { - this.manager.itemEnd(url); - }); - this.manager.itemStart(url); - } + this._program.bind(); - setResponseType(value) { - this.responseType = value; - return this; + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } - setMimeType(value) { - this.mimeType = value; - return this; + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } -} -const KTX2TransferSRGB = 2; -const KTX2_ALPHA_PREMULTIPLIED = 1; + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines instancing silhouette vertex shader"); + src.push("uniform int renderPass;"); -let activeTranscoders = 0; + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); -/** - * Transcodes texture data from KTX2. - * - * ## Overview - * - * * Uses the [Basis Universal GPU Texture Codec](https://github.com/BinomialLLC/basis_universal) to - * transcode [KTX2](https://github.khronos.org/KTX-Specification/) textures. - * * {@link XKTLoaderPlugin} uses a KTX2TextureTranscoder to load textures in XKT files. - * * {@link VBOSceneModel} uses a KTX2TextureTranscoder to enable us to add KTX2-encoded textures. - * * Loads the Basis Codec from [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/) by default, but can - * also be configured to load the Codec from local files. - * * We also bundle the Basis Codec with the xeokit-sdk npm package, and in the [repository](https://github.com/xeokit/xeokit-sdk/tree/master/dist/basis). - * - * ## What is KTX2? - * - * A [KTX2](https://github.khronos.org/KTX-Specification/) file stores GPU texture data in the Khronos Texture 2.0 (KTX2) container format. It contains image data for - * a texture asset compressed with Basis Universal (BasisU) supercompression that can be transcoded to different formats - * depending on the support provided by the target devices. KTX2 provides a lightweight format for distributing texture - * assets to GPUs. Due to BasisU compression, KTX2 files can store any image format supported by GPUs. - * - * ## Loading XKT files containing KTX2 textures - * - * {@link XKTLoaderPlugin} uses a KTX2TextureTranscoder to load textures in XKT files. An XKTLoaderPlugin has its own - * default KTX2TextureTranscoder, configured to load the Basis Codec from the [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/). If we wish, we can override that with our own - * KTX2TextureTranscoder, configured to load the Codec locally. - * - * In the example below, we'll create a {@link Viewer} and add an {@link XKTLoaderPlugin} - * configured with a KTX2TextureTranscoder. Then we'll use the XKTLoaderPlugin to load an - * XKT file that contains KTX2 textures, which the plugin will transcode using - * its KTX2TextureTranscoder. - * - * We'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. If we were happy with loading the - * Codec from our [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/) (ie. our app will always have an Internet connection) then we could just leave out the - * KTX2TextureTranscoder altogether, and let the XKTLoaderPlugin use its internal default KTX2TextureTranscoder, which is configured to - * load the Codec from the CDN. We'll stick with loading our own Codec, in case we want to run our app without an Internet connection. - * - * - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan)] - * - * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [-2.56, 8.38, 8.27]; - * viewer.camera.look = [13.44, 3.31, -14.83]; - * viewer.camera.up = [0.10, 0.98, -0.14]; - * - * const textureTranscoder = new KTX2TextureTranscoder({ - * viewer, - * transcoderPath: "./../dist/basis/" // <------ Path to Basis Universal transcoder - * }); - * - * const xktLoader = new XKTLoaderPlugin(viewer, { - * textureTranscoder // <<------------- Transcodes KTX2 textures in XKT files - * }); - * - * const sceneModel = xktLoader.load({ - * id: "myModel", - * src: "./HousePlan.xkt" // <<------ XKT file with KTX2 textures - * }); - * ```` - * - * ## Loading KTX2 files into a VBOSceneModel - * - * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will - * allow us to load textures into it from KTX2-transcoded buffers or files. - * - * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a - * KTX2TextureTranscoder. - * - * We'll then programmatically create a simple object within the VBOSceneModel, consisting of - * a single box mesh with a texture loaded from a KTX2 file, which our VBOSceneModel internally transcodes, using - * its KTX2TextureTranscoder. - * - * As in the previous example, we'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. - * - * * [Run a similar example](http://localhost:8080/examples/sceneRepresentation_VBOSceneModel_batching_textures_ktx2.html) - * - * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * const textureTranscoder = new KTX2TextureTranscoder({ - * viewer, - * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module - * }); - * - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "myModel", - * textureTranscoder // <<-------------------- Configure model with our transcoder - * }); - * - * vboSceneModel.createTexture({ - * id: "myColorTexture", - * src: "../assets/textures/compressed/sample_uastc_zstd.ktx2" // <<----- KTX2 texture asset - * }); - * - * vboSceneModel.createTexture({ - * id: "myMetallicRoughnessTexture", - * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset - * }); - * - * vboSceneModel.createTextureSet({ - * id: "myTextureSet", - * colorTextureId: "myColorTexture", - * metallicRoughnessTextureId: "myMetallicRoughnessTexture" - * }); - * - * vboSceneModel.createMesh({ - * id: "myMesh", - * textureSetId: "myTextureSet", - * primitive: "triangles", - * positions: [1, 1, 1, ...], - * normals: [0, 0, 1, 0, ...], - * uv: [1, 0, 0, ...], - * indices: [0, 1, 2, ...], - * }); - * - * vboSceneModel.createEntity({ - * id: "myEntity", - * meshIds: ["myMesh"] - * }); - * - * vboSceneModel.finalize(); - * ```` - * - * ## Loading KTX2 ArrayBuffers into a VBOSceneModel - * - * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will also allow us to load textures into - * it from KTX2 ArrayBuffers. - * - * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a - * KTX2TextureTranscoder. - * - * We'll then programmatically create a simple object within the VBOSceneModel, consisting of - * a single mesh with a texture loaded from a KTX2 ArrayBuffer, which our VBOSceneModel internally transcodes, using - * its KTX2TextureTranscoder. - * - * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * const textureTranscoder = new KTX2TextureTranscoder({ - * viewer, - * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module - * }); - * - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "myModel", - * textureTranscoder // <<-------------------- Configure model with our transcoder - * }); - * - * utils.loadArraybuffer("../assets/textures/compressed/sample_uastc_zstd.ktx2",(arrayBuffer) => { - * - * vboSceneModel.createTexture({ - * id: "myColorTexture", - * buffers: [arrayBuffer] // <<----- KTX2 texture asset - * }); - * - * vboSceneModel.createTexture({ - * id: "myMetallicRoughnessTexture", - * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset - * }); - * - * vboSceneModel.createTextureSet({ - * id: "myTextureSet", - * colorTextureId: "myColorTexture", - * metallicRoughnessTextureId: "myMetallicRoughnessTexture" - * }); - * - * vboSceneModel.createMesh({ - * id: "myMesh", - * textureSetId: "myTextureSet", - * primitive: "triangles", - * positions: [1, 1, 1, ...], - * normals: [0, 0, 1, 0, ...], - * uv: [1, 0, 0, ...], - * indices: [0, 1, 2, ...], - * }); - * - * vboSceneModel.createEntity({ - * id: "myEntity", - * meshIds: ["myMesh"] - * }); - * - * vboSceneModel.finalize(); - * }); - * ```` - * - * @implements {TextureTranscoder} - */ -class KTX2TextureTranscoder { + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); - /** - * Creates a new KTX2TextureTranscoder. - * - * @param {Viewer} viewer The Viewer that our KTX2TextureTranscoder will be used with. This KTX2TextureTranscoder - * must only be used to transcode textures for this Viewer. This is because the Viewer's capabilities will decide - * what target GPU formats this KTX2TextureTranscoder will transcode to. - * @param {String} [transcoderPath="https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/"] Path to the Basis - * transcoder module that internally does the heavy lifting for our KTX2TextureTranscoder. If we omit this configuration, - * then our KTX2TextureTranscoder will load it from ````https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/```` by - * default. Therefore, make sure your application is connected to the internet if you wish to use the default transcoder path. - * @param {Number} [workerLimit] The maximum number of Workers to use for transcoding. - */ - constructor({viewer, transcoderPath, workerLimit}) { + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - this._transcoderPath = transcoderPath || "https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/"; - this._transcoderBinary = null; - this._transcoderPending = null; - this._workerPool = new WorkerPool$1(); - this._workerSourceURL = ''; + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - if (workerLimit) { - this._workerPool.setWorkerLimit(workerLimit); + src.push("uniform vec4 color;"); + + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - const viewerCapabilities = viewer.capabilities; + src.push("void main(void) {"); - this._workerConfig = { - astcSupported: viewerCapabilities.astcSupported, - etc1Supported: viewerCapabilities.etc1Supported, - etc2Supported: viewerCapabilities.etc2Supported, - dxtSupported: viewerCapabilities.dxtSupported, - bptcSupported: viewerCapabilities.bptcSupported, - pvrtcSupported: viewerCapabilities.pvrtcSupported - }; + // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - this._supportedFileTypes = ["xkt2"]; + src.push(`if (int(flags.y) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + src.push("gl_Position = clipPos;"); + src.push("}"); + src.push("}"); + return src; } - _init() { - if (!this._transcoderPending) { - const jsLoader = new FileLoader(); - jsLoader.setPath(this._transcoderPath); - jsLoader.setWithCredentials(this.withCredentials); - const jsContent = jsLoader.loadAsync('basis_transcoder.js'); - const binaryLoader = new FileLoader(); - binaryLoader.setPath(this._transcoderPath); - binaryLoader.setResponseType('arraybuffer'); - binaryLoader.setWithCredentials(this.withCredentials); - const binaryContent = binaryLoader.loadAsync('basis_transcoder.wasm'); - this._transcoderPending = Promise.all([jsContent, binaryContent]) - .then(([jsContent, binaryContent]) => { - const fn = KTX2TextureTranscoder.BasisWorker.toString(); - const body = [ - '/* constants */', - 'let _EngineFormat = ' + JSON.stringify(KTX2TextureTranscoder.EngineFormat), - 'let _TranscoderFormat = ' + JSON.stringify(KTX2TextureTranscoder.TranscoderFormat), - 'let _BasisFormat = ' + JSON.stringify(KTX2TextureTranscoder.BasisFormat), - '/* basis_transcoder.js */', - jsContent, - '/* worker */', - fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')) - ].join('\n'); - this._workerSourceURL = URL.createObjectURL(new Blob([body])); - this._transcoderBinary = binaryContent; - this._workerPool.setWorkerCreator(() => { - const worker = new Worker(this._workerSourceURL); - const transcoderBinary = this._transcoderBinary.slice(0); - worker.postMessage({ - type: 'init', - config: this._workerConfig, - transcoderBinary - }, [transcoderBinary]); - return worker; - }); - }); - if (activeTranscoders > 0) { - console.warn('KTX2TextureTranscoder: Multiple active KTX2TextureTranscoder may cause performance issues.' + ' Use a single KTX2TextureTranscoder instance, or call .dispose() on old instances.'); + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Lines instancing silhouette fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } - activeTranscoders++; } - return this._transcoderPending; + src.push("uniform vec4 color;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("outColor = color;"); + src.push("}"); + return src; } - /** - * Transcodes texture data from transcoded buffers into a {@link Texture2D}. - * - * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support multi-image textures, such as cube maps. - * @param {*} config Transcoding options. - * @param {Texture2D} texture The texture to load. - * @returns {Promise} Resolves when the texture has loaded. - */ - transcode(buffers, texture, config = {}) { - return new Promise((resolve, reject) => { - const taskConfig = config; - this._init().then(() => { - return this._workerPool.postMessage({ - type: 'transcode', - buffers, - taskConfig: taskConfig - }, buffers); - }).then((e) => { - const transcodeResult = e.data; - const {mipmaps, width, height, format, type, error, dfdTransferFn, dfdFlags} = transcodeResult; - if (type === 'error') { - return reject(error); - } - texture.setCompressedData({ - mipmaps, - props: { - format: format, - minFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter, - magFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter, - encoding: dfdTransferFn === KTX2TransferSRGB ? sRGBEncoding : LinearEncoding, - premultiplyAlpha: !!(dfdFlags & KTX2_ALPHA_PREMULTIPLIED) - } - }); - resolve(); - }); - }); + webglContextRestored() { + this._program = null; } - /** - * Destroys this KTX2TextureTranscoder - */ destroy() { - URL.revokeObjectURL(this._workerSourceURL); - this._workerPool.destroy(); - activeTranscoders--; + if (this._program) { + this._program.destroy(); + } + this._program = null; } } /** * @private */ -KTX2TextureTranscoder.BasisFormat = { - ETC1S: 0, - UASTC_4x4: 1 -}; +class LinesInstancingRenderers { -/** - * @private - */ -KTX2TextureTranscoder.TranscoderFormat = { - ETC1: 0, - ETC2: 1, - BC1: 2, - BC3: 3, - BC4: 4, - BC5: 5, - BC7_M6_OPAQUE_ONLY: 6, - BC7_M5: 7, - PVRTC1_4_RGB: 8, - PVRTC1_4_RGBA: 9, - ASTC_4x4: 10, - ATC_RGB: 11, - ATC_RGBA_INTERPOLATED_ALPHA: 12, - RGBA32: 13, - RGB565: 14, - BGR565: 15, - RGBA4444: 16 -}; + constructor(scene) { + this._scene = scene; + } + + _compile() { + if (this._colorRenderer && (!this._colorRenderer.getValid())) { + this._colorRenderer.destroy(); + this._colorRenderer = null; + } + if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { + this._silhouetteRenderer.destroy(); + this._silhouetteRenderer = null; + } + } + + get colorRenderer() { + if (!this._colorRenderer) { + this._colorRenderer = new LinesInstancingColorRenderer(this._scene); + } + return this._colorRenderer; + } + + get silhouetteRenderer() { + if (!this._silhouetteRenderer) { + this._silhouetteRenderer = new LinesInstancingSilhouetteRenderer(this._scene); + } + return this._silhouetteRenderer; + } + + _destroy() { + if (this._colorRenderer) { + this._colorRenderer.destroy(); + } + if (this._silhouetteRenderer) { + this._silhouetteRenderer.destroy(); + } + } +} + +const cachedRenderers$2 = {}; /** * @private */ -KTX2TextureTranscoder.EngineFormat = { - RGBAFormat: RGBAFormat, - RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, - RGBA_BPTC_Format: RGBA_BPTC_Format, - RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, - RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, - RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, - RGB_ETC1_Format: RGB_ETC1_Format, - RGB_ETC2_Format: RGB_ETC2_Format, - RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, - RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format -}; +function getInstancingRenderers(scene) { + const sceneId = scene.id; + let instancingRenderers = cachedRenderers$2[sceneId]; + if (!instancingRenderers) { + instancingRenderers = new LinesInstancingRenderers(scene); + cachedRenderers$2[sceneId] = instancingRenderers; + instancingRenderers._compile(); + scene.on("compile", () => { + instancingRenderers._compile(); + }); + scene.on("destroyed", () => { + delete cachedRenderers$2[sceneId]; + instancingRenderers._destroy(); + }); + } + return instancingRenderers; +} -/* WEB WORKER */ +const tempUint8Vec4$1 = new Uint8Array(4); + +const tempVec4a$7 = math.vec4([0, 0, 0, 1]); +const tempVec4b$7 = math.vec4([0, 0, 0, 1]); +const tempVec4c$4 = math.vec4([0, 0, 0, 1]); + +const tempVec3fa$1 = new Float32Array(3); /** * @private - * @constructor */ -KTX2TextureTranscoder.BasisWorker = function () { +class LinesInstancingLayer { - let config; - let transcoderPending; - let BasisModule; + /** + * @param cfg + * @param cfg.layerIndex + * @param cfg.model + * @param cfg.geometry + * @param cfg.material + * @param cfg.origin + */ + constructor(cfg) { - const EngineFormat = _EngineFormat; // eslint-disable-line no-undef - const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef - const BasisFormat = _BasisFormat; // eslint-disable-line no-undef + /** + * Owner model + * @type {VBOSceneModel} + */ + this.model = cfg.model; - self.addEventListener('message', function (e) { - const message = e.data; - switch (message.type) { - case 'init': - config = message.config; - init(message.transcoderBinary); - break; - case 'transcode': - transcoderPending.then(() => { - try { - const { - width, - height, - hasAlpha, - mipmaps, - format, - dfdTransferFn, - dfdFlags - } = transcode(message.buffers[0]); - const buffers = []; - for (let i = 0; i < mipmaps.length; ++i) { - buffers.push(mipmaps[i].data.buffer); - } - self.postMessage({ - type: 'transcode', - id: message.id, - width, - height, - hasAlpha, - mipmaps, - format, - dfdTransferFn, - dfdFlags - }, buffers); - } catch (error) { - console.error(`[KTX2TextureTranscoder.BasisWorker]: ${error}`); - self.postMessage({type: 'error', id: message.id, error: error.message}); - } - }); - break; - } - }); + /** + * Shared geometry + * @type {VBOSceneModelGeometry} + */ + this.geometry = cfg.geometry; - function init(wasmBinary) { - transcoderPending = new Promise(resolve => { - BasisModule = { - wasmBinary, - onRuntimeInitialized: resolve - }; - BASIS(BasisModule); // eslint-disable-line no-undef - }).then(() => { - BasisModule.initializeBasis(); - if (BasisModule.KTX2File === undefined) { - console.warn('KTX2TextureTranscoder: Please update Basis Universal transcoder.'); - } + /** + * Shared material + * @type {VBOSceneModelGeometry} + */ + this.material = cfg.material; + + /** + * State sorting key. + * @type {string} + */ + this.sortId = "LinesInstancingLayer"; + + /** + * Index of this InstancingLayer in VBOSceneModel#_layerList + * @type {Number} + */ + this.layerIndex = cfg.layerIndex; + + this._linesInstancingRenderers = getInstancingRenderers(cfg.model.scene); + + this._aabb = math.collapseAABB3(); + + this._state = new RenderState({ + obb: math.OBB3(), + numInstances: 0, + origin: null }); - } - function transcode(buffer) { - const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer)); + // These counts are used to avoid unnecessary render passes + this._numPortions = 0; + this._numVisibleLayerPortions = 0; + this._numTransparentLayerPortions = 0; + this._numXRayedLayerPortions = 0; + this._numHighlightedLayerPortions = 0; + this._numSelectedLayerPortions = 0; + this._numClippableLayerPortions = 0; + this._numEdgesLayerPortions = 0; + this._numPickableLayerPortions = 0; + this._numCulledLayerPortions = 0; - function cleanup() { - ktx2File.close(); - ktx2File.delete(); - } + /** @private */ + this.numIndices = cfg.geometry.numIndices; - if (!ktx2File.isValid()) { - cleanup(); - throw new Error('KTX2TextureTranscoder: Invalid or unsupported .ktx2 file'); - } - const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S; - const width = ktx2File.getWidth(); - const height = ktx2File.getHeight(); - const levels = ktx2File.getLevels(); - const hasAlpha = ktx2File.getHasAlpha(); - const dfdTransferFn = ktx2File.getDFDTransferFunc(); - const dfdFlags = ktx2File.getDFDFlags(); - const {transcoderFormat, engineFormat} = getTranscoderFormat(basisFormat, width, height, hasAlpha); - if (!width || !height || !levels) { - cleanup(); - throw new Error('KTX2TextureTranscoder: Invalid texture'); - } - if (!ktx2File.startTranscoding()) { - cleanup(); - throw new Error('KTX2TextureTranscoder: .startTranscoding failed'); - } - const mipmaps = []; - for (let mip = 0; mip < levels; mip++) { - const levelInfo = ktx2File.getImageLevelInfo(mip, 0, 0); - const mipWidth = levelInfo.origWidth; - const mipHeight = levelInfo.origHeight; - const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, 0, 0, transcoderFormat)); - const status = ktx2File.transcodeImage(dst, mip, 0, 0, transcoderFormat, 0, -1, -1); - if (!status) { - cleanup(); - throw new Error('KTX2TextureTranscoder: .transcodeImage failed.'); - } - mipmaps.push({data: dst, width: mipWidth, height: mipHeight}); - } - cleanup(); - return {width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags}; - } + // Vertex arrays + this._colors = []; + this._offsets = []; - // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC), - // device capabilities, and texture dimensions. The list below ranks the formats separately - // for ETC1S and UASTC. - // - // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at - // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently - // chooses RGBA32 only as a last resort and does not expose that option to the caller. + // Modeling matrix per instance, array for each column + this._modelMatrixCol0 = []; + this._modelMatrixCol1 = []; + this._modelMatrixCol2 = []; - const FORMAT_OPTIONS = [{ - if: 'astcSupported', - basisFormat: [BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], - engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], - priorityETC1S: Infinity, - priorityUASTC: 1, - needsPowerOfTwo: false - }, { - if: 'bptcSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], - engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], - priorityETC1S: 3, - priorityUASTC: 2, - needsPowerOfTwo: false - }, { - if: 'dxtSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], - engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], - priorityETC1S: 4, - priorityUASTC: 5, - needsPowerOfTwo: false - }, { - if: 'etc2Supported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], - engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], - priorityETC1S: 1, - priorityUASTC: 3, - needsPowerOfTwo: false - }, { - if: 'etc1Supported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.ETC1], - engineFormat: [EngineFormat.RGB_ETC1_Format], - priorityETC1S: 2, - priorityUASTC: 4, - needsPowerOfTwo: false - }, { - if: 'pvrtcSupported', - basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], - transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], - engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], - priorityETC1S: 5, - priorityUASTC: 6, - needsPowerOfTwo: true - }]; - const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { - return a.priorityETC1S - b.priorityETC1S; - }); - const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { - return a.priorityUASTC - b.priorityUASTC; - }); + this._portions = []; - function getTranscoderFormat(basisFormat, width, height, hasAlpha) { - let transcoderFormat; - let engineFormat; - const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS; - for (let i = 0; i < options.length; i++) { - const opt = options[i]; - if (!config[opt.if]) continue; - if (!opt.basisFormat.includes(basisFormat)) continue; - if (hasAlpha && opt.transcoderFormat.length < 2) continue; - if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue; - transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0]; - engineFormat = opt.engineFormat[hasAlpha ? 1 : 0]; - return { - transcoderFormat, - engineFormat - }; + if (cfg.origin) { + this._state.origin = math.vec3(cfg.origin); } - console.warn('KTX2TextureTranscoder: No suitable compressed texture format found. Decoding to RGBA32.'); - transcoderFormat = TranscoderFormat.RGBA32; - engineFormat = EngineFormat.RGBAFormat; - return { - transcoderFormat, - engineFormat - }; - } - function isPowerOfTwo(value) { - if (value <= 2) return true; - return (value & value - 1) === 0 && value !== 0; + this._finalized = false; + + /** + * The axis-aligned World-space boundary of this InstancingLayer's positions. + * @type {*|Float64Array} + */ + this.aabb = math.collapseAABB3(); } -}; -const cachedTranscoders = {}; + /** + * Creates a new portion within this InstancingLayer, returns the new portion ID. + * + * The portion will instance this InstancingLayer's geometry. + * + * Gives the portion the specified color and matrix. + * + * @param cfg Portion params + * @param cfg.color Color [0..255,0..255,0..255] + * @param cfg.opacity Opacity [0..255]. + * @param cfg.meshMatrix Flat float 4x4 matrix. + * @param [cfg.worldMatrix] Flat float 4x4 matrix. + * @param cfg.aabb Flat float AABB. + * @returns {number} Portion ID. + */ + createPortion(cfg) { -/** - * Returns a new {@link KTX2TextureTranscoder}. - * - * The ````transcoderPath```` config will be set to: "https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/" - * - * @private - */ -function getKTX2TextureTranscoder(viewer) { - const sceneId = viewer.scene.id; - let transcoder = cachedTranscoders[sceneId]; - if (!transcoder) { - transcoder = new KTX2TextureTranscoder({viewer}); - cachedTranscoders[sceneId] = transcoder; - viewer.scene.on("destroyed", () => { - delete cachedTranscoders[sceneId]; - transcoder.destroy(); - }); - } - return transcoder; -} + const color = cfg.color; + const opacity = cfg.opacity; + const meshMatrix = cfg.meshMatrix; + const worldMatrix = cfg.worldMatrix; + const worldAABB = cfg.aabb; -const tempVec3a$9 = math.vec3(); -const tempMat4$1 = math.mat4(); + if (this._finalized) { + throw "Already finalized"; + } -const defaultScale = math.vec3([1, 1, 1]); -const defaultPosition = math.vec3([0, 0, 0]); -const defaultRotation = math.vec3([0, 0, 0]); -const defaultQuaternion = math.identityQuaternion(); + // TODO: find AABB for portion by transforming the geometry local AABB by the given meshMatrix? -const defaultColorTextureId = "defaultColorTexture"; -const defaultMetalRoughTextureId = "defaultMetalRoughTexture"; -const defaultNormalsTextureId = "defaultNormalsTexture"; -const defaultEmissiveTextureId = "defaultEmissiveTexture"; -const defaultOcclusionTextureId = "defaultOcclusionTexture"; -const defaultTextureSetId = "defaultTextureSet"; + const r = color[0]; // Color is pre-quantized by VBOSceneModel + const g = color[1]; + const b = color[2]; + color[3]; -/** - * @desc A high-performance model representation for efficient rendering and low memory usage. - * - * # Examples - * - * * [VBOSceneModel using geometry batching](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) - * * [VBOSceneModel using geometry batching and RTC coordinates](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching_origin) - * * [VBOSceneModel using geometry instancing](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing) - * * [VBOSceneModel using geometry instancing and RTC coordinates](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing_origin) - * - * # Overview - * - * While xeokit's standard [scene graph](https://github.com/xeokit/xeokit-sdk/wiki/Scene-Graphs) is great for gizmos and medium-sized models, it doesn't scale up to millions of objects in terms of memory and rendering efficiency. - * - * For huge models, we have the ````VBOSceneModel```` representation, which is optimized to pack large amounts of geometry into memory and render it efficiently using WebGL. - * - * ````VBOSceneModel```` is the default model representation loaded by (at least) {@link GLTFLoaderPlugin}, {@link XKTLoaderPlugin} and {@link WebIFCLoaderPlugin}. - * - * In this tutorial you'll learn how to use ````VBOSceneModel```` to create high-detail content programmatically. Ordinarily you'd be learning about ````VBOSceneModel```` if you were writing your own model loader plugins. - * - * # Contents - * - * - [VBOSceneModel](#performancemodel) - * - [GPU-Resident Geometry](#gpu-resident-geometry) - * - [Picking](#picking) - * - [Example 1: Geometry Instancing](#example-1--geometry-instancing) - * - [Finalizing a VBOSceneModel](#finalizing-a-performancemodel) - * - [Finding Entities](#finding-entities) - * - [Example 2: Geometry Batching](#example-2--geometry-batching) - * - [Classifying with Metadata](#classifying-with-metadata) - * - [Querying Metadata](#querying-metadata) - * - [Metadata Structure](#metadata-structure) - * - [RTC Coordinates](#rtc-coordinates-for-double-precision) - * - [Example 3: RTC Coordinates with Geometry Instancing](#example-2--rtc-coordinates-with-geometry-instancing) - * - [Example 4: RTC Coordinates with Geometry Batching](#example-2--rtc-coordinates-with-geometry-batching) - * - * ## VBOSceneModel - * - * ````VBOSceneModel```` uses two rendering techniques internally: - * - * 1. ***Geometry batching*** for unique geometries, combining those into a single WebGL geometry buffer, to render in one draw call, and - * 2. ***geometry instancing*** for geometries that are shared by multiple meshes, rendering all instances of each shared geometry in one draw call. - * - *
- * These techniques come with certain limitations: - * - * * Non-realistic rendering - while scene graphs can use xeokit's full set of material workflows, ````VBOSceneModel```` uses simple Lambertian shading without textures. - * * Static transforms - transforms within a ````VBOSceneModel```` are static and cannot be dynamically translated, rotated and scaled the way {@link Node}s and {@link Mesh}es in scene graphs can. - * * Immutable model representation - while scene graph {@link Node}s and - * {@link Mesh}es can be dynamically plugged together, ````VBOSceneModel```` is immutable, - * since it packs its geometries into buffers and instanced arrays. - * - * ````VBOSceneModel````'s API allows us to exploit batching and instancing, while exposing its elements as - * abstract {@link Entity} types. - * - * {@link Entity} is the abstract base class for - * the various xeokit components that represent models, objects, or anonymous visible elements. An Entity has a unique ID and can be - * individually shown, hidden, selected, highlighted, ghosted, culled, picked and clipped, and has its own World-space boundary. - * - * * A ````VBOSceneModel```` is an {@link Entity} that represents a model. - * * A ````VBOSceneModel```` represents each of its objects with an {@link Entity}. - * * Each {@link Entity} has one or more meshes that define its shape. - * * Each mesh has either its own unique geometry, or shares a geometry with other meshes. - * - * ## GPU-Resident Geometry - * - * For a low memory footprint, ````VBOSceneModel```` stores its geometries in GPU memory only, compressed (quantized) as integers. Unfortunately, GPU-resident geometry is - * not readable by JavaScript. - * - * - * ## Example 1: Geometry Instancing - * - * In the example below, we'll use a ````VBOSceneModel```` - * to build a simple table model using geometry instancing. - * - * We'll start by adding a reusable box-shaped geometry to our ````VBOSceneModel````. - * - * Then, for each object in our model we'll add an {@link Entity} - * that has a mesh that instances our box geometry, transforming and coloring the instance. - * - * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing) - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing)] - * - * ````javascript - * import {Viewer, VBOSceneModel} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * // Build a VBOSceneModel representing a table - * // with four legs, using geometry instancing - * - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "table", - * isModel: true, // <--- Registers VBOSceneModel in viewer.scene.models - * position: [0, 0, 0], - * scale: [1, 1, 1], - * rotation: [0, 0, 0] - * }); - * - * // Create a reusable geometry within the VBOSceneModel - * // We'll instance this geometry by five meshes - * - * vboSceneModel.createGeometry({ - * - * id: "myBoxGeometry", - * - * // The primitive type - allowed values are "points", "lines" and "triangles". - * // See the OpenGL/WebGL specification docs - * // for how the coordinate arrays are supposed to be laid out. - * primitive: "triangles", - * - * // The vertices - eight for our cube, each - * // one spanning three array elements for X,Y and Z - * positions: [ - * 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // v0-v1-v2-v3 front - * 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // v0-v3-v4-v1 right - * 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // v0-v1-v6-v1 top - * -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // v1-v6-v7-v2 left - * -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, // v7-v4-v3-v2 bottom - * 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 // v4-v7-v6-v1 back - * ], - * - * // Normal vectors, one for each vertex - * normals: [ - * 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front - * 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right - * 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top - * -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left - * 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // v7-v4-v3-v2 bottom - * 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1 // v4-v7-v6-v5 back - * ], - * - * // Indices - these organise the positions and and normals - * // into geometric primitives in accordance with the "primitive" parameter, - * // in this case a set of three indices for each triangle. - * // - * // Note that each triangle is specified in counter-clockwise winding order. - * // - * indices: [ - * 0, 1, 2, 0, 2, 3, // front - * 4, 5, 6, 4, 6, 7, // right - * 8, 9, 10, 8, 10, 11, // top - * 12, 13, 14, 12, 14, 15, // left - * 16, 17, 18, 16, 18, 19, // bottom - * 20, 21, 22, 20, 22, 23 - * ] - * }); - * - * // Red table leg - * - * vboSceneModel.createMesh({ - * id: "redLegMesh", - * geometryId: "myBoxGeometry", - * position: [-4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1, 0.3, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * id: "redLeg", - * meshIds: ["redLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Green table leg - * - * vboSceneModel.createMesh({ - * id: "greenLegMesh", - * geometryId: "myBoxGeometry", - * position: [4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 1.0, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * id: "greenLeg", - * meshIds: ["greenLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Blue table leg - * - * vboSceneModel.createMesh({ - * id: "blueLegMesh", - * geometryId: "myBoxGeometry", - * position: [4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * id: "blueLeg", - * meshIds: ["blueLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Yellow table leg - * - * vboSceneModel.createMesh({ - * id: "yellowLegMesh", - * geometryId: "myBoxGeometry", - * position: [-4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1.0, 1.0, 0.0] - * }); - * - * vboSceneModel.createEntity({ - * id: "yellowLeg", - * meshIds: ["yellowLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Purple table top - * - * vboSceneModel.createMesh({ - * id: "purpleTableTopMesh", - * geometryId: "myBoxGeometry", - * position: [0, -3, 0], - * scale: [6, 0.5, 6], - * rotation: [0, 0, 0], - * color: [1.0, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * id: "purpleTableTop", - * meshIds: ["purpleTableTopMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * ```` - * - * ## Finalizing a VBOSceneModel - * - * Before we can view and interact with our ````VBOSceneModel````, we need to **finalize** it. Internally, this causes the ````VBOSceneModel```` to build the - * vertex buffer objects (VBOs) that support our geometry instances. When using geometry batching (see next example), - * this causes ````VBOSceneModel```` to build the VBOs that combine the batched geometries. Note that you can do both instancing and - * batching within the same ````VBOSceneModel````. - * - * Once finalized, we can't add anything more to our ````VBOSceneModel````. - * - * ```` javascript - * vboSceneModel.finalize(); - * ```` - * - * ## Finding Entities - * - * As mentioned earlier, {@link Entity} is - * the abstract base class for components that represent models, objects, or just - * anonymous visible elements. - * - * Since we created configured our ````VBOSceneModel```` with ````isModel: true````, - * we're able to find it as an Entity by ID in ````viewer.scene.models````. Likewise, since - * we configured each of its Entities with ````isObject: true````, we're able to - * find them in ````viewer.scene.objects````. - * - * - * ````javascript - * // Get the whole table model Entity - * const table = viewer.scene.models["table"]; - * - * // Get some leg object Entities - * const redLeg = viewer.scene.objects["redLeg"]; - * const greenLeg = viewer.scene.objects["greenLeg"]; - * const blueLeg = viewer.scene.objects["blueLeg"]; - * ```` - * - * ## Example 2: Geometry Batching - * - * Let's once more use a ````VBOSceneModel```` - * to build the simple table model, this time exploiting geometry batching. - * - * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching)] - * - * ````javascript - * import {Viewer, VBOSceneModel} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * // Create a VBOSceneModel representing a table with four legs, using geometry batching - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "table", - * isModel: true, // <--- Registers VBOSceneModel in viewer.scene.models - * position: [0, 0, 0], - * scale: [1, 1, 1], - * rotation: [0, 0, 0] - * }); - * - * // Red table leg - * - * vboSceneModel.createMesh({ - * id: "redLegMesh", - * - * // Geometry arrays are same as for the earlier batching example - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [-4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1, 0.3, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * id: "redLeg", - * meshIds: ["redLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Green table leg - * - * vboSceneModel.createMesh({ - * id: "greenLegMesh", - * primitive: "triangles", - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 1.0, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * id: "greenLeg", - * meshIds: ["greenLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Blue table leg - * - * vboSceneModel.createMesh({ - * id: "blueLegMesh", - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * id: "blueLeg", - * meshIds: ["blueLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Yellow table leg object - * - * vboSceneModel.createMesh({ - * id: "yellowLegMesh", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [-4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1.0, 1.0, 0.0] - * }); - * - * vboSceneModel.createEntity({ - * id: "yellowLeg", - * meshIds: ["yellowLegMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Purple table top - * - * vboSceneModel.createMesh({ - * id: "purpleTableTopMesh", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [0, -3, 0], - * scale: [6, 0.5, 6], - * rotation: [0, 0, 0], - * color: [1.0, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * id: "purpleTableTop", - * meshIds: ["purpleTableTopMesh"], - * isObject: true // <---- Registers Entity by ID on viewer.scene.objects - * }); - * - * // Finalize the VBOSceneModel. - * - * vboSceneModel.finalize(); - * - * // Find BigModelNodes by their model and object IDs - * - * // Get the whole table model - * const table = viewer.scene.models["table"]; - * - * // Get some leg objects - * const redLeg = viewer.scene.objects["redLeg"]; - * const greenLeg = viewer.scene.objects["greenLeg"]; - * const blueLeg = viewer.scene.objects["blueLeg"]; - * ```` - * - * ## Classifying with Metadata - * - * In the previous examples, we used ````VBOSceneModel```` to build - * two versions of the same table model, to demonstrate geometry batching and geometry instancing. - * - * We'll now classify our {@link Entity}s with metadata. This metadata - * will work the same for both our examples, since they create the exact same structure of {@link Entity}s - * to represent their models and objects. The abstract Entity type is, after all, intended to provide an abstract interface through which differently-implemented scene content can be accessed uniformly. - * - * To create the metadata, we'll create a {@link MetaModel} for our model, - * with a {@link MetaObject} for each of it's objects. The MetaModel and MetaObjects - * get the same IDs as the {@link Entity}s that represent their model and objects within our scene. - * - * ```` javascript - * const furnitureMetaModel = viewer.metaScene.createMetaModel("furniture", { // Creates a MetaModel in the MetaScene - * - * "projectId": "myTableProject", - * "revisionId": "V1.0", - * - * "metaObjects": [ - * { // Creates a MetaObject in the MetaModel - * "id": "table", - * "name": "Table", // Same ID as an object Entity - * "type": "furniture", // Arbitrary type, could be IFC type - * "properties": { // Arbitrary properties, could be IfcPropertySet - * "cost": "200" - * } - * }, - * { - * "id": "redLeg", - * "name": "Red table Leg", - * "type": "leg", - * "parent": "table", // References first MetaObject as parent - * "properties": { - * "material": "wood" - * } - * }, - * { - * "id": "greenLeg", // Node with corresponding id does not need to exist - * "name": "Green table leg", // and MetaObject does not need to exist for Node with an id - * "type": "leg", - * "parent": "table", - * "properties": { - * "material": "wood" - * } - * }, - * { - * "id": "blueLeg", - * "name": "Blue table leg", - * "type": "leg", - * "parent": "table", - * "properties": { - * "material": "wood" - * } - * }, - * { - * "id": "yellowLeg", - * "name": "Yellow table leg", - * "type": "leg", - * "parent": "table", - * "properties": { - * "material": "wood" - * } - * }, - * { - * "id": "tableTop", - * "name": "Purple table top", - * "type": "surface", - * "parent": "table", - * "properties": { - * "material": "formica", - * "width": "60", - * "depth": "60", - * "thickness": "5" - * } - * } - * ] - * }); - * ```` - * - * ## Querying Metadata - * - * Having created and classified our model (either the instancing or batching example), we can now find the {@link MetaModel} - * and {@link MetaObject}s using the IDs of their - * corresponding {@link Entity}s. - * - * ````JavaScript - * const furnitureMetaModel = scene.metaScene.metaModels["furniture"]; - * - * const redLegMetaObject = scene.metaScene.metaObjects["redLeg"]; - * ```` - * - * In the snippet below, we'll log metadata on each {@link Entity} we click on: - * - * ````JavaScript - * viewer.scene.input.on("mouseclicked", function (coords) { - * - * const hit = viewer.scene.pick({ - * canvasPos: coords - * }); - * - * if (hit) { - * const entity = hit.entity; - * const metaObject = viewer.metaScene.metaObjects[entity.id]; - * if (metaObject) { - * console.log(JSON.stringify(metaObject.getJSON(), null, "\t")); - * } - * } - * }); - * ```` - * - * ## Metadata Structure - * - * The {@link MetaModel} - * organizes its {@link MetaObject}s in - * a tree that describes their structural composition: - * - * ````JavaScript - * // Get metadata on the root object - * const tableMetaObject = furnitureMetaModel.rootMetaObject; - * - * // Get metadata on the leg objects - * const redLegMetaObject = tableMetaObject.children[0]; - * const greenLegMetaObject = tableMetaObject.children[1]; - * const blueLegMetaObject = tableMetaObject.children[2]; - * const yellowLegMetaObject = tableMetaObject.children[3]; - * ```` - * - * Given an {@link Entity}, we can find the object or model of which it is a part, or the objects that comprise it. We can also generate UI - * components from the metadata, such as the tree view demonstrated in [this demo](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_glTF_OTCConferenceCenter). - * - * This hierarchy allows us to express the hierarchical structure of a model while representing it in - * various ways in the 3D scene (such as with ````VBOSceneModel````, which - * has a non-hierarchical scene representation). - * - * Note also that a {@link MetaObject} does not need to have a corresponding - * {@link Entity} and vice-versa. - * - * # RTC Coordinates for Double Precision - * - * ````VBOSceneModel```` can emulate 64-bit precision on GPUs using relative-to-center (RTC) coordinates. - * - * Consider a model that contains many small objects, but with such large spatial extents that 32 bits of GPU precision (accurate to ~7 digits) will not be sufficient to render all of the the objects without jittering. - * - * To prevent jittering, we could spatially subdivide the objects into "tiles". Each tile would have a center position, and the positions of the objects within the tile would be relative to that center ("RTC coordinates"). - * - * While the center positions of the tiles would be 64-bit values, the object positions only need to be 32-bit. - * - * Internally, when rendering an object with RTC coordinates, xeokit first temporarily translates the camera viewing matrix by the object's tile's RTC center, on the CPU, using 64-bit math. - * - * Then xeokit loads the viewing matrix into its WebGL shaders, where math happens at 32-bit precision. Within the shaders, the matrix is effectively down-cast to 32-bit precision, and the object's 32-bit vertex positions are transformed by the matrix. - * - * We see no jittering, because with RTC a detectable loss of GPU accuracy only starts happening to objects as they become very distant from the camera viewpoint, at which point they are too small to be discernible anyway. - * - * ## RTC Coordinates with Geometry Instancing - * - * To use RTC with ````VBOSceneModel```` geometry instancing, we specify an RTC center for the geometry via its ````origin```` parameter. Then ````VBOSceneModel```` assumes that all meshes that instance that geometry are within the same RTC coordinate system, ie. the meshes ````position```` and ````rotation```` properties are assumed to be relative to the geometry's ````origin````. - * - * For simplicity, our example's meshes all instance the same geometry. Therefore, our example model has only one RTC center. - * - * Note that the axis-aligned World-space boundary (AABB) of our model is ````[ -6, -9, -6, 1000000006, -2.5, 1000000006]````. - * - * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing_origin)] - * - * ````javascript - * const origin = [100000000, 0, 100000000]; - * - * vboSceneModel.createGeometry({ - * id: "box", - * origin: origin, // This geometry's positions, and the transforms of all meshes that instance the geometry, are relative to the RTC center - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * }); - * - * vboSceneModel.createMesh({ - * id: "leg1", - * geometryId: "box", - * position: [-4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1, 0.3, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg1"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg2", - * geometryId: "box", - * position: [4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 1.0, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg2"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg3", - * geometryId: "box", - * position: [4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg3"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg4", - * geometryId: "box", - * position: [-4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1.0, 1.0, 0.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg4"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "top", - * geometryId: "box", - * position: [0, -3, 0], - * scale: [6, 0.5, 6], - * rotation: [0, 0, 0], - * color: [1.0, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["top"], - * isObject: true - * }); - * ```` - * - * ## RTC Coordinates with Geometry Batching - * - * To use RTC with ````VBOSceneModel```` geometry batching, we specify an RTC center (````origin````) for each mesh. For performance, we try to have as many meshes share the same value for ````origin```` as possible. Each mesh's ````positions````, ````position```` and ````rotation```` properties are assumed to be relative to ````origin````. - * - * For simplicity, the meshes in our example all share the same RTC center. - * - * The axis-aligned World-space boundary (AABB) of our model is ````[ -6, -9, -6, 1000000006, -2.5, 1000000006]````. - * - * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching_origin)] - * - * ````javascript - * const origin = [100000000, 0, 100000000]; - * - * vboSceneModel.createMesh({ - * id: "leg1", - * origin: origin, // This mesh's positions and transforms are relative to the RTC center - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [-4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1, 0.3, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg1"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg2", - * origin: origin, // This mesh's positions and transforms are relative to the RTC center - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 1.0, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg2"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg3", - * origin: origin, // This mesh's positions and transforms are relative to the RTC center - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg3"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg4", - * origin: origin, // This mesh's positions and transforms are relative to the RTC center - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [-4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1.0, 1.0, 0.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg4"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "top", - * origin: origin, // This mesh's positions and transforms are relative to the RTC center - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * position: [0, -3, 0], - * scale: [6, 0.5, 6], - * rotation: [0, 0, 0], - * color: [1.0, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["top"], - * isObject: true - * }); - * ```` - * - * ## Positioning at World-space coordinates - * - * To position a VBOSceneModel at given double-precision World coordinates, we can - * configure the ````origin```` of the VBOSceneModel itself. The ````origin```` is a double-precision - * 3D World-space position at which the VBOSceneModel will be located. - * - * Note that ````position```` is a single-precision offset relative to ````origin````. - * - * ````javascript - * const origin = [100000000, 0, 100000000]; - * - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "table", - * isModel: true, - * origin: origin, // Everything in this VBOSceneModel is relative to this RTC center - * position: [0, 0, 0], - * scale: [1, 1, 1], - * rotation: [0, 0, 0] - * }); - * - * vboSceneModel.createGeometry({ - * id: "box", - * primitive: "triangles", - * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], - * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], - * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], - * }); - * - * vboSceneModel.createMesh({ - * id: "leg1", - * geometryId: "box", - * position: [-4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1, 0.3, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg1"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg2", - * geometryId: "box", - * position: [4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 1.0, 0.3] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg2"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg3", - * geometryId: "box", - * position: [4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [0.3, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg3"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "leg4", - * geometryId: "box", - * position: [-4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * color: [1.0, 1.0, 0.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["leg4"], - * isObject: true - * }); - * - * vboSceneModel.createMesh({ - * id: "top", - * geometryId: "box", - * position: [0, -3, 0], - * scale: [6, 0.5, 6], - * rotation: [0, 0, 0], - * color: [1.0, 0.3, 1.0] - * }); - * - * vboSceneModel.createEntity({ - * meshIds: ["top"], - * isObject: true - * }); - * ```` - * - * # Textures - * - * ## Loading KTX2 Texture Files into a VBOSceneModel - * - * A {@link VBOSceneModel} that is configured with a {@link KTX2TextureTranscoder} will - * allow us to load textures into it from KTX2 buffers or files. - * - * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a - * {@link KTX2TextureTranscoder}. We'll then programmatically create a simple object within the VBOSceneModel, consisting of - * a single mesh with a texture loaded from a KTX2 file, which our VBOSceneModel internally transcodes, using - * its {@link KTX2TextureTranscoder}. Note how we configure our {@link KTX2TextureTranscoder} with a path to the Basis Universal - * transcoder WASM module. - * - * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * const textureTranscoder = new KTX2TextureTranscoder({ - * viewer, - * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module - * }); - * - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "myModel", - * textureTranscoder // <<-------------------- Configure model with our transcoder - * }); - * - * vboSceneModel.createTexture({ - * id: "myColorTexture", - * src: "../assets/textures/compressed/sample_uastc_zstd.ktx2" // <<----- KTX2 texture asset - * }); - * - * vboSceneModel.createTexture({ - * id: "myMetallicRoughnessTexture", - * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset - * }); - * - * vboSceneModel.createTextureSet({ - * id: "myTextureSet", - * colorTextureId: "myColorTexture", - * metallicRoughnessTextureId: "myMetallicRoughnessTexture" - * }); - * - * vboSceneModel.createMesh({ - * id: "myMesh", - * textureSetId: "myTextureSet", - * primitive: "triangles", - * positions: [1, 1, 1, ...], - * normals: [0, 0, 1, 0, ...], - * uv: [1, 0, 0, ...], - * indices: [0, 1, 2, ...], - * }); - * - * vboSceneModel.createEntity({ - * id: "myEntity", - * meshIds: ["myMesh"] - * }); - * - * vboSceneModel.finalize(); - * ```` - * - * ## Loading KTX2 Textures from ArrayBuffers into a VBOSceneModel - * - * A VBOSceneModel that is configured with a {@link KTX2TextureTranscoder} will allow us to load textures into - * it from KTX2 ArrayBuffers. - * - * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a - * {@link KTX2TextureTranscoder}. We'll then programmatically create a simple object within the VBOSceneModel, consisting of - * a single mesh with a texture loaded from a KTX2 ArrayBuffer, which our VBOSceneModel internally transcodes, using - * its {@link KTX2TextureTranscoder}. - * - * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * const textureTranscoder = new KTX2TextureTranscoder({ - * viewer, - * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module - * }); - * - * const vboSceneModel = new VBOSceneModel(viewer.scene, { - * id: "myModel", - * textureTranscoder // <<-------------------- Configure model with our transcoder - * }); - * - * utils.loadArraybuffer("../assets/textures/compressed/sample_uastc_zstd.ktx2",(arrayBuffer) => { - * - * vboSceneModel.createTexture({ - * id: "myColorTexture", - * buffers: [arrayBuffer] // <<----- KTX2 texture asset - * }); - * - * vboSceneModel.createTexture({ - * id: "myMetallicRoughnessTexture", - * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset - * }); - * - * vboSceneModel.createTextureSet({ - * id: "myTextureSet", - * colorTextureId: "myColorTexture", - * metallicRoughnessTextureId: "myMetallicRoughnessTexture" - * }); - * - * vboSceneModel.createMesh({ - * id: "myMesh", - * textureSetId: "myTextureSet", - * primitive: "triangles", - * positions: [1, 1, 1, ...], - * normals: [0, 0, 1, 0, ...], - * uv: [1, 0, 0, ...], - * indices: [0, 1, 2, ...], - * }); - * - * vboSceneModel.createEntity({ - * id: "myEntity", - * meshIds: ["myMesh"] - * }); - * - * vboSceneModel.finalize(); - * }); - * ```` - * - * @implements {Drawable} - * @implements {Entity} - * @implements {SceneModel} - */ -class VBOSceneModel extends Component { + this._colors.push(r); + this._colors.push(g); + this._colors.push(b); + this._colors.push(opacity); - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent scene, generated automatically when omitted. - * @param {Boolean} [cfg.isModel] Specify ````true```` if this VBOSceneModel represents a model, in which case the VBOSceneModel will be registered by {@link VBOSceneModel#id} in {@link Scene#models} and may also have a corresponding {@link MetaModel} with matching {@link MetaModel#id}, registered by that ID in {@link MetaScene#metaModels}. - * @param {Number[]} [cfg.origin=[0,0,0]] World-space double-precision 3D origin. - * @param {Number[]} [cfg.position=[0,0,0]] Local, single-precision 3D position, relative to the origin parameter. - * @param {Number[]} [cfg.scale=[1,1,1]] Local scale. - * @param {Number[]} [cfg.rotation=[0,0,0]] Local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] Local modelling transform matrix. Overrides the position, scale and rotation parameters. - * @param {Boolean} [cfg.visible=true] Indicates if the VBOSceneModel is initially visible. - * @param {Boolean} [cfg.culled=false] Indicates if the VBOSceneModel is initially culled from view. - * @param {Boolean} [cfg.pickable=true] Indicates if the VBOSceneModel is initially pickable. - * @param {Boolean} [cfg.clippable=true] Indicates if the VBOSceneModel is initially clippable. - * @param {Boolean} [cfg.collidable=true] Indicates if the VBOSceneModel is initially included in boundary calculations. - * @param {Boolean} [cfg.xrayed=false] Indicates if the VBOSceneModel is initially xrayed. - * @param {Boolean} [cfg.highlighted=false] Indicates if the VBOSceneModel is initially highlighted. - * @param {Boolean} [cfg.selected=false] Indicates if the VBOSceneModel is initially selected. - * @param {Boolean} [cfg.edges=false] Indicates if the VBOSceneModel's edges are initially emphasized. - * @param {Number[]} [cfg.colorize=[1.0,1.0,1.0]] VBOSceneModel's initial RGB colorize color, multiplies by the rendered fragment colors. - * @param {Number} [cfg.opacity=1.0] VBOSceneModel's initial opacity factor, multiplies by the rendered fragment alpha. - * @param {Number} [cfg.backfaces=false] When we set this ````true````, then we force rendering of backfaces for this VBOSceneModel. When - * we leave this ````false````, then we allow the Viewer to decide when to render backfaces. In that case, the - * Viewer will hide backfaces on watertight meshes, show backfaces on open meshes, and always show backfaces on meshes when we slice them open with {@link SectionPlane}s. - * @param {Boolean} [cfg.saoEnabled=true] Indicates if Scalable Ambient Obscurance (SAO) will apply to this VBOSceneModel. SAO is configured by the Scene's {@link SAO} component. - * @param {Boolean} [cfg.pbrEnabled=true] Indicates if physically-based rendering (PBR) will apply to the VBOSceneModel when {@link Scene#pbrEnabled} is ````true````. - * @param {Boolean} [cfg.colorTextureEnabled=true] Indicates if base color textures will be rendered for the VBOSceneModel when {@link Scene#colorTextureEnabled} is ````true````. - * @param {Number} [cfg.edgeThreshold=10] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. - * @param {Number} [cfg.maxGeometryBatchSize=50000000] Maximum geometry batch size, as number of vertices. This is optionally supplied - * to limit the size of the batched geometry arrays that VBOSceneModel internally creates for batched geometries. - * A lower value means less heap allocation/de-allocation while creating/loading batched geometries, but more draw calls and - * slower rendering speed. A high value means larger heap allocation/de-allocation while creating/loading, but less draw calls - * and faster rendering speed. It's recommended to keep this somewhere roughly between ````50000```` and ````50000000```. - * @param {TextureTranscoder} [cfg.textureTranscoder] Transcoder that will be used internally by {@link VBOSceneModel#createTexture} - * to convert transcoded texture data. Only required when we'll be providing transcoded data - * to {@link VBOSceneModel#createTexture}. We assume that all transcoded texture data added to a ````VBOSceneModel```` - * will then in a format supported by this transcoder. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); + if (this.model.scene.entityOffsetsEnabled) { + this._offsets.push(0); + this._offsets.push(0); + this._offsets.push(0); + } - this._textureTranscoder = cfg.textureTranscoder || getKTX2TextureTranscoder(this.scene.viewer); + this._modelMatrixCol0.push(meshMatrix[0]); + this._modelMatrixCol0.push(meshMatrix[4]); + this._modelMatrixCol0.push(meshMatrix[8]); + this._modelMatrixCol0.push(meshMatrix[12]); - this._maxGeometryBatchSize = cfg.maxGeometryBatchSize; + this._modelMatrixCol1.push(meshMatrix[1]); + this._modelMatrixCol1.push(meshMatrix[5]); + this._modelMatrixCol1.push(meshMatrix[9]); + this._modelMatrixCol1.push(meshMatrix[13]); - this._aabb = math.collapseAABB3(); - this._aabbDirty = false; - this._layerList = []; // For GL state efficiency when drawing, InstancingLayers are in first part, BatchingLayers are in second - this._nodeList = []; + this._modelMatrixCol2.push(meshMatrix[2]); + this._modelMatrixCol2.push(meshMatrix[6]); + this._modelMatrixCol2.push(meshMatrix[10]); + this._modelMatrixCol2.push(meshMatrix[14]); - this._lastOrigin = null; - this._lastPositionsDecodeMatrix = null; - this._lastNormals = null; + // Expand AABB - this._instancingLayers = {}; - this._currentBatchingLayers = {}; + math.collapseAABB3(worldAABB); + const obb = this._state.obb; + const lenPositions = obb.length; + for (let i = 0; i < lenPositions; i += 4) { + tempVec4a$7[0] = obb[i + 0]; + tempVec4a$7[1] = obb[i + 1]; + tempVec4a$7[2] = obb[i + 2]; + math.transformPoint4(meshMatrix, tempVec4a$7, tempVec4b$7); + if (worldMatrix) { + math.transformPoint4(worldMatrix, tempVec4b$7, tempVec4c$4); + math.expandAABB3Point3(worldAABB, tempVec4c$4); + } else { + math.expandAABB3Point3(worldAABB, tempVec4b$7); + } + } - this._scratchMemory = getScratchMemory(); + if (this._state.origin) { + const origin = this._state.origin; + worldAABB[0] += origin[0]; + worldAABB[1] += origin[1]; + worldAABB[2] += origin[2]; + worldAABB[3] += origin[0]; + worldAABB[4] += origin[1]; + worldAABB[5] += origin[2]; + } - this._geometries = {}; - this._textures = {}; - this._textureSets = {}; - this._meshes = {}; - this._nodes = {}; + math.expandAABB3(this.aabb, worldAABB); - /** @private **/ - this.renderFlags = new RenderFlags(); + this._state.numInstances++; - /** - * @private - */ - this.numGeometries = 0; // Number of geometries created with createGeometry() + const portionId = this._portions.length; + this._portions.push({}); - // These counts are used to avoid unnecessary render passes - // They are incremented or decremented exclusively by BatchingLayer and InstancingLayer + this._numPortions++; + this.model.numPortions++; - /** - * @private - */ - this.numPortions = 0; + return portionId; + } - /** - * @private - */ - this.numVisibleLayerPortions = 0; + finalize() { + if (this._finalized) { + throw "Already finalized"; + } + const gl = this.model.scene.canvas.gl; + const colorsLength = this._colors.length; + const flagsLength = colorsLength; + if (colorsLength > 0) { + let notNormalized = false; + this._state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._colors), this._colors.length, 4, gl.DYNAMIC_DRAW, notNormalized); + this._colors = []; // Release memory + } + if (flagsLength > 0) { + // Because we only build flags arrays here, + // get their length from the colors array + let notNormalized = false; + let normalized = true; + this._state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, notNormalized); + this._state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, normalized); + } + if (this.model.scene.entityOffsetsEnabled) { + if (this._offsets.length > 0) { + const notNormalized = false; + this._state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._offsets), this._offsets.length, 3, gl.DYNAMIC_DRAW, notNormalized); + this._offsets = []; // Release memory + } + } + if (this._modelMatrixCol0.length > 0) { + const normalized = false; + this._state.modelMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol0), this._modelMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); + this._state.modelMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol1), this._modelMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); + this._state.modelMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol2), this._modelMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); + this._modelMatrixCol0 = []; + this._modelMatrixCol1 = []; + this._modelMatrixCol2 = []; + } + this._finalized = true; + } - /** - * @private - */ - this.numTransparentLayerPortions = 0; + // The following setters are called by VBOSceneModelMesh, in turn called by VBOSceneModelNode, only after the layer is finalized. + // It's important that these are called after finalize() in order to maintain integrity of counts like _numVisibleLayerPortions etc. - /** - * @private - */ - this.numXRayedLayerPortions = 0; + initFlags(portionId, flags, meshTransparent) { + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } + if (flags & ENTITY_FLAGS.EDGES) { + this._numEdgesLayerPortions++; + this.model.numEdgesLayerPortions++; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } + if (meshTransparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } + this._setFlags(portionId, flags, meshTransparent); + this._setFlags2(portionId, flags); + } - /** - * @private - */ - this.numHighlightedLayerPortions = 0; + setVisible(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } else { + this._numVisibleLayerPortions--; + this.model.numVisibleLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - /** - * @private - */ - this.numSelectedLayerPortions = 0; + setHighlighted(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } else { + this._numHighlightedLayerPortions--; + this.model.numHighlightedLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - /** - * @private - */ - this.numEdgesLayerPortions = 0; + setXRayed(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } else { + this._numXRayedLayerPortions--; + this.model.numXRayedLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - /** - * @private - */ - this.numPickableLayerPortions = 0; + setSelected(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } else { + this._numSelectedLayerPortions--; + this.model.numSelectedLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - /** - * @private - */ - this.numClippableLayerPortions = 0; + setEdges(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.EDGES) { + this._numEdgesLayerPortions++; + this.model.numEdgesLayerPortions++; + } else { + this._numEdgesLayerPortions--; + this.model.numEdgesLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - /** - * @private - */ - this.numCulledLayerPortions = 0; + setClippable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } else { + this._numClippableLayerPortions--; + this.model.numClippableLayerPortions--; + } + this._setFlags2(portionId, flags); + } - /** @private */ - this.numEntities = 0; + setCollidable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } + } - /** @private */ - this._numTriangles = 0; + setPickable(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } else { + this._numPickableLayerPortions--; + this.model.numPickableLayerPortions--; + } + this._setFlags2(portionId, flags, meshTransparent); + } - /** @private */ - this._numLines = 0; + setCulled(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } else { + this._numCulledLayerPortions--; + this.model.numCulledLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - /** @private */ - this._numPoints = 0; + setColor(portionId, color) { // RGBA color is normalized as ints + if (!this._finalized) { + throw "Not finalized"; + } + tempUint8Vec4$1[0] = color[0]; + tempUint8Vec4$1[1] = color[1]; + tempUint8Vec4$1[2] = color[2]; + tempUint8Vec4$1[3] = color[3]; + this._state.colorsBuf.setData(tempUint8Vec4$1, portionId * 4, 4); + } - this._edgeThreshold = cfg.edgeThreshold || 10; + setTransparent(portionId, flags, transparent) { + if (transparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } else { + this._numTransparentLayerPortions--; + this.model.numTransparentLayerPortions--; + } + this._setFlags(portionId, flags, transparent); + } - // Build static matrix + _setFlags(portionId, flags, meshTransparent) { - this._origin = math.vec3(cfg.origin || [0, 0, 0]); - this._position = math.vec3(cfg.position || [0, 0, 0]); - this._rotation = math.vec3(cfg.rotation || [0, 0, 0]); - this._quaternion = math.vec4(cfg.quaternion || [0, 0, 0, 1]); - if (cfg.rotation) { - math.eulerToQuaternion(this._rotation, "XYZ", this._quaternion); + if (!this._finalized) { + throw "Not finalized"; } - this._scale = math.vec3(cfg.scale || [1, 1, 1]); - this._worldMatrix = math.mat4(); - math.composeMat4(this._position, this._quaternion, this._scale, this._worldMatrix); - this._worldNormalMatrix = math.mat4(); - math.inverseMat4(this._worldMatrix, this._worldNormalMatrix); - math.transposeMat4(this._worldNormalMatrix); - if (cfg.matrix || cfg.position || cfg.rotation || cfg.scale || cfg.quaternion) { - this._viewMatrix = math.mat4(); - this._viewNormalMatrix = math.mat4(); - this._viewMatrixDirty = true; - this._worldMatrixNonIdentity = true; + const visible = !!(flags & ENTITY_FLAGS.VISIBLE); + const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); + const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); + const selected = !!(flags & ENTITY_FLAGS.SELECTED); + const edges = !!(flags & ENTITY_FLAGS.EDGES); + const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); + const culled = !!(flags & ENTITY_FLAGS.CULLED); + + // Normal fill + + let f0; + if (!visible || culled || xrayed + || (highlighted && !this.model.scene.highlightMaterial.glowThrough) + || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { + f0 = RENDER_PASSES.NOT_RENDERED; + } else { + if (meshTransparent) { + f0 = RENDER_PASSES.COLOR_TRANSPARENT; + } else { + f0 = RENDER_PASSES.COLOR_OPAQUE; + } } - this._opacity = 1.0; - this._colorize = [1, 1, 1]; + // Emphasis fill - this._saoEnabled = (cfg.saoEnabled !== false); - this._pbrEnabled = (cfg.pbrEnabled !== false); - this._colorTextureEnabled = (cfg.colorTextureEnabled !== false); + let f1; + if (!visible || culled) { + f1 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f1 = RENDER_PASSES.SILHOUETTE_SELECTED; + } else if (highlighted) { + f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; + } else if (xrayed) { + f1 = RENDER_PASSES.SILHOUETTE_XRAYED; + } else { + f1 = RENDER_PASSES.NOT_RENDERED; + } - this._isModel = cfg.isModel; - if (this._isModel) { - this.scene._registerModel(this); + // Edges + + let f2 = 0; + if (!visible || culled) { + f2 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f2 = RENDER_PASSES.EDGES_SELECTED; + } else if (highlighted) { + f2 = RENDER_PASSES.EDGES_HIGHLIGHTED; + } else if (xrayed) { + f2 = RENDER_PASSES.EDGES_XRAYED; + } else if (edges) { + if (meshTransparent) { + f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT; + } else { + f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE; + } + } else { + f2 = RENDER_PASSES.NOT_RENDERED; } - this._onCameraViewMatrix = this.scene.camera.on("matrix", () => { - this._viewMatrixDirty = true; - }); + // Pick - this._createDefaultTextureSet(); + let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; - this.visible = cfg.visible; - this.culled = cfg.culled; - this.pickable = cfg.pickable; - this.clippable = cfg.clippable; - this.collidable = cfg.collidable; - this.castsShadow = cfg.castsShadow; - this.receivesShadow = cfg.receivesShadow; - this.xrayed = cfg.xrayed; - this.highlighted = cfg.highlighted; - this.selected = cfg.selected; - this.edges = cfg.edges; - this.colorize = cfg.colorize; - this.opacity = cfg.opacity; - this.backfaces = cfg.backfaces; - } + tempUint8Vec4$1[0] = f0; // x - normal fill + tempUint8Vec4$1[1] = f1; // y - emphasis fill + tempUint8Vec4$1[2] = f2; // z - edges + tempUint8Vec4$1[3] = f3; // w - pick - _createDefaultTextureSet() { - // Every VBOSceneModelMesh gets at least the default TextureSet, - // which contains empty default textures filled with color - const defaultColorTexture = new VBOSceneModelTexture({ - id: defaultColorTextureId, - texture: new Texture2D({ - gl: this.scene.canvas.gl, - preloadColor: [1, 1, 1, 1] // [r, g, b, a]}) - }) - }); - const defaultMetalRoughTexture = new VBOSceneModelTexture({ - id: defaultMetalRoughTextureId, - texture: new Texture2D({ - gl: this.scene.canvas.gl, - preloadColor: [0, 1, 1, 1] // [unused, roughness, metalness, unused] - }) - }); - const defaultNormalsTexture = new VBOSceneModelTexture({ - id: defaultNormalsTextureId, - texture: new Texture2D({ - gl: this.scene.canvas.gl, - preloadColor: [0, 0, 0, 0] // [x, y, z, unused] - these must be zeros - }) - }); - const defaultEmissiveTexture = new VBOSceneModelTexture({ - id: defaultEmissiveTextureId, - texture: new Texture2D({ - gl: this.scene.canvas.gl, - preloadColor: [0, 0, 0, 1] // [x, y, z, unused] - }) - }); - const defaultOcclusionTexture = new VBOSceneModelTexture({ - id: defaultOcclusionTextureId, - texture: new Texture2D({ - gl: this.scene.canvas.gl, - preloadColor: [1, 1, 1, 1] // [x, y, z, unused] - }) - }); - this._textures[defaultColorTextureId] = defaultColorTexture; - this._textures[defaultMetalRoughTextureId] = defaultMetalRoughTexture; - this._textures[defaultNormalsTextureId] = defaultNormalsTexture; - this._textures[defaultEmissiveTextureId] = defaultEmissiveTexture; - this._textures[defaultOcclusionTextureId] = defaultOcclusionTexture; - this._textureSets[defaultTextureSetId] = new VBOSceneModelTextureSet({ - id: defaultTextureSetId, - model: this, - colorTexture: defaultColorTexture, - metallicRoughnessTexture: defaultMetalRoughTexture, - normalsTexture: defaultNormalsTexture, - emissiveTexture: defaultEmissiveTexture, - occlusionTexture: defaultOcclusionTexture - }); + this._state.flagsBuf.setData(tempUint8Vec4$1, portionId * 4, 4); } - //------------------------------------------------------------------------------------------------------------------ - // VBOSceneModel members - //------------------------------------------------------------------------------------------------------------------ + _setFlags2(portionId, flags) { - /** - * Returns true to indicate that this Component is a VBOSceneModel. - * @type {Boolean} - */ - get isPerformanceModel() { - return true; - } + if (!this._finalized) { + throw "Not finalized"; + } - /** - * Returns the {@link Entity}s in this VBOSceneModel. - * @returns {*|{}} - */ - get objects() { - return this._nodes; - } + const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; + tempUint8Vec4$1[0] = clippable; - /** - * Gets the 3D World-space origin for this VBOSceneModel. - * - * Each geometry or mesh origin, if supplied, is relative to this origin. - * - * Default value is ````[0,0,0]````. - * - * @type {Float64Array} - * @abstract - */ - get origin() { - return this._origin; + this._state.flags2Buf.setData(tempUint8Vec4$1, portionId * 4, 4); } - /** - * Gets the VBOSceneModel's local translation. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - */ - get position() { - return this._position; + setOffset(portionId, offset) { + if (!this._finalized) { + throw "Not finalized"; + } + if (!this.model.scene.entityOffsetsEnabled) { + this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled + return; + } + tempVec3fa$1[0] = offset[0]; + tempVec3fa$1[1] = offset[1]; + tempVec3fa$1[2] = offset[2]; + this._state.offsetsBuf.setData(tempVec3fa$1, portionId * 3, 3); } - /** - * Gets the VBOSceneModel's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - */ - get rotation() { - return this._rotation; - } + // ---------------------- NORMAL RENDERING ----------------------------------- - /** - * Gets the PerformanceModels's local rotation quaternion. - * - * Default value is ````[0,0,0,1]````. - * - * @type {Number[]} - */ - get quaternion() { - return this._quaternion; + drawColorOpaque(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + + if (this._linesInstancingRenderers.colorRenderer) { + this._linesInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } } - /** - * Gets the VBOSceneModel's local scale. - * - * Default value is ````[1,1,1]````. - * - * @type {Number[]} - */ - get scale() { - return this._scale; + drawColorTransparent(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { + return; + } + if (this._linesInstancingRenderers.colorRenderer) { + this._linesInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } } - /** - * Gets the VBOSceneModel's local modeling transform matrix. - * - * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. - * - * @type {Number[]} - */ - get matrix() { - return this._worldMatrix; + // ---------------------- RENDERING SAO POST EFFECT TARGETS -------------- + + drawDepth(renderFlags, frameCtx) { } - /** - * Gets the VBOSceneModel's World matrix. - * - * @property worldMatrix - * @type {Number[]} - */ - get worldMatrix() { - return this._worldMatrix; + drawNormals(renderFlags, frameCtx) { } - /** - * Gets the VBOSceneModel's World normal matrix. - * - * @type {Number[]} - */ - get worldNormalMatrix() { - return this._worldNormalMatrix; + // ---------------------- EMPHASIS RENDERING ----------------------------------- + + drawSilhouetteXRayed(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + return; + } + if (this._linesInstancingRenderers.silhouetteRenderer) { + this._linesInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); + } } - /** - * Called by private renderers in ./lib, returns the view matrix with which to - * render this VBOSceneModel. The view matrix is the concatenation of the - * Camera view matrix with the Performance model's world (modeling) matrix. - * - * @private - */ - get viewMatrix() { - if (!this._viewMatrix) { - return this.scene.camera.viewMatrix; + drawSilhouetteHighlighted(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + return; } - if (this._viewMatrixDirty) { - math.mulMat4(this.scene.camera.viewMatrix, this._worldMatrix, this._viewMatrix); - math.inverseMat4(this._viewMatrix, this._viewNormalMatrix); - math.transposeMat4(this._viewNormalMatrix); - this._viewMatrixDirty = false; + if (this._linesInstancingRenderers.silhouetteRenderer) { + this._linesInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); } - return this._viewMatrix; } - /** - * Called by private renderers in ./lib, returns the view normal matrix with which to render this VBOSceneModel. - * - * @private - */ - get viewNormalMatrix() { - if (!this._viewNormalMatrix) { - return this.scene.camera.viewNormalMatrix; + drawSilhouetteSelected(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { + return; } - if (this._viewMatrixDirty) { - math.mulMat4(this.scene.camera.viewMatrix, this._worldMatrix, this._viewMatrix); - math.inverseMat4(this._viewMatrix, this._viewNormalMatrix); - math.transposeMat4(this._viewNormalMatrix); - this._viewMatrixDirty = false; + if (this._linesInstancingRenderers.silhouetteRenderer) { + this._linesInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); } - return this._viewNormalMatrix; } - /** - * Sets if backfaces are rendered for this VBOSceneModel. - * - * Default is ````false````. - * - * @type {Boolean} - */ - get backfaces() { - return this._backfaces; + // ---------------------- EDGES RENDERING ----------------------------------- + + drawEdgesColorOpaque(renderFlags, frameCtx) { } - /** - * Sets if backfaces are rendered for this VBOSceneModel. - * - * Default is ````false````. - * - * When we set this ````true````, then backfaces are always rendered for this VBOSceneModel. - * - * When we set this ````false````, then we allow the Viewer to decide whether to render backfaces. In this case, - * the Viewer will: - * - * * hide backfaces on watertight meshes, - * * show backfaces on open meshes, and - * * always show backfaces on meshes when we slice them open with {@link SectionPlane}s. - * - * @type {Boolean} - */ - set backfaces(backfaces) { - backfaces = !!backfaces; - this._backfaces = backfaces; - this.glRedraw(); + drawEdgesColorTransparent(renderFlags, frameCtx) { } - /** - * Gets the list of {@link Entity}s within this VBOSceneModel. - * - * @returns {Entity[]} - */ - get entityList() { - return this._nodeList; + drawEdgesXRayed(renderFlags, frameCtx) { } - /** - * Returns true to indicate that VBOSceneModel is an {@link Entity}. - * @type {Boolean} - */ - get isEntity() { - return true; + drawEdgesHighlighted(renderFlags, frameCtx) { } - /** - * Returns ````true```` if this VBOSceneModel represents a model. - * - * When ````true```` the VBOSceneModel will be registered by {@link VBOSceneModel#id} in - * {@link Scene#models} and may also have a {@link MetaObject} with matching {@link MetaObject#id}. - * - * @type {Boolean} - */ - get isModel() { - return this._isModel; + drawEdgesSelected(renderFlags, frameCtx) { } - //------------------------------------------------------------------------------------------------------------------ - // VBOSceneModel members - //------------------------------------------------------------------------------------------------------------------ + // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- - /** - * Returns ````false```` to indicate that VBOSceneModel never represents an object. - * - * @type {Boolean} - */ - get isObject() { - return false; + drawOcclusion(renderFlags, frameCtx) { } - /** - * Gets the VBOSceneModel's World-space 3D axis-aligned bounding box. - * - * Represented by a six-element Float64Array containing the min/max extents of the - * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. - * - * @type {Number[]} - */ - get aabb() { - if (this._aabbDirty) { - this._rebuildAABB(); - } - return this._aabb; - } + // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- - /** - * The approximate number of triangle primitives in this VBOSceneModel. - * - * @type {Number} - */ - get numTriangles() { - return this._numTriangles; + drawShadow(renderFlags, frameCtx) { } - //------------------------------------------------------------------------------------------------------------------ - // Entity members - //------------------------------------------------------------------------------------------------------------------ + //---- PICKING ---------------------------------------------------------------------------------------------------- - /** - * The approximate number of line primitives in this VBOSceneModel. - * - * @type {Number} - */ - get numLines() { - return this._numLines; + drawPickMesh(renderFlags, frameCtx) { } - /** - * The approximate number of point primitives in this VBOSceneModel. - * - * @type {Number} - */ - get numPoints() { - return this._numPoints; + drawPickDepths(renderFlags, frameCtx) { } - /** - * Gets if any {@link Entity}s in this VBOSceneModel are visible. - * - * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is ````true```` and {@link VBOSceneModel#culled} is ````false````. - * - * @type {Boolean} - */ - get visible() { - return (this.numVisibleLayerPortions > 0); + drawPickNormals(renderFlags, frameCtx) { } - /** - * Sets if this VBOSceneModel is visible. - * - * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is ````true```` and {@link VBOSceneModel#culled} is ````false````. - ** - * @type {Boolean} - */ - set visible(visible) { - visible = visible !== false; - this._visible = visible; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].visible = visible; + + destroy() { + const state = this._state; + if (state.positionsBuf) { + state.positionsBuf.destroy(); + state.positionsBuf = null; } - this.glRedraw(); + if (state.colorsBuf) { + state.colorsBuf.destroy(); + state.colorsBuf = null; + } + if (state.flagsBuf) { + state.flagsBuf.destroy(); + state.flagsBuf = null; + } + if (state.flags2Buf) { + state.flags2Buf.destroy(); + state.flags2Buf = null; + } + if (state.offsetsBuf) { + state.offsetsBuf.destroy(); + state.offsetsBuf = null; + } + if (state.modelMatrixCol0Buf) { + state.modelMatrixCol0Buf.destroy(); + state.modelMatrixCol0Buf = null; + } + if (state.modelMatrixCol1Buf) { + state.modelMatrixCol1Buf.destroy(); + state.modelMatrixCol1Buf = null; + } + if (state.modelMatrixCol2Buf) { + state.modelMatrixCol2Buf.destroy(); + state.modelMatrixCol2Buf = null; + } + state.destroy(); } +} - /** - * Gets if any {@link Entity}s in this VBOSceneModel are xrayed. - * - * @type {Boolean} - */ - get xrayed() { - return (this.numXRayedLayerPortions > 0); - } +const tempVec3a$l = math.vec3(); - /** - * Sets if all {@link Entity}s in this VBOSceneModel are xrayed. - * - * @type {Boolean} - */ - set xrayed(xrayed) { - xrayed = !!xrayed; - this._xrayed = xrayed; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].xrayed = xrayed; - } - this.glRedraw(); - } +/** + * @private + */ +class PointsBatchingColorRenderer { - /** - * Gets if any {@link Entity}s in this VBOSceneModel are highlighted. - * - * @type {Boolean} - */ - get highlighted() { - return (this.numHighlightedLayerPortions > 0); + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - /** - * Sets if all {@link Entity}s in this VBOSceneModel are highlighted. - * - * @type {Boolean} - */ - set highlighted(highlighted) { - highlighted = !!highlighted; - this._highlighted = highlighted; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].highlighted = highlighted; - } - this.glRedraw(); + getValid() { + return this._hash === this._getHash(); } - /** - * Gets if any {@link Entity}s in this VBOSceneModel are selected. - * - * @type {Boolean} - */ - get selected() { - return (this.numSelectedLayerPortions > 0); + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; } - /** - * Sets if all {@link Entity}s in this VBOSceneModel are selected. - * - * @type {Boolean} - */ - set selected(selected) { - selected = !!selected; - this._selected = selected; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].selected = selected; - } - this.glRedraw(); - } + drawLayer(frameCtx, pointsBatchingLayer, renderPass) { - /** - * Gets if any {@link Entity}s in this VBOSceneModel have edges emphasised. - * - * @type {Boolean} - */ - get edges() { - return (this.numEdgesLayerPortions > 0); - } + const scene = this._scene; + const camera = scene.camera; + const model = pointsBatchingLayer.model; + const gl = scene.canvas.gl; + const state = pointsBatchingLayer._state; + const origin = pointsBatchingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial; - /** - * Sets if all {@link Entity}s in this VBOSceneModel have edges emphasised. - * - * @type {Boolean} - */ - set edges(edges) { - edges = !!edges; - this._edges = edges; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].edges = edges; + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } } - this.glRedraw(); - } - - /** - * Gets if this VBOSceneModel is culled from view. - * - * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is true and {@link VBOSceneModel#culled} is false. - * - * @type {Boolean} - */ - get culled() { - return this._culled; - } - /** - * Sets if this VBOSceneModel is culled from view. - * - * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is true and {@link VBOSceneModel#culled} is false. - * - * @type {Boolean} - */ - set culled(culled) { - culled = !!culled; - this._culled = culled; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].culled = culled; + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); } - this.glRedraw(); - } - /** - * Gets if {@link Entity}s in this VBOSceneModel are clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * @type {Boolean} - */ - get clippable() { - return this._clippable; - } + gl.uniform1i(this._uRenderPass, renderPass); - /** - * Sets if {@link Entity}s in this VBOSceneModel are clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * @type {Boolean} - */ - set clippable(clippable) { - clippable = clippable !== false; - this._clippable = clippable; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].clippable = clippable; + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$l); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - this.glRedraw(); - } - /** - * Gets if this VBOSceneModel is collidable. - * - * @type {Boolean} - */ - get collidable() { - return this._collidable; - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); - /** - * Sets if {@link Entity}s in this VBOSceneModel are collidable. - * - * @type {Boolean} - */ - set collidable(collidable) { - collidable = collidable !== false; - this._collidable = collidable; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].collidable = collidable; + this._aPosition.bindArrayBuffer(state.positionsBuf); + + if (this._aColor) { + this._aColor.bindArrayBuffer(state.colorsBuf); } - } - /** - * Gets if this VBOSceneModel is pickable. - * - * Picking is done via calls to {@link Scene#pick}. - * - * @type {Boolean} - */ - get pickable() { - return (this.numPickableLayerPortions > 0); - } + if (pointsMaterial.filterIntensity) { + gl.uniform2f(this._uIntensityRange, pointsMaterial.minIntensity, pointsMaterial.maxIntensity); + } - /** - * Sets if {@link Entity}s in this VBOSceneModel are pickable. - * - * Picking is done via calls to {@link Scene#pick}. - * - * @type {Boolean} - */ - set pickable(pickable) { - pickable = pickable !== false; - this._pickable = pickable; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].pickable = pickable; + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - } - /** - * Gets the RGB colorize color for this VBOSceneModel. - * - * Each element of the color is in range ````[0..1]````. - * - * @type {Number[]} - */ - get colorize() { - return this._colorize; - } + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + } - /** - * Sets the RGB colorize color for this VBOSceneModel. - * - * Multiplies by rendered fragment colors. - * - * Each element of the color is in range ````[0..1]````. - * - * @type {Number[]} - */ - set colorize(colorize) { - this._colorize = colorize; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].colorize = colorize; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - } - /** - * Gets this VBOSceneModel's opacity factor. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - get opacity() { - return this._opacity; + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + + gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); + + frameCtx.drawArrays++; } - /** - * Sets the opacity factor for this VBOSceneModel. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - set opacity(opacity) { - this._opacity = opacity; - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i].opacity = opacity; + _allocate() { + + const scene = this._scene; + const pointsMaterial = scene.pointsMaterial._state; + const gl = scene.canvas.gl; + + this._program = new Program(gl, this._buildShader(scene)); + + if (this._program.errors) { + this.errors = this._program.errors; + return; } - } - /** - * Gets if this VBOSceneModel casts a shadow. - * - * @type {Boolean} - */ - get castsShadow() { - return this._castsShadow; - } + const program = this._program; - /** - * Sets if this VBOSceneModel casts a shadow. - * - * @type {Boolean} - */ - set castsShadow(castsShadow) { - castsShadow = (castsShadow !== false); - if (castsShadow !== this._castsShadow) { - this._castsShadow = castsShadow; - this.glRedraw(); + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + + this._uSectionPlanes = []; + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - } - /** - * Sets if this VBOSceneModel can have shadow cast upon it. - * - * @type {Boolean} - */ - get receivesShadow() { - return this._receivesShadow; - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - /** - * Sets if this VBOSceneModel can have shadow cast upon it. - * - * @type {Boolean} - */ - set receivesShadow(receivesShadow) { - receivesShadow = (receivesShadow !== false); - if (receivesShadow !== this._receivesShadow) { - this._receivesShadow = receivesShadow; - this.glRedraw(); + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + + if (pointsMaterial.filterIntensity) { + this._uIntensityRange = program.getLocation("intensityRange"); } - } - /** - * Gets if Scalable Ambient Obscurance (SAO) will apply to this VBOSceneModel. - * - * SAO is configured by the Scene's {@link SAO} component. - * - * Only works when {@link SAO#enabled} is also true. - * - * @type {Boolean} - */ - get saoEnabled() { - return this._saoEnabled; + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - /** - * Gets if physically-based rendering (PBR) is enabled for this VBOSceneModel. - * - * Only works when {@link Scene#pbrEnabled} is also true. - * - * @type {Boolean} - */ - get pbrEnabled() { - return this._pbrEnabled; - } + _bindProgram() { - /** - * Gets if color textures are enabled for this VBOSceneModel. - * - * Only works when {@link Scene#colorTextureEnabled} is also true. - * - * @type {Boolean} - */ - get colorTextureEnabled() { - return this._colorTextureEnabled; - } + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + const project = scene.camera.project; - /** - * Returns true to indicate that VBOSceneModel is implements {@link Drawable}. - * - * @type {Boolean} - */ - get isDrawable() { - return true; - } + program.bind(); - /** @private */ - get isStateSortable() { - return false - } + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - /** - * Configures the appearance of xrayed {@link Entity}s within this VBOSceneModel. - * - * This is the {@link Scene#xrayMaterial}. - * - * @type {EmphasisMaterial} - */ - get xrayMaterial() { - return this.scene.xrayMaterial; + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } - /** - * Configures the appearance of highlighted {@link Entity}s within this VBOSceneModel. - * - * This is the {@link Scene#highlightMaterial}. - * - * @type {EmphasisMaterial} - */ - get highlightMaterial() { - return this.scene.highlightMaterial; + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - /** - * Configures the appearance of selected {@link Entity}s within this VBOSceneModel. - * - * This is the {@link Scene#selectedMaterial}. - * - * @type {EmphasisMaterial} - */ - get selectedMaterial() { - return this.scene.selectedMaterial; - } + _buildVertexShader() { - /** - * Configures the appearance of edges of {@link Entity}s within this VBOSceneModel. - * - * This is the {@link Scene#edgeMaterial}. - * - * @type {EdgeMaterial} - */ - get edgeMaterial() { - return this.scene.edgeMaterial; - } + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial; + const src = []; + src.push('#version 300 es'); + src.push("// Points batching color vertex shader"); - //------------------------------------------------------------------------------------------------------------------ - // Drawable members - //------------------------------------------------------------------------------------------------------------------ + src.push("uniform int renderPass;"); - /** - * Called by private renderers in ./lib, returns the picking view matrix with which to - * ray-pick on this VBOSceneModel. - * - * @private - */ - getPickViewMatrix(pickViewMatrix) { - if (!this._viewMatrix) { - return pickViewMatrix; - } - return this._viewMatrix; - } + src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - /** - * Creates a reusable geometry within this VBOSceneModel. - * - * We can then supply the geometry ID to {@link VBOSceneModel#createMesh} when we want to create meshes that instance the geometry. - * - * @param {*} cfg Geometry properties. - * @param {String|Number} cfg.id Mandatory ID for the geometry, to refer to with {@link VBOSceneModel#createMesh}. - * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. - * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. - * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. - * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. - * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. - * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. - * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. - * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. - * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````VBOSceneModel```` constructor. - */ - createGeometry(cfg) { - const geometryId = cfg.id; - if (geometryId === undefined || geometryId === null) { - this.error("Config missing: id"); - return; - } - if (this._geometries[geometryId]) { - this.error("Geometry already created: " + geometryId); - return; + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - const primitive = cfg.primitive; - if (primitive === undefined || primitive === null) { - this.error("Param expected: primitive"); - return; + + src.push("uniform mat4 worldMatrix;"); + + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); } - if (primitive !== "points" && primitive !== "lines" && primitive !== "triangles" && primitive !== "solid" && primitive !== "surface") { - this.error(`Unsupported value for 'primitive': '${primitive}' - supported values are 'points', 'lines', 'triangles', 'solid' and 'surface'. Defaulting to 'triangles'.`); - return; + + if (pointsMaterial.filterIntensity) { + src.push("uniform vec2 intensityRange;"); } - if (!cfg.positions && !cfg.positionsCompressed) { - this.error("Param expected: `positions` or `positionsCompressed'"); - return null; + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); } - if (cfg.positionsCompressed && !cfg.positionsDecodeMatrix) { - this.error("Param expected: `positionsDecodeMatrix` (required for `positionsCompressed')"); - return null; + + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - if (cfg.uvCompressed && !cfg.uvDecodeMatrix) { - this.error("Param expected: `uvDecodeMatrix` (required for `uvCompressed')"); - return null; + src.push("out vec4 vColor;"); + + src.push("void main(void) {"); + + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE + + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + + if (pointsMaterial.filterIntensity) { + src.push("float intensity = float(color.a) / 255.0;"); + src.push("if (intensity < intensityRange[0] || intensity > intensityRange[1]) {"); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); } - if (!cfg.indices && primitive !== "points") { - this.error(`Param expected: indices (required for '${primitive}' primitive type)`); - return null; + + src.push("vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push("worldPosition.xyz = worldPosition.xyz + offset;"); } - const geometry = new VBOSceneModelGeometry(geometryId, this, cfg); - this._geometries[geometryId] = geometry; - this._numTriangles += (cfg.indices ? Math.round(cfg.indices.length / 3) : 0); - this.numGeometries++; - } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - /** - * Creates a texture within this VBOSceneModel. - * - * We can then supply the texture ID to {@link VBOSceneModel#createTextureSet} when we want to create texture sets that use the texture. - * - * @param {*} cfg Texture properties. - * @param {String|Number} cfg.id Mandatory ID for the texture, to refer to with {@link VBOSceneModel#createTextureSet}. - * @param {String} [cfg.src] Image file for the texture. Assumed to be transcoded if not having a recognized image file - * extension (jpg, jpeg, png etc.). If transcoded, then assumes ````VBOSceneModel```` is configured with a {@link TextureTranscoder}. - * @param {ArrayBuffer[]} [cfg.buffers] Transcoded texture data. Assumes ````VBOSceneModel```` is - * configured with a {@link TextureTranscoder}. This parameter is given as an array of buffers so we can potentially support multi-image textures, such as cube maps. - * @param {HTMLImageElement} [cfg.image] HTML Image object to load into this texture. Overrides ````src```` and ````buffers````. Never transcoded. - * @param {Number} [cfg.minFilter=LinearMipmapLinearFilter] How the texture is sampled when a texel covers less than one pixel. - * Supported values are {@link LinearMipmapLinearFilter}, {@link LinearMipMapNearestFilter}, {@link NearestMipMapNearestFilter}, {@link NearestMipMapLinearFilter} and {@link LinearMipMapLinearFilter}. - * @param {Number} [cfg.magFilter=LinearFilter] How the texture is sampled when a texel covers more than one pixel. Supported values are {@link LinearFilter} and {@link NearestFilter}. - * @param {Number} [cfg.wrapS=RepeatWrapping] Wrap parameter for texture coordinate *S*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. - * @param {Number} [cfg.wrapT=RepeatWrapping] Wrap parameter for texture coordinate *T*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}.. - * @param {Boolean} [cfg.flipY=false] Flips this Texture's source data along its vertical axis when ````true````. - * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. - */ - createTexture(cfg) { - const textureId = cfg.id; - if (textureId === undefined || textureId === null) { - this.error("Config missing: id"); - return; + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, 1.0);"); + + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } - if (this._textures[textureId]) { - this.error("Texture already created: " + textureId); - return; + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } - if (!cfg.src && !cfg.image && !cfg.buffers) { - this.error("Param expected: `src`, `image' or 'buffers'"); - return null; + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); } - let minFilter = cfg.minFilter || LinearMipmapLinearFilter; - if (minFilter !== LinearFilter && - minFilter !== LinearMipMapNearestFilter && - minFilter !== LinearMipmapLinearFilter && - minFilter !== NearestMipMapLinearFilter && - minFilter !== NearestMipMapNearestFilter) { - this.error(`[createTexture] Unsupported value for 'minFilter' - - supported values are LinearFilter, LinearMipMapNearestFilter, NearestMipMapNearestFilter, - NearestMipMapLinearFilter and LinearMipmapLinearFilter. Defaulting to LinearMipmapLinearFilter.`); - minFilter = LinearMipmapLinearFilter; + src.push("}"); + if (pointsMaterial.filterIntensity) { + src.push("}"); } - let magFilter = cfg.magFilter || LinearFilter; - if (magFilter !== LinearFilter && magFilter !== NearestFilter) { - this.error(`[createTexture] Unsupported value for 'magFilter' - supported values are LinearFilter and NearestFilter. Defaulting to LinearFilter.`); - magFilter = LinearFilter; + src.push("}"); + return src; + } + + _buildFragmentShader() { + + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Points batching color fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - let wrapS = cfg.wrapS || RepeatWrapping; - if (wrapS !== ClampToEdgeWrapping && wrapS !== MirroredRepeatWrapping && wrapS !== RepeatWrapping) { - this.error(`[createTexture] Unsupported value for 'wrapS' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping.`); - wrapS = RepeatWrapping; + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } } - let wrapT = cfg.wrapT || RepeatWrapping; - if (wrapT !== ClampToEdgeWrapping && wrapT !== MirroredRepeatWrapping && wrapT !== RepeatWrapping) { - this.error(`[createTexture] Unsupported value for 'wrapT' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping.`); - wrapT = RepeatWrapping; + src.push("in vec4 vColor;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); } - let encoding = cfg.encoding || LinearEncoding; - if (encoding !== LinearEncoding && encoding !== sRGBEncoding) { - this.error("[createTexture] Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); - encoding = LinearEncoding; + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); } - const texture = new Texture2D({gl: this.scene.canvas.gl}); - if (cfg.preloadColor) { - texture.setPreloadColor(cfg.preloadColor); + src.push(" outColor = vColor;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - if (cfg.image) { // Ignore transcoder for Images - const image = cfg.image; - image.crossOrigin = "Anonymous"; - texture.setImage(image, {minFilter, magFilter, wrapS, wrapT, flipY: cfg.flipY, encoding}); + src.push("}"); + return src; + } - } else if (cfg.src) { - const ext = cfg.src.split('.').pop(); - switch (ext) { // Don't transcode recognized image file types - case "jpeg": - case "jpg": - case "png": - case "gif": - const image = new Image(); - image.onload = () => { - texture.setImage(image, {minFilter, magFilter, wrapS, wrapT, flipY: cfg.flipY, encoding}); - }; - image.src = cfg.src; // URL or Base64 string - break; - default: // Assume other file types need transcoding - if (!this._textureTranscoder) { - this.error(`Can't create texture from 'src' - VBOSceneModel needs to be configured with a TextureTranscoder for this file type ('${ext}')`); - } else { - utils.loadArraybuffer(cfg.src, (arrayBuffer) => { - if (!arrayBuffer.byteLength) { - this.error(`Can't create texture from 'src': file data is zero length`); - return; - } - this._textureTranscoder.transcode([arrayBuffer], texture).then(() => { - this.glRedraw(); - }); - }, - function (errMsg) { - this.error(`Can't create texture from 'src': ${errMsg}`); - }); - } - break; - } - } else if (cfg.buffers) { // Buffers implicitly require transcoding - if (!this._textureTranscoder) { - this.error(`Can't create texture from 'buffers' - VBOSceneModel needs to be configured with a TextureTranscoder for this option`); - } else { - this._textureTranscoder.transcode(cfg.buffers, texture).then(() => { - this.glRedraw(); - }); - } + webglContextRestored() { + this._program = null; + } + + destroy() { + if (this._program) { + this._program.destroy(); } + this._program = null; + } +} - this._textures[textureId] = new VBOSceneModelTexture({id: textureId, texture}); +const defaultColor = new Float32Array([1, 1, 1]); +const tempVec3a$k = math.vec3(); + +/** + * @private + */ +class PointsBatchingSilhouetteRenderer { + + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - /** - * Creates a texture set within this VBOSceneModel. - * - * A texture set is a collection of textures that can be shared among meshes. We can then supply the texture set - * ID to {@link VBOSceneModel#createMesh} when we want to create meshes that use the texture set. - * - * The textures can work as a texture atlas, where each mesh can have geometry UVs that index - * a different part of the textures. This allows us to minimize the number of textures in our models, which - * means faster rendering. - * - * @param {*} cfg Texture set properties. - * @param {String|Number} cfg.id Mandatory ID for the texture set, to refer to with {@link VBOSceneModel#createMesh}. - * @param {*} [cfg.colorTextureId] ID of *RGBA* base color texture, with color in *RGB* and alpha in *A*. - * @param {*} [cfg.metallicRoughnessTextureId] ID of *RGBA* metal-roughness texture, with the metallic factor in *R*, and roughness factor in *G*. - * @param {*} [cfg.normalsTextureId] ID of *RGBA* normal map texture, with normal map vectors in *RGB*. - * @param {*} [cfg.emissiveTextureId] ID of *RGBA* emissive map texture, with emissive color in *RGB*. - * @param {*} [cfg.occlusionTextureId] ID of *RGBA* occlusion map texture, with occlusion factor in *R*. - */ - createTextureSet(cfg) { - const textureSetId = cfg.id; - if (textureSetId === undefined || textureSetId === null) { - this.error("Config missing: id"); - return; - } - if (this._textureSets[textureSetId]) { - this.error(`Texture set already created: ${textureSetId}`); - return; - } - let colorTexture; - if (cfg.colorTextureId !== undefined && cfg.colorTextureId !== null) { - colorTexture = this._textures[cfg.colorTextureId]; - if (!colorTexture) { - this.error(`Texture not found: ${cfg.colorTextureId} - ensure that you create it first with createTexture()`); - return; - } - } else { - colorTexture = this._textures[defaultColorTextureId]; - } - let metallicRoughnessTexture; - if (cfg.metallicRoughnessTextureId !== undefined && cfg.metallicRoughnessTextureId !== null) { - metallicRoughnessTexture = this._textures[cfg.metallicRoughnessTextureId]; - if (!metallicRoughnessTexture) { - this.error(`Texture not found: ${cfg.metallicRoughnessTextureId} - ensure that you create it first with createTexture()`); + getValid() { + return this._hash === this._getHash(); + }; + + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + } + + drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + + const model = pointsBatchingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = pointsBatchingLayer._state; + const origin = pointsBatchingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + + if (!this._program) { + this._allocate(); + if (this.errors) { return; } - } else { - metallicRoughnessTexture = this._textures[defaultMetalRoughTextureId]; } - let normalsTexture; - if (cfg.normalsTextureId !== undefined && cfg.normalsTextureId !== null) { - normalsTexture = this._textures[cfg.normalsTextureId]; - if (!normalsTexture) { - this.error(`Texture not found: ${cfg.normalsTextureId} - ensure that you create it first with createTexture()`); - return; - } - } else { - normalsTexture = this._textures[defaultNormalsTextureId]; + + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); } - let emissiveTexture; - if (cfg.emissiveTextureId !== undefined && cfg.emissiveTextureId !== null) { - emissiveTexture = this._textures[cfg.emissiveTextureId]; - if (!emissiveTexture) { - this.error(`Texture not found: ${cfg.emissiveTextureId} - ensure that you create it first with createTexture()`); - return; - } + + gl.uniform1i(this._uRenderPass, renderPass); + + if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + const material = scene.xrayMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + const material = scene.selectedMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + } else { - emissiveTexture = this._textures[defaultEmissiveTextureId]; + gl.uniform4fv(this._uColor, defaultColor); } - let occlusionTexture; - if (cfg.occlusionTextureId !== undefined && cfg.occlusionTextureId !== null) { - occlusionTexture = this._textures[cfg.occlusionTextureId]; - if (!occlusionTexture) { - this.error(`Texture not found: ${cfg.occlusionTextureId} - ensure that you create it first with createTexture()`); - return; + + const viewMat = (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix; + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMat); + + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$k); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } } - } else { - occlusionTexture = this._textures[defaultOcclusionTextureId]; } - const textureSet = new VBOSceneModelTextureSet({ - id: textureSetId, - model: this, - colorTexture, - metallicRoughnessTexture, - normalsTexture, - emissiveTexture, - occlusionTexture - }); - this._textureSets[textureSetId] = textureSet; - } - /** - * Creates a mesh within this VBOSceneModel. - * - * A mesh can either define its own geometry or share it with other meshes. To define own geometry, provide the - * various geometry arrays to this method. To share a geometry, provide the ID of a geometry created earlier - * with {@link VBOSceneModel#createGeometry}. - * - * Internally, VBOSceneModel will batch all unique mesh geometries into the same arrays, which improves - * rendering performance. - * - * If you accompany the arrays with an ````origin````, then ````createMesh()```` will assume - * that the ````positions```` are in relative-to-center (RTC) coordinates, with ````origin```` being the origin of their - * RTC coordinate system. - * - * @param {object} cfg Object properties. - * @param {String} cfg.id Mandatory ID for the new mesh. Must not clash with any existing components within the {@link Scene}. - * @param {String|Number} [cfg.textureSetId] ID of a texture set previously created with {@link VBOSceneModel#createTextureSet"}. - * @param {String|Number} [cfg.geometryId] ID of a geometry to instance, previously created with {@link VBOSceneModel#createGeometry"}. Overrides all other geometry parameters given to this method. - * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. - * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. - * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. - * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. - * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. - * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. - * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. - * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. - * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. - * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. - * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````VBOSceneModel```` constructor. - * @param {Number[]} [cfg.origin] Optional geometry origin, relative to {@link VBOSceneModel#origin}. When this is given, then ````positions```` are assumed to be relative to this. - * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position of the mesh. - * @param {Number[]} [cfg.scale=[1,1,1]] Scale of the mesh. - * @param {Number[]} [cfg.rotation=[0,0,0]] Rotation of the mesh as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Mesh modelling transform matrix. Overrides the ````position````, ````scale```` and ````rotation```` parameters. - * @param {Number[]} [cfg.color=[1,1,1]] RGB color in range ````[0..1, 0..1, 0..1]````. Overridden by texture set ````colorTexture````. Overrides ````colors```` and ````colorsCompressed````. - * @param {Number} [cfg.opacity=1] Opacity in range ````[0..1]````. Overridden by texture set ````colorTexture````. - * @param {Number} [cfg.metallic=0] Metallic factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. - * @param {Number} [cfg.roughness=1] Roughness factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. - */ - createMesh(cfg) { + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); - let id = cfg.id; - if (id === undefined || id === null) { - this.error("Config missing: id"); - return; - } + this._aPosition.bindArrayBuffer(state.positionsBuf); - if (this._meshes[id]) { - this.error(`VBOSceneModel already has a mesh with this ID: ${id}`); - return; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - const geometryId = cfg.geometryId; - const sharingGeometry = (cfg.geometryId !== undefined); - if (sharingGeometry && !this._geometries[cfg.geometryId]) { - this.error(`Geometry not found: ${cfg.geometryId} - ensure that you create it first with createGeometry()`); - return; + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - const textureSetId = cfg.textureSetId || defaultTextureSetId; - if (textureSetId) { - if (!this._textureSets[textureSetId]) { - this.error(`Texture set not found: ${textureSetId} - ensure that you create it first with createTextureSet()`); - return; - } + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - let portionId; - - const color = (cfg.color) ? new Uint8Array([Math.floor(cfg.color[0] * 255), Math.floor(cfg.color[1] * 255), Math.floor(cfg.color[2] * 255)]) : [255, 255, 255]; - const opacity = (cfg.opacity !== undefined && cfg.opacity !== null) ? Math.floor(cfg.opacity * 255) : 255; - const metallic = (cfg.metallic !== undefined && cfg.metallic !== null) ? Math.floor(cfg.metallic * 255) : 0; - const roughness = (cfg.roughness !== undefined && cfg.roughness !== null) ? Math.floor(cfg.roughness * 255) : 255; + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - const mesh = new VBOSceneModelMesh(this, id, color, opacity); + gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); + } - const pickId = mesh.pickId; + _allocate() { - const a = pickId >> 24 & 0xFF; - const b = pickId >> 16 & 0xFF; - const g = pickId >> 8 & 0xFF; - const r = pickId & 0xFF; + const scene = this._scene; + const gl = scene.canvas.gl; - const pickColor = new Uint8Array([r, g, b, a]); // Quantized pick color + this._program = new Program(gl, this._buildShader()); - const aabb = math.collapseAABB3(); + if (this._program.errors) { + this.errors = this._program.errors; + return; + } - let layer; + const program = this._program; - if (sharingGeometry) { + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uColor = program.getLocation("color"); + this._uSectionPlanes = []; - let meshMatrix; - let worldMatrix = this._worldMatrixNonIdentity ? this._worldMatrix : null; + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } - if (cfg.matrix) { - meshMatrix = cfg.matrix; - } else { - const scale = cfg.scale || defaultScale; - const position = cfg.position || defaultPosition; - const rotation = cfg.rotation || defaultRotation; - math.eulerToQuaternion(rotation, "XYZ", defaultQuaternion); - meshMatrix = math.composeMat4(position, defaultQuaternion, scale, tempMat4$1); - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - const cfgOrigin = cfg.origin || cfg.rtcCenter; - const origin = (cfgOrigin) ? math.addVec3(this._origin, cfgOrigin, tempVec3a$9) : this._origin; + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - const instancingLayer = this._getInstancingLayer(origin, textureSetId, geometryId); + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } + } - layer = instancingLayer; + _bindProgram() { - portionId = instancingLayer.createPortion({ - color: color, - metallic: metallic, - roughness: roughness, - opacity: opacity, - meshMatrix: meshMatrix, - worldMatrix: worldMatrix, - aabb: aabb, - pickColor: pickColor - }); + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - math.expandAABB3(this._aabb, aabb); + this._program.bind(); - const numTriangles = Math.round(instancingLayer.numIndices / 3); - this._numTriangles += numTriangles; - mesh.numTriangles = numTriangles; + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - mesh.origin = origin; + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } + } - } else { // Batching + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - let primitive = cfg.primitive; - if (primitive === undefined || primitive === null) { - primitive = "triangles"; - } - if (primitive !== "points" && primitive !== "lines" && primitive !== "triangles" && primitive !== "solid" && primitive !== "surface") { - this.error(`Unsupported value for 'primitive': '${primitive}' ('geometryId' is absent) - supported values are 'points', 'lines', 'triangles', 'solid' and 'surface'.`); - return; - } - if (!cfg.positions && !cfg.positionsCompressed) { - this.error("Param expected: 'positions' or 'positionsCompressed' ('geometryId' is absent)"); - return null; - } - if (cfg.positions && cfg.positionsCompressed) { - this.error("Only one param expected, not both: 'positions' or 'positionsCompressed' ('geometryId' is absent)"); - return null; - } - if (cfg.positionsCompressed && !cfg.positionsDecodeMatrix) { - this.error("Param expected: 'positionsDecodeMatrix' (required for 'positionsCompressed'; 'geometryId' is absent)"); - return null; - } - if (cfg.uvCompressed && !cfg.uvDecodeMatrix) { - this.error("Param expected: `uvDecodeMatrix` (required for `uvCompressed'; 'geometryId' is absent)"); - return null; - } - if (!cfg.indices && primitive !== "points") { - this.error(`Param expected: indices (required for '${primitive}' primitive type)`); - return null; - } - if (!cfg.indices && primitive !== "points") { - this.error("Config expected: indices (no meshIds provided, so expecting geometry arrays instead)"); - return null; - } + _buildVertexShader() { - let indices = cfg.indices; - let edgeIndices = cfg.edgeIndices; - let origin = (cfg.origin || cfg.rtcCenter) ? math.addVec3(this._origin, cfg.origin || cfg.rtcCenter, tempVec3a$9) : this._origin; - let positions = cfg.positions; + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batching silhouette vertex shader"); + src.push("uniform int renderPass;"); - if (positions) { - const rtcCenter = math.vec3(); - const rtcPositions = []; - const rtcNeeded = worldToRTCPositions(positions, rtcPositions, rtcCenter); - if (rtcNeeded) { - positions = rtcPositions; - origin = math.addVec3(origin, rtcCenter, rtcCenter); - } - } - - let needNewBatchingLayers = false; - - if (!this._lastOrigin) { - needNewBatchingLayers = true; - this._lastOrigin = math.vec3(origin); - } else { - if (!math.compareVec3(this._lastOrigin, origin)) { - needNewBatchingLayers = true; - this._lastOrigin.set(origin); - } - } - if (cfg.positionsDecodeMatrix) { - if (!this._lastPositionsDecodeMatrix) { - needNewBatchingLayers = true; - this._lastPositionsDecodeMatrix = math.mat4(cfg.positionsDecodeMatrix); - - } else { - if (!math.compareMat4(this._lastPositionsDecodeMatrix, cfg.positionsDecodeMatrix)) { - needNewBatchingLayers = true; - this._lastPositionsDecodeMatrix.set(cfg.positionsDecodeMatrix); - } - } - } - if (cfg.uvDecodeMatrix) { - if (!this._lastUVDecodeMatrix) { - needNewBatchingLayers = true; - this._lastUVDecodeMatrix = math.mat4(cfg.uvDecodeMatrix); - - } else { - if (!math.compareMat4(this._lastUVDecodeMatrix, cfg.uvDecodeMatrix)) { - needNewBatchingLayers = true; - this._lastUVDecodeMatrix.set(cfg.uvDecodeMatrix); - } - } - } - if (cfg.textureSetId) { - if (this._lastTextureSetId !== cfg.textureSetId) { - needNewBatchingLayers = true; - this._lastTextureSetId = cfg.textureSetId; - } - } - if (needNewBatchingLayers) { - for (let prim in this._currentBatchingLayers) { - if (this._currentBatchingLayers.hasOwnProperty(prim)) { - this._currentBatchingLayers[prim].finalize(); - } - } - this._currentBatchingLayers = {}; - } - - const normalsProvided = (!!cfg.normals && cfg.normals.length > 0); - if (primitive === "triangles" || primitive === "solid" || primitive === "surface") { - if (this._lastNormals !== null && normalsProvided !== this._lastNormals) { - ["triangles", "solid", "surface"].map(primitiveId => { - if (this._currentBatchingLayers[primitiveId]) { - this._currentBatchingLayers[primitiveId].finalize(); - delete this._currentBatchingLayers[primitiveId]; - } - }); - } - this._lastNormals = normalsProvided; - } - - const worldMatrix = this._worldMatrixNonIdentity ? this._worldMatrix : null; - let meshMatrix; - - if (!cfg.positionsDecodeMatrix) { - if (cfg.matrix) { - meshMatrix = cfg.matrix; - } else { - const scale = cfg.scale || defaultScale; - const position = cfg.position || defaultPosition; - const rotation = cfg.rotation || defaultRotation; - math.eulerToQuaternion(rotation, "XYZ", defaultQuaternion); - meshMatrix = math.composeMat4(position, defaultQuaternion, scale, tempMat4$1); - } - } - - const textureSet = textureSetId ? this._textureSets[textureSetId] : null; - - layer = this._currentBatchingLayers[primitive]; - - const lenPositions = (positions || cfg.positionsCompressed).length; - - switch (primitive) { - case "triangles": - case "solid": - case "surface": - if (layer) { - if (!layer.canCreatePortion(lenPositions, indices.length)) { - layer.finalize(); - delete this._currentBatchingLayers[primitive]; - layer = null; - } - } - if (!layer) { - layer = new TrianglesBatchingLayer({ - model: this, - textureSet: textureSet, - layerIndex: 0, // This is set in #finalize() - scratchMemory: this._scratchMemory, - positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined - uvDecodeMatrix: cfg.uvDecodeMatrix, // Can be undefined - origin, - maxGeometryBatchSize: this._maxGeometryBatchSize, - solid: (primitive === "solid"), - autoNormals: (!normalsProvided) - }); - this._layerList.push(layer); - this._currentBatchingLayers[primitive] = layer; - } - if (!edgeIndices) { - edgeIndices = buildEdgeIndices(positions || cfg.positionsCompressed, indices, null, this._edgeThreshold); - } - portionId = layer.createPortion({ - positions: positions, - positionsCompressed: cfg.positionsCompressed, - normals: cfg.normals, - normalsCompressed: cfg.normalsCompressed, - colors: cfg.colors, - colorsCompressed: cfg.colorsCompressed, - uv: cfg.uv, - uvCompressed: cfg.uvCompressed, - indices: indices, - edgeIndices: edgeIndices, - color: color, - opacity: opacity, - metallic: metallic, - roughness: roughness, - meshMatrix: meshMatrix, - worldMatrix: worldMatrix, - worldAABB: aabb, - pickColor: pickColor - }); - const numTriangles = Math.round(indices.length / 3); - this._numTriangles += numTriangles; - mesh.numTriangles = numTriangles; - break; + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + src.push("uniform vec4 color;"); - case "lines": - if (layer) { - if (!layer.canCreatePortion(lenPositions, indices.length)) { - layer.finalize(); - delete this._currentBatchingLayers[primitive]; - layer = null; - } - } - if (!layer) { - layer = new LinesBatchingLayer({ - model: this, - layerIndex: 0, // This is set in #finalize() - scratchMemory: this._scratchMemory, - positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined - origin, - maxGeometryBatchSize: this._maxGeometryBatchSize - }); - this._layerList.push(layer); - this._currentBatchingLayers[primitive] = layer; - } - portionId = layer.createPortion({ - positions: positions, - positionsCompressed: cfg.positionsCompressed, - indices: indices, - colors: cfg.colors, - colorsCompressed: cfg.colorsCompressed, - color: color, - opacity: opacity, - meshMatrix: meshMatrix, - worldMatrix: worldMatrix, - worldAABB: aabb, - pickColor: pickColor - }); - this._numLines += Math.round(indices.length / 2); - break; + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); + } - case "points": - if (layer) { - if (!layer.canCreatePortion(lenPositions)) { - layer.finalize(); - delete this._currentBatchingLayers[primitive]; - layer = null; - } - } - if (!layer) { - layer = new PointsBatchingLayer({ - model: this, - layerIndex: 0, // This is set in #finalize() - scratchMemory: this._scratchMemory, - positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined - origin, - maxGeometryBatchSize: this._maxGeometryBatchSize - }); - this._layerList.push(layer); - this._currentBatchingLayers[primitive] = layer; - } - portionId = layer.createPortion({ - positions: positions, - positionsCompressed: cfg.positionsCompressed, - colors: cfg.colors, - colorsCompressed: cfg.colorsCompressed, - color: color, - opacity: opacity, - meshMatrix: meshMatrix, - worldMatrix: worldMatrix, - worldAABB: aabb, - pickColor: pickColor - }); - this._numPoints += Math.round(lenPositions / 3); - break; - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - math.expandAABB3(this._aabb, aabb); - this.numGeometries++; - mesh.origin = origin; + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - mesh.parent = null; // Will be set within PerformanceModelNode constructor - mesh._layer = layer; - mesh._portionId = portionId; - mesh.aabb = aabb; + src.push("void main(void) {"); - this._meshes[id] = mesh; - } + // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | SILHOUETTE_XRAYED + // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - _getInstancingLayer(origin, textureSetId, geometryId) { - const layerId = `${origin[0]}.${origin[1]}.${origin[2]}.${textureSetId}.${geometryId}`; - let instancingLayer = this._instancingLayers[layerId]; - if (instancingLayer) { - return instancingLayer; + src.push(`if (int(flags.y) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); + + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - let textureSet; - if (textureSetId !== undefined) { - textureSet = this._textureSets[textureSetId]; - if (!textureSet) { - this.error(`TextureSet not found: ${textureSetId} - ensure that you create it first with createTextureSet()`); - return; - } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); } - const geometry = this._geometries[geometryId]; - if (!this._geometries[geometryId]) { - this.error(`Geometry not found: ${geometryId} - ensure that you create it first with createGeometry()`); - return; + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } - switch (geometry.primitive) { - case "triangles": - instancingLayer = new TrianglesInstancingLayer({ - model: this, - textureSet, - geometry, - origin, - layerIndex: 0, - solid: false - }); - break; - case "solid": - instancingLayer = new TrianglesInstancingLayer({ - model: this, - textureSet, - geometry, - origin, - layerIndex: 0, - solid: true - }); - break; - case "surface": - instancingLayer = new TrianglesInstancingLayer({ - model: this, - textureSet, - geometry, - origin, - layerIndex: 0, - solid: false - }); - break; - case "lines": - instancingLayer = new LinesInstancingLayer({ - model: this, - textureSet, - geometry, - origin, - layerIndex: 0 - }); - break; - case "points": - instancingLayer = new PointsInstancingLayer({ - model: this, - textureSet, - geometry, - origin, - layerIndex: 0 - }); - break; + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); } - this._instancingLayers[layerId] = instancingLayer; - this._layerList.push(instancingLayer); - return instancingLayer; + src.push("}"); + src.push("}"); + return src; } - /** - * Creates an {@link Entity} within this VBOSceneModel, giving it one or more meshes previously created with {@link VBOSceneModel#createMesh}. - * - * A mesh can only belong to one {@link Entity}, so you'll get an error if you try to reuse a mesh among multiple {@link Entity}s. - * - * @param {Object} cfg Entity configuration. - * @param {String} cfg.id Optional ID for the new Entity. Must not clash with any existing components within the {@link Scene}. - * @param {String[]} cfg.meshIds IDs of one or more meshes created previously with {@link VBOSceneModel@createMesh}. - - * @param {Boolean} [cfg.isObject] Set ````true```` if the {@link Entity} represents an object, in which case it will be registered by {@link Entity#id} in {@link Scene#objects} and can also have a corresponding {@link MetaObject} with matching {@link MetaObject#id}, registered by that ID in {@link MetaScene#metaObjects}. - * @param {Boolean} [cfg.visible=true] Indicates if the Entity is initially visible. - * @param {Boolean} [cfg.culled=false] Indicates if the Entity is initially culled from view. - * @param {Boolean} [cfg.pickable=true] Indicates if the Entity is initially pickable. - * @param {Boolean} [cfg.clippable=true] Indicates if the Entity is initially clippable. - * @param {Boolean} [cfg.collidable=true] Indicates if the Entity is initially included in boundary calculations. - * @param {Boolean} [cfg.castsShadow=true] Indicates if the Entity initially casts shadows. - * @param {Boolean} [cfg.receivesShadow=true] Indicates if the Entity initially receives shadows. - * @param {Boolean} [cfg.xrayed=false] Indicates if the Entity is initially xrayed. XRayed appearance is configured by {@link VBOSceneModel#xrayMaterial}. - * @param {Boolean} [cfg.highlighted=false] Indicates if the Entity is initially highlighted. Highlighted appearance is configured by {@link VBOSceneModel#highlightMaterial}. - * @param {Boolean} [cfg.selected=false] Indicates if the Entity is initially selected. Selected appearance is configured by {@link VBOSceneModel#selectedMaterial}. - * @param {Boolean} [cfg.edges=false] Indicates if the Entity's edges are initially emphasized. Edges appearance is configured by {@link VBOSceneModel#edgeMaterial}. - * @returns {Entity} - */ - createEntity(cfg) { - // Validate or generate Entity ID - let id = cfg.id; - if (id === undefined) { - id = math.createUUID(); - } else if (this.scene.components[id]) { - this.error("Scene already has a Component with this ID: " + id + " - will assign random ID"); - id = math.createUUID(); - } - // Collect PerformanceModelNode's PerformanceModelMeshes - const meshIds = cfg.meshIds; - if (meshIds === undefined) { - this.error("Config missing: meshIds"); - return; + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + let i; + let len; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batching silhouette vertex shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - let meshes = []; - for (let i = 0, len = meshIds.length; i < len; i++) { - const meshId = meshIds[i]; - const mesh = this._meshes[meshId]; - if (!mesh) { - this.error("Mesh with this ID not found: " + meshId + " - ignoring this mesh"); - continue; - } - if (mesh.parent) { - this.error("Mesh with ID " + meshId + " already belongs to object with ID " + mesh.parent.id + " - ignoring this mesh"); - continue; + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } - meshes.push(mesh); - } - // Create PerformanceModelNode flags - let flags = 0; - if (this._visible && cfg.visible !== false) { - flags = flags | ENTITY_FLAGS.VISIBLE; - } - if (this._pickable && cfg.pickable !== false) { - flags = flags | ENTITY_FLAGS.PICKABLE; - } - if (this._culled && cfg.culled !== false) { - flags = flags | ENTITY_FLAGS.CULLED; - } - if (this._clippable && cfg.clippable !== false) { - flags = flags | ENTITY_FLAGS.CLIPPABLE; - } - if (this._collidable && cfg.collidable !== false) { - flags = flags | ENTITY_FLAGS.COLLIDABLE; - } - if (this._edges && cfg.edges !== false) { - flags = flags | ENTITY_FLAGS.EDGES; - } - if (this._xrayed && cfg.xrayed !== false) { - flags = flags | ENTITY_FLAGS.XRAYED; - } - if (this._highlighted && cfg.highlighted !== false) { - flags = flags | ENTITY_FLAGS.HIGHLIGHTED; } - if (this._selected && cfg.selected !== false) { - flags = flags | ENTITY_FLAGS.SELECTED; + src.push("uniform vec4 color;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); } - // Create PerformanceModelNode AABB - let aabb; - if (meshes.length === 1) { - aabb = meshes[0].aabb; - } else { - aabb = math.collapseAABB3(); - for (let i = 0, len = meshes.length; i < len; i++) { - math.expandAABB3(aabb, meshes[i].aabb); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } + src.push(" if (dist > 0.0) { discard; }"); + src.push("}"); } - const node = new VBOSceneModelNode(this, cfg.isObject, id, meshes, flags, aabb); // Internally sets PerformanceModelMesh#parent to this PerformanceModelNode - this._nodeList.push(node); - this._nodes[id] = node; - this.numEntities++; - return node; + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("outColor = color;"); + src.push("}"); + return src; } - /** - * Finalizes this VBOSceneModel. - * - * Immediately creates the VBOSceneModel's {@link Entity}s within the {@link Scene}. - * - * Once finalized, you can't add anything more to this VBOSceneModel. - */ - finalize() { + webglContextRestored() { + this._program = null; + } - if (this.destroyed) { - return; + destroy() { + if (this._program) { + this._program.destroy(); } + this._program = null; + } +} - for (const layerId in this._instancingLayers) { - if (this._instancingLayers.hasOwnProperty(layerId)) { - this._instancingLayers[layerId].finalize(); - } - } +const tempVec3a$j = math.vec3(); - for (let layerId in this._currentBatchingLayers) { - if (this._currentBatchingLayers.hasOwnProperty(layerId)) { - this._currentBatchingLayers[layerId].finalize(); - } - } - this._currentBatchingLayers = {}; +/** + * @private + */ +class PointsBatchingPickMeshRenderer { - for (let i = 0, len = this._nodeList.length; i < len; i++) { - const node = this._nodeList[i]; - node._finalize(); - } + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - for (let i = 0, len = this._nodeList.length; i < len; i++) { - const node = this._nodeList[i]; - node._finalize2(); - } + getValid() { + return this._hash === this._getHash(); + }; - // Sort layers to reduce WebGL shader switching when rendering them + _getHash() { + return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash); + } - this._layerList.sort((a, b) => { - if (a.sortId < b.sortId) { - return -1; - } - if (a.sortId > b.sortId) { - return 1; - } - return 0; - }); + drawLayer(frameCtx, pointsBatchingLayer, renderPass) { - for (let i = 0, len = this._layerList.length; i < len; i++) { - const layer = this._layerList[i]; - layer.layerIndex = i; + const model = pointsBatchingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = pointsBatchingLayer._state; + const origin = pointsBatchingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + + if (!this._program) { + this._allocate(pointsBatchingLayer); } - this.glRedraw(); + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx); + } - this.scene._aabbDirty = true; - } + gl.uniform1i(this._uRenderPass, renderPass); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - _rebuildAABB() { - math.collapseAABB3(this._aabb); - for (let i = 0, len = this._nodeList.length; i < len; i++) { - const node = this._nodeList[i]; - math.expandAABB3(this._aabb, node.aabb); - } - this._aabbDirty = false; - } + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - /** @private */ - stateSortCompare(drawable1, drawable2) { - } + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); - /** @private */ - rebuildRenderFlags() { - this.renderFlags.reset(); - this._updateRenderFlagsVisibleLayers(); - if (this.renderFlags.numLayers > 0 && this.renderFlags.numVisibleLayers === 0) { - this.renderFlags.culled = true; - return; + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - this._updateRenderFlags(); - } - /** - * @private - */ - _updateRenderFlagsVisibleLayers() { - const renderFlags = this.renderFlags; - renderFlags.numLayers = this._layerList.length; - renderFlags.numVisibleLayers = 0; - for (let layerIndex = 0, len = this._layerList.length; layerIndex < len; layerIndex++) { - const layer = this._layerList[layerIndex]; - const layerVisible = this._getActiveSectionPlanesForLayer(layer); - if (layerVisible) { - renderFlags.visibleLayers[renderFlags.numVisibleLayers++] = layerIndex; + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$j); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } } } - } - /** @private */ - _getActiveSectionPlanesForLayer(layer) { + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); - const renderFlags = this.renderFlags; - const sectionPlanes = this.scene._sectionPlanesState.sectionPlanes; - const numSectionPlanes = sectionPlanes.length; - const baseIndex = layer.layerIndex * numSectionPlanes; + this._aPosition.bindArrayBuffer(state.positionsBuf); - if (numSectionPlanes > 0) { - for (let i = 0; i < numSectionPlanes; i++) { + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + } - const sectionPlane = sectionPlanes[i]; + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); + } - if (!sectionPlane.active) { - renderFlags.sectionPlanesActivePerLayer[baseIndex + i] = false; + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + } - } else { - renderFlags.sectionPlanesActivePerLayer[baseIndex + i] = true; - renderFlags.sectioned = true; - } - } + if (this._aPickColor) { + this._aPickColor.bindArrayBuffer(state.pickColorsBuf); } - return true; + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + + gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); } - /** @private */ - _updateRenderFlags() { + _allocate() { - if (this.numVisibleLayerPortions === 0) { - return; - } + const scene = this._scene; + const gl = scene.canvas.gl; - if (this.numCulledLayerPortions === this.numPortions) { + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; return; } - const renderFlags = this.renderFlags; + const program = this._program; - renderFlags.colorOpaque = (this.numTransparentLayerPortions < this.numPortions); + this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - if (this.numTransparentLayerPortions > 0) { - renderFlags.colorTransparent = true; - } + this._uSectionPlanes = []; - if (this.numXRayedLayerPortions > 0) { - const xrayMaterial = this.scene.xrayMaterial._state; - if (xrayMaterial.fill) { - if (xrayMaterial.fillAlpha < 1.0) { - renderFlags.xrayedSilhouetteTransparent = true; - } else { - renderFlags.xrayedSilhouetteOpaque = true; - } - } - if (xrayMaterial.edges) { - if (xrayMaterial.edgeAlpha < 1.0) { - renderFlags.xrayedEdgesTransparent = true; - } else { - renderFlags.xrayedEdgesOpaque = true; - } - } + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - if (this.numEdgesLayerPortions > 0) { - const edgeMaterial = this.scene.edgeMaterial._state; - if (edgeMaterial.edges) { - renderFlags.edgesOpaque = (this.numTransparentLayerPortions < this.numPortions); - if (this.numTransparentLayerPortions > 0) { - renderFlags.edgesTransparent = true; - } - } - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aPickColor = program.getAttribute("pickColor"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - if (this.numSelectedLayerPortions > 0) { - const selectedMaterial = this.scene.selectedMaterial._state; - if (selectedMaterial.fill) { - if (selectedMaterial.fillAlpha < 1.0) { - renderFlags.selectedSilhouetteTransparent = true; - } else { - renderFlags.selectedSilhouetteOpaque = true; - } - } - if (selectedMaterial.edges) { - if (selectedMaterial.edgeAlpha < 1.0) { - renderFlags.selectedEdgesTransparent = true; - } else { - renderFlags.selectedEdgesOpaque = true; - } - } - } + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - if (this.numHighlightedLayerPortions > 0) { - const highlightMaterial = this.scene.highlightMaterial._state; - if (highlightMaterial.fill) { - if (highlightMaterial.fillAlpha < 1.0) { - renderFlags.highlightedSilhouetteTransparent = true; - } else { - renderFlags.highlightedSilhouetteOpaque = true; - } - } - if (highlightMaterial.edges) { - if (highlightMaterial.edgeAlpha < 1.0) { - renderFlags.highlightedEdgesTransparent = true; - } else { - renderFlags.highlightedEdgesOpaque = true; - } - } + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - // -------------- RENDERING --------------------------------------------------------------------------------------- - - /** @private */ - drawColorOpaque(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawColorOpaque(renderFlags, frameCtx); - } + _bindProgram(frameCtx) { + const scene = this._scene; + const gl = scene.canvas.gl; + this._program.bind(); + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); } - /** @private */ - drawColorTransparent(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawColorTransparent(renderFlags, frameCtx); - } + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - /** @private */ - drawDepth(frameCtx) { // Dedicated to SAO because it skips transparent objects - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawDepth(renderFlags, frameCtx); - } - } + _buildVertexShader() { - /** @private */ - drawNormals(frameCtx) { // Dedicated to SAO because it skips transparent objects - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawNormals(renderFlags, frameCtx); - } - } + const scene = this._scene; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batching pick mesh vertex shader"); + src.push("uniform int renderPass;"); - /** @private */ - drawSilhouetteXRayed(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawSilhouetteXRayed(renderFlags, frameCtx); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - /** @private */ - drawSilhouetteHighlighted(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawSilhouetteHighlighted(renderFlags, frameCtx); - } - } + src.push("in vec4 pickColor;"); - /** @private */ - drawSilhouetteSelected(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawSilhouetteSelected(renderFlags, frameCtx); - } - } + src.push("uniform bool pickInvisible;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - /** @private */ - drawEdgesColorOpaque(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawEdgesColorOpaque(renderFlags, frameCtx); + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); } - } - /** @private */ - drawEdgesColorTransparent(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawEdgesColorTransparent(renderFlags, frameCtx); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); } - } - /** @private */ - drawEdgesXRayed(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawEdgesXRayed(renderFlags, frameCtx); + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - } - /** @private */ - drawEdgesHighlighted(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawEdgesHighlighted(renderFlags, frameCtx); - } - } + src.push("out vec4 vPickColor;"); - /** @private */ - drawEdgesSelected(frameCtx) { - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawEdgesSelected(renderFlags, frameCtx); - } - } + src.push("void main(void) {"); - /** - * @private - */ - drawOcclusion(frameCtx) { - if (this.numVisibleLayerPortions === 0) { - return; + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK + + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawOcclusion(renderFlags, frameCtx); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - } - - /** - * @private - */ - drawShadow(frameCtx) { - if (this.numVisibleLayerPortions === 0) { - return; + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawShadow(renderFlags, frameCtx); + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); } + src.push("gl_PointSize += 10.0;"); + src.push(" }"); + src.push("}"); + return src; } - /** @private */ - drawPickMesh(frameCtx) { - if (this.numVisibleLayerPortions === 0) { - return; + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batching pick mesh vertex shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawPickMesh(renderFlags, frameCtx); + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } } - } - - /** - * Called by VBOSceneModelMesh.drawPickDepths() - * @private - */ - drawPickDepths(frameCtx) { - if (this.numVisibleLayerPortions === 0) { - return; + src.push("in vec4 vPickColor;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); } - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawPickDepths(renderFlags, frameCtx); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" outColor = vPickColor; "); + src.push("}"); + return src; } - /** - * Called by VBOSceneModelMesh.drawPickNormals() - * @private - */ - drawPickNormals(frameCtx) { - if (this.numVisibleLayerPortions === 0) { - return; - } - const renderFlags = this.renderFlags; - for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { - const layerIndex = renderFlags.visibleLayers[i]; - this._layerList[layerIndex].drawPickNormals(renderFlags, frameCtx); - } + webglContextRestored() { + this._program = null; } - //------------------------------------------------------------------------------------------------------------------ - // Component members - //------------------------------------------------------------------------------------------------------------------ - - /** - * Destroys this VBOSceneModel. - */ destroy() { - for (let layerId in this._currentBatchingLayers) { - if (this._currentBatchingLayers.hasOwnProperty(layerId)) { - this._currentBatchingLayers[layerId].destroy(); - } - } - this._currentBatchingLayers = {}; - this.scene.camera.off(this._onCameraViewMatrix); - for (let i = 0, len = this._layerList.length; i < len; i++) { - this._layerList[i].destroy(); - } - for (let i = 0, len = this._nodeList.length; i < len; i++) { - this._nodeList[i]._destroy(); - } - Object.entries(this._geometries).forEach(([key, geometry]) => { - geometry.destroy(); - }); - this._geometries = {}; - this._textures = {}; - this._textureSets = {}; - this._meshes = {}; - this._nodes = {}; - this.scene._aabbDirty = true; - if (this._isModel) { - this.scene._deregisterModel(this); + if (this._program) { + this._program.destroy(); } - putScratchMemory(); - super.destroy(); + this._program = null; } } -const angleAxis = math.vec4(4); -const q1 = math.vec4(); -const q2 = math.vec4(); -const xAxis = math.vec3([1, 0, 0]); -const yAxis = math.vec3([0, 1, 0]); -const zAxis = math.vec3([0, 0, 1]); - -const veca = math.vec3(3); -const vecb = math.vec3(3); - -const identityMat = math.identityMat4(); +const tempVec3a$i = math.vec3(); /** - * @desc An {@link Entity} that is a scene graph node that can have child Nodes and {@link Mesh}es. - * - * ## Usage - * - * The example below is the same as the one given for {@link Mesh}, since the two classes work together. In this example, - * we'll create a scene graph in which a root Node represents a group and the {@link Mesh}s are leaves. Since Node - * implements {@link Entity}, we can designate the root Node as a model, causing it to be registered by its ID in {@link Scene#models}. - * - * Since {@link Mesh} also implements {@link Entity}, we can designate the leaf {@link Mesh}es as objects, causing them to - * be registered by their IDs in {@link Scene#objects}. - * - * We can then find those {@link Entity} types in {@link Scene#models} and {@link Scene#objects}. - * - * We can also update properties of our object-Meshes via calls to {@link Scene#setObjectsHighlighted} etc. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_SceneGraph)] - * - * ````javascript - * import {Viewer, Mesh, Node, PhongMaterial} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; - * viewer.scene.camera.look = [0, -5.75, 0]; - * viewer.scene.camera.up = [0.37, 0.91, -0.11]; - * - * new Node(viewer.scene, { - * id: "table", - * isModel: true, // <---------- Node represents a model, so is registered by ID in viewer.scene.models - * rotation: [0, 50, 0], - * position: [0, 0, 0], - * scale: [1, 1, 1], - * - * children: [ - * - * new Mesh(viewer.scene, { // Red table leg - * id: "redLeg", - * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects - * position: [-4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * material: new PhongMaterial(viewer.scene, { - * diffuse: [1, 0.3, 0.3] - * }) - * }), - * - * new Mesh(viewer.scene, { // Green table leg - * id: "greenLeg", - * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects - * position: [4, -6, -4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * material: new PhongMaterial(viewer.scene, { - * diffuse: [0.3, 1.0, 0.3] - * }) - * }), - * - * new Mesh(viewer.scene, {// Blue table leg - * id: "blueLeg", - * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects - * position: [4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * material: new PhongMaterial(viewer.scene, { - * diffuse: [0.3, 0.3, 1.0] - * }) - * }), - * - * new Mesh(viewer.scene, { // Yellow table leg - * id: "yellowLeg", - * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects - * position: [-4, -6, 4], - * scale: [1, 3, 1], - * rotation: [0, 0, 0], - * material: new PhongMaterial(viewer.scene, { - * diffuse: [1.0, 1.0, 0.0] - * }) - * }), - * - * new Mesh(viewer.scene, { // Purple table top - * id: "tableTop", - * isObject: true, // <------ Node represents an object, so is registered by ID in viewer.scene.objects - * position: [0, -3, 0], - * scale: [6, 0.5, 6], - * rotation: [0, 0, 0], - * material: new PhongMaterial(viewer.scene, { - * diffuse: [1.0, 0.3, 1.0] - * }) - * }) - * ] - * }); - * - * // Find Nodes and Meshes by their IDs - * - * var table = viewer.scene.models["table"]; // Since table Node has isModel == true - * - * var redLeg = viewer.scene.objects["redLeg"]; // Since the Meshes have isObject == true - * var greenLeg = viewer.scene.objects["greenLeg"]; - * var blueLeg = viewer.scene.objects["blueLeg"]; - * - * // Highlight one of the table leg Meshes - * - * viewer.scene.setObjectsHighlighted(["redLeg"], true); // Since the Meshes have isObject == true - * - * // Periodically update transforms on our Nodes and Meshes - * - * viewer.scene.on("tick", function () { - * - * // Rotate legs - * redLeg.rotateY(0.5); - * greenLeg.rotateY(0.5); - * blueLeg.rotateY(0.5); - * - * // Rotate table - * table.rotateY(0.5); - * table.rotateX(0.3); - * }); - * ```` - * - * ## Metadata - * - * As mentioned, we can also associate {@link MetaModel}s and {@link MetaObject}s with our Nodes and {@link Mesh}es, - * within a {@link MetaScene}. See {@link MetaScene} for an example. - * - * @implements {Entity} + * @private */ -class Node$1 extends Component { - - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent scene, generated automatically when omitted. - * @param {Boolean} [cfg.isModel] Specify ````true```` if this Mesh represents a model, in which case the Mesh will be registered by {@link Mesh#id} in {@link Scene#models} and may also have a corresponding {@link MetaModel} with matching {@link MetaModel#id}, registered by that ID in {@link MetaScene#metaModels}. - * @param {Boolean} [cfg.isObject] Specify ````true```` if this Mesh represents an object, in which case the Mesh will be registered by {@link Mesh#id} in {@link Scene#objects} and may also have a corresponding {@link MetaObject} with matching {@link MetaObject#id}, registered by that ID in {@link MetaScene#metaObjects}. - * @param {Node} [cfg.parent] The parent Node. - * @param {Number[]} [cfg.origin] World-space origin for this Node. - * @param {Number[]} [cfg.rtcCenter] Deprecated - renamed to ````origin````. - * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position. - * @param {Number[]} [cfg.scale=[1,1,1]] Local scale. - * @param {Number[]} [cfg.rotation=[0,0,0]] Local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] Local modelling transform matrix. Overrides the position, scale and rotation parameters. - * @param {Number[]} [cfg.offset=[0,0,0]] World-space 3D translation offset. Translates the Node in World space, after modelling transforms. - * @param {Boolean} [cfg.visible=true] Indicates if the Node is initially visible. - * @param {Boolean} [cfg.culled=false] Indicates if the Node is initially culled from view. - * @param {Boolean} [cfg.pickable=true] Indicates if the Node is initially pickable. - * @param {Boolean} [cfg.clippable=true] Indicates if the Node is initially clippable. - * @param {Boolean} [cfg.collidable=true] Indicates if the Node is initially included in boundary calculations. - * @param {Boolean} [cfg.castsShadow=true] Indicates if the Node initially casts shadows. - * @param {Boolean} [cfg.receivesShadow=true] Indicates if the Node initially receives shadows. - * @param {Boolean} [cfg.xrayed=false] Indicates if the Node is initially xrayed. - * @param {Boolean} [cfg.highlighted=false] Indicates if the Node is initially highlighted. - * @param {Boolean} [cfg.selected=false] Indicates if the Mesh is initially selected. - * @param {Boolean} [cfg.edges=false] Indicates if the Node's edges are initially emphasized. - * @param {Number[]} [cfg.colorize=[1.0,1.0,1.0]] Node's initial RGB colorize color, multiplies by the rendered fragment colors. - * @param {Number} [cfg.opacity=1.0] Node's initial opacity factor, multiplies by the rendered fragment alpha. - * @param {Array} [cfg.children] Child Nodes or {@link Mesh}es to add initially. Children must be in the same {@link Scene} and will be removed first from whatever parents they may already have. - * @param {Boolean} [cfg.inheritStates=true] Indicates if children given to this constructor should inherit rendering state from this parent as they are added. Rendering state includes {@link Node#visible}, {@link Node#culled}, {@link Node#pickable}, {@link Node#clippable}, {@link Node#castsShadow}, {@link Node#receivesShadow}, {@link Node#selected}, {@link Node#highlighted}, {@link Node#colorize} and {@link Node#opacity}. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - this._parentNode = null; - this._children = []; - - this._aabb = null; - this._aabbDirty = true; +class PointsBatchingPickDepthRenderer { - this.scene._aabbDirty = true; + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - this._numTriangles = 0; + getValid() { + return this._hash === this._getHash(); + }; - this._scale = math.vec3(); - this._quaternion = math.identityQuaternion(); - this._rotation = math.vec3(); - this._position = math.vec3(); - this._offset = math.vec3(); + _getHash() { + return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash); + } - this._localMatrix = math.identityMat4(); - this._worldMatrix = math.identityMat4(); + drawLayer(frameCtx, pointsBatchingLayer, renderPass) { - this._localMatrixDirty = true; - this._worldMatrixDirty = true; + const model = pointsBatchingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = pointsBatchingLayer._state; + const origin = pointsBatchingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; - if (cfg.matrix) { - this.matrix = cfg.matrix; - } else { - this.scale = cfg.scale; - this.position = cfg.position; - if (cfg.quaternion) ; else { - this.rotation = cfg.rotation; - } + if (!this._program) { + this._allocate(); } - this._isModel = cfg.isModel; - if (this._isModel) { - this.scene._registerModel(this); + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); } - this._isObject = cfg.isObject; - if (this._isObject) { - this.scene._registerObject(this); - } + gl.uniform1i(this._uRenderPass, renderPass); - this.origin = cfg.origin; - this.visible = cfg.visible; - this.culled = cfg.culled; - this.pickable = cfg.pickable; - this.clippable = cfg.clippable; - this.collidable = cfg.collidable; - this.castsShadow = cfg.castsShadow; - this.receivesShadow = cfg.receivesShadow; - this.xrayed = cfg.xrayed; - this.highlighted = cfg.highlighted; - this.selected = cfg.selected; - this.edges = cfg.edges; - this.colorize = cfg.colorize; - this.opacity = cfg.opacity; - this.offset = cfg.offset; + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - // Add children, which inherit state from this Node + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const viewMatrix = origin ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - if (cfg.children) { - const children = cfg.children; - for (let i = 0, len = children.length; i < len; i++) { - this.addChild(children[i], cfg.inheritStates); - } + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uViewMatrix, false, viewMatrix); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + + gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); + gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - if (cfg.parentId) { - const parentNode = this.scene.components[cfg.parentId]; - if (!parentNode) { - this.error("Parent not found: '" + cfg.parentId + "'"); - } else if (!parentNode.isNode) { - this.error("Parent is not a Node: '" + cfg.parentId + "'"); - } else { - parentNode.addChild(this); - } - } else if (cfg.parent) { - if (!cfg.parent.isNode) { - this.error("Parent is not a Node"); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$i); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } } - cfg.parent.addChild(this); } - } - //------------------------------------------------------------------------------------------------------------------ - // Entity members - //------------------------------------------------------------------------------------------------------------------ - - /** - * Returns true to indicate that this Component is an Entity. - * @type {Boolean} - */ - get isEntity() { - return true; - } + //============================================================= + // TODO: Use drawElements count and offset to draw only one entity + //============================================================= - /** - * Returns ````true```` if this Mesh represents a model. - * - * When this returns ````true````, the Mesh will be registered by {@link Mesh#id} in {@link Scene#models} and - * may also have a corresponding {@link MetaModel}. - * - * @type {Boolean} - */ - get isModel() { - return this._isModel; - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); - /** - * Returns ````true```` if this Node represents an object. - * - * When ````true```` the Node will be registered by {@link Node#id} in - * {@link Scene#objects} and may also have a {@link MetaObject} with matching {@link MetaObject#id}. - * - * @type {Boolean} - * @abstract - */ - get isObject() { - return this._isObject; - } + this._aPosition.bindArrayBuffer(state.positionsBuf); - /** - * Gets the Node's World-space 3D axis-aligned bounding box. - * - * Represented by a six-element Float64Array containing the min/max extents of the - * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. - * - * @type {Number[]} - */ - get aabb() { - if (this._aabbDirty) { - this._updateAABB(); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - return this._aabb; - } - /** - * Sets the World-space origin for this Node. - * - * @type {Float64Array} - */ - set origin(origin) { - if (origin) { - if (!this._origin) { - this._origin = math.vec3(); - } - this._origin.set(origin); - } else { - if (this._origin) { - this._origin = null; - } + if (this._aFlags) { + this._aFlags.bindArrayBuffer(state.flagsBuf); } - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].origin = origin; + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); } - this.glRedraw(); - } - /** - * Gets the World-space origin for this Node. - * - * @type {Float64Array} - */ - get origin() { - return this._origin; - } + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - /** - * Sets the World-space origin for this Node. - * - * Deprecated and replaced by {@link Node#origin}. - * - * @deprecated - * @type {Float64Array} - */ - set rtcCenter(rtcCenter) { - this.origin = rtcCenter; + gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); } - /** - * Gets the World-space origin for this Node. - * - * Deprecated and replaced by {@link Node#origin}. - * - * @deprecated - * @type {Float64Array} - */ - get rtcCenter() { - return this.origin; - } + _allocate() { - /** - * The number of triangles in this Node. - * - * @type {Number} - */ - get numTriangles() { - return this._numTriangles; - } + const scene = this._scene; + const gl = scene.canvas.gl; - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are visible. - * - * Only rendered both {@link Node#visible} is ````true```` and {@link Node#culled} is ````false````. - * - * When {@link Node#isObject} and {@link Node#visible} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#visibleObjects}. - * - * @type {Boolean} - */ - set visible(visible) { - visible = visible !== false; - this._visible = visible; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].visible = visible; - } - if (this._isObject) { - this.scene._objectVisibilityUpdated(this, visible); + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; + return; } - } - /** - * Gets if this Node is visible. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * When {@link Node#isObject} and {@link Node#visible} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#visibleObjects}. - * - * @type {Boolean} - */ - get visible() { - return this._visible; - } + const program = this._program; - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are xrayed. - * - * When {@link Node#isObject} and {@link Node#xrayed} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#xrayedObjects}. - * - * @type {Boolean} - */ - set xrayed(xrayed) { - xrayed = !!xrayed; - this._xrayed = xrayed; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].xrayed = xrayed; - } - if (this._isObject) { - this.scene._objectXRayedUpdated(this, xrayed); + this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - } - /** - * Gets if this Node is xrayed. - * - * When {@link Node#isObject} and {@link Node#xrayed} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#xrayedObjects}. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get xrayed() { - return this._xrayed; - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._uPickZNear = program.getLocation("pickZNear"); + this._uPickZFar = program.getLocation("pickZFar"); - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are highlighted. - * - * When {@link Node#isObject} and {@link Node#highlighted} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#highlightedObjects}. - * - * @type {Boolean} - */ - set highlighted(highlighted) { - highlighted = !!highlighted; - this._highlighted = highlighted; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].highlighted = highlighted; - } - if (this._isObject) { - this.scene._objectHighlightedUpdated(this, highlighted); + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } } - /** - * Gets if this Node is highlighted. - * - * When {@link Node#isObject} and {@link Node#highlighted} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#highlightedObjects}. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get highlighted() { - return this._highlighted; + _bindProgram() { + this._program.bind(); } - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are selected. - * - * When {@link Node#isObject} and {@link Node#selected} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#selectedObjects}. - * - * @type {Boolean} - */ - set selected(selected) { - selected = !!selected; - this._selected = selected; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].selected = selected; - } - if (this._isObject) { - this.scene._objectSelectedUpdated(this, selected); - } + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - /** - * Gets if this Node is selected. - * - * When {@link Node#isObject} and {@link Node#selected} are both ````true```` the Node will be - * registered by {@link Node#id} in {@link Scene#selectedObjects}. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get selected() { - return this._selected; - } + _buildVertexShader() { + const scene = this._scene; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batched pick depth vertex shader"); + src.push("uniform int renderPass;"); - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are edge-enhanced. - * - * @type {Boolean} - */ - set edges(edges) { - edges = !!edges; - this._edges = edges; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].edges = edges; + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - /** - * Gets if this Node's edges are enhanced. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get edges() { - return this._edges; - } + src.push("uniform bool pickInvisible;"); - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are culled. - * - * @type {Boolean} - */ - set culled(culled) { - culled = !!culled; - this._culled = culled; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].culled = culled; + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); } - } - /** - * Gets if this Node is culled. - * - * @type {Boolean} - */ - get culled() { - return this._culled; - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#clips}. - * - * @type {Boolean} - */ - set clippable(clippable) { - clippable = clippable !== false; - this._clippable = clippable; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].clippable = clippable; + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - } + src.push("out vec4 vViewPosition;"); + src.push("void main(void) {"); - /** - * Gets if this Node is clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#clips}. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get clippable() { - return this._clippable; - } + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are included in boundary calculations. - * - * @type {Boolean} - */ - set collidable(collidable) { - collidable = collidable !== false; - this._collidable = collidable; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].collidable = collidable; + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); + } + src.push("vViewPosition = viewPosition;"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); } + src.push("gl_PointSize += 10.0;"); + src.push(" }"); + src.push("}"); + return src; } - /** - * Gets if this Node is included in boundary calculations. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get collidable() { - return this._collidable; - } + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batched pick depth fragment shader"); - /** - * Sets if this Node and all child Nodes and {@link Mesh}es are pickable. - * - * Picking is done via calls to {@link Scene#pick}. - * - * @type {Boolean} - */ - set pickable(pickable) { - pickable = pickable !== false; - this._pickable = pickable; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].pickable = pickable; + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - } - /** - * Gets if to this Node is pickable. - * - * Picking is done via calls to {@link Scene#pick}. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get pickable() { - return this._pickable; - } + src.push("uniform float pickZNear;"); + src.push("uniform float pickZFar;"); - /** - * Sets the RGB colorize color for this Node and all child Nodes and {@link Mesh}es}. - * - * Multiplies by rendered fragment colors. - * - * Each element of the color is in range ````[0..1]````. - * - * @type {Number[]} - */ - set colorize(rgb) { - let colorize = this._colorize; - if (!colorize) { - colorize = this._colorize = new Float32Array(4); - colorize[3] = 1.0; + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } } - if (rgb) { - colorize[0] = rgb[0]; - colorize[1] = rgb[1]; - colorize[2] = rgb[2]; - } else { - colorize[0] = 1; - colorize[1] = 1; - colorize[2] = 1; + src.push("in vec4 vViewPosition;"); + src.push("vec4 packDepth(const in float depth) {"); + src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); + src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); + src.push(" vec4 res = fract(depth * bitShift);"); + src.push(" res -= res.xxyz * bitMask;"); + src.push(" return res;"); + src.push("}"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); } - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].colorize = colorize; + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (var i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } - if (this._isObject) { - const colorized = (!!rgb); - this.scene._objectColorizeUpdated(this, colorized); + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); + src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth + src.push("}"); + return src; } - /** - * Gets the RGB colorize color for this Node. - * - * Each element of the color is in range ````[0..1]````. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Number[]} - */ - get colorize() { - return this._colorize.slice(0, 3); + webglContextRestored() { + this._program = null; } - /** - * Sets the opacity factor for this Node and all child Nodes and {@link Mesh}es. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - set opacity(opacity) { - let colorize = this._colorize; - if (!colorize) { - colorize = this._colorize = new Float32Array(4); - colorize[0] = 1; - colorize[1] = 1; - colorize[2] = 1; - } - colorize[3] = opacity !== null && opacity !== undefined ? opacity : 1.0; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].opacity = opacity; - } - if (this._isObject) { - const opacityUpdated = (opacity !== null && opacity !== undefined); - this.scene._objectOpacityUpdated(this, opacityUpdated); + destroy() { + if (this._program) { + this._program.destroy(); } + this._program = null; } +} - /** - * Gets this Node's opacity factor. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Number} - */ - get opacity() { - return this._colorize[3]; - } +const tempVec3a$h = math.vec3(); - /** - * Sets if this Node and all child Nodes and {@link Mesh}es cast shadows. - * - * @type {Boolean} - */ - set castsShadow(castsShadow) { - castsShadow = !!castsShadow; - this._castsShadow = castsShadow; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].castsShadow = castsShadow; - } +/** + * @private + */ +class PointsBatchingOcclusionRenderer { + + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - /** - * Gets if this Node casts shadows. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get castsShadow() { - return this._castsShadow; + getValid() { + return this._hash === this._getHash(); + }; + + _getHash() { + return this._scene._sectionPlanesState.getHash() + (this._scene.pointsMaterial.hash); } - /** - * Sets if this Node and all child Nodes and {@link Mesh}es can have shadows cast upon them. - * - * @type {Boolean} - */ - set receivesShadow(receivesShadow) { - receivesShadow = !!receivesShadow; - this._receivesShadow = receivesShadow; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].receivesShadow = receivesShadow; + drawLayer(frameCtx, pointsBatchingLayer, renderPass) { + + const model = pointsBatchingLayer.model; + const scene = model.scene; + const gl = scene.canvas.gl; + const state = pointsBatchingLayer._state; + const camera = scene.camera; + const origin = pointsBatchingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + + if (!this._program) { + this._allocate(pointsBatchingLayer); + if (this.errors) { + return; + } } - } - /** - * Whether or not to this Node can have shadows cast upon it. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Boolean} - */ - get receivesShadow() { - return this._receivesShadow; - } + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - /** - * Gets if this Node can have Scalable Ambient Obscurance (SAO) applied to it. - * - * SAO is configured by {@link SAO}. - * - * @type {Boolean} - * @abstract - */ - get saoEnabled() { - return false; // TODO: Support SAO on Nodes - } + gl.uniform1i(this._uRenderPass, renderPass); + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - /** - * Sets the 3D World-space offset for this Node and all child Nodes and {@link Mesh}es}. - * - * The offset dynamically translates those components in World-space. - * - * Default value is ````[0, 0, 0]````. - * - * Note that child Nodes and {@link Mesh}es may subsequently be given different values for this property. - * - * @type {Number[]} - */ - set offset(offset) { - if (offset) { - this._offset[0] = offset[0]; - this._offset[1] = offset[1]; - this._offset[2] = offset[2]; - } else { - this._offset[0] = 0; - this._offset[1] = 0; - this._offset[2] = 0; + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = pointsBatchingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$h); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i].offset = this._offset; + + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, pointsBatchingLayer._state.positionsDecodeMatrix); + + this._aPosition.bindArrayBuffer(state.positionsBuf); + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); } - if (this._isObject) { - this.scene._objectOffsetUpdated(this, offset); + + this._aFlags.bindArrayBuffer(state.flagsBuf); + + if (this._aFlags2) { // Won't be in shader when not clipping + this._aFlags2.bindArrayBuffer(state.flags2Buf); } + + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + + gl.drawArrays(gl.POINTS, 0, state.positionsBuf.numItems); } - /** - * Gets the Node's 3D World-space offset. - * - * Default value is ````[0, 0, 0]````. - * - * Child Nodes and {@link Mesh}es may have different values for this property. - * - * @type {Number[]} - */ - get offset() { - return this._offset; + _allocate() { + + const scene = this._scene; + const gl = scene.canvas.gl; + + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; + return; + } + + const program = this._program; + + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; + + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } + + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } + _bindProgram() { - //------------------------------------------------------------------------------------------------------------------ - // Node members - //------------------------------------------------------------------------------------------------------------------ + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - /** - * Returns true to indicate that this Component is a Node. - * @type {Boolean} - */ - get isNode() { - return true; + this._program.bind(); + + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } } - _setLocalMatrixDirty() { - this._localMatrixDirty = true; - this._setWorldMatrixDirty(); + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - _setWorldMatrixDirty() { - this._worldMatrixDirty = true; - for (let i = 0, len = this._children.length; i < len; i++) { - this._children[i]._setWorldMatrixDirty(); + _buildVertexShader() { + const scene = this._scene; + const clipping = scene._sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push ('#version 300 es'); + src.push("// Points batching occlusion vertex shader"); + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - _buildWorldMatrix() { - const localMatrix = this.matrix; - if (!this._parentNode) { - for (let i = 0, len = localMatrix.length; i < len; i++) { - this._worldMatrix[i] = localMatrix[i]; - } - } else { - math.mulMat4(this._parentNode.worldMatrix, localMatrix, this._worldMatrix); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); } - this._worldMatrixDirty = false; - } - _setSubtreeAABBsDirty(node) { - node._aabbDirty = true; - if (node._children) { - for (let i = 0, len = node._children.length; i < len; i++) { - this._setSubtreeAABBsDirty(node._children[i]); - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); } - } + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } + src.push("void main(void) {"); - _setAABBDirty() { - this._setSubtreeAABBsDirty(this); - if (this.collidable) { - for (let node = this; node; node = node._parentNode) { - node._aabbDirty = true; - } + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE + // Only opaque objects can be occluders + + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push(" } else {"); + src.push(" vec4 worldPosition = worldMatrix * (positionsDecodeMatrix * vec4(position, 1.0)); "); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - } - _updateAABB() { - this.scene._aabbDirty = true; - if (!this._aabb) { - this._aabb = math.AABB3(); + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); } - if (this._buildAABB) { - this._buildAABB(this.worldMatrix, this._aabb); // Mesh or VBOSceneModel - } else { // Node | Node | Model - math.collapseAABB3(this._aabb); - let node; - for (let i = 0, len = this._children.length; i < len; i++) { - node = this._children[i]; - if (!node.collidable) { - continue; - } - math.expandAABB3(this._aabb, node.aabb); - } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } - this._aabbDirty = false; + src.push(" gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); + } + src.push(" }"); + src.push("}"); + return src; } - /** - * Adds a child Node or {@link Mesh}. - * - * The child must be a Node or {@link Mesh} in the same {@link Scene}. - * - * If the child already has a parent, will be removed from that parent first. - * - * Does nothing if already a child. - * - * @param {Node|Mesh|String} child Instance or ID of the child to add. - * @param [inheritStates=false] Indicates if the child should inherit rendering states from this parent as it is added. Rendering state includes {@link Node#visible}, {@link Node#culled}, {@link Node#pickable}, {@link Node#clippable}, {@link Node#castsShadow}, {@link Node#receivesShadow}, {@link Node#selected}, {@link Node#highlighted}, {@link Node#colorize} and {@link Node#opacity}. - * @returns {Node|Mesh} The child. - */ - addChild(child, inheritStates) { - if (utils.isNumeric(child) || utils.isString(child)) { - const nodeId = child; - child = this.scene.component[nodeId]; - if (!child) { - this.warn("Component not found: " + utils.inQuotes(nodeId)); - return; - } - if (!child.isNode && !child.isMesh) { - this.error("Not a Node or Mesh: " + nodeId); - return; - } - } else { - if (!child.isNode && !child.isMesh) { - this.error("Not a Node or Mesh: " + child.id); - return; - } - if (child._parentNode) { - if (child._parentNode.id === this.id) { - this.warn("Already a child: " + child.id); - return; - } - child._parentNode.removeChild(child); + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push("// Points batching occlusion fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - child.id; - if (child.scene.id !== this.scene.id) { - this.error("Child not in same Scene: " + child.id); - return; + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); } - this._children.push(child); - child._parentNode = this; - if (!!inheritStates) { - child.visible = this.visible; - child.culled = this.culled; - child.xrayed = this.xrayed; - child.highlited = this.highlighted; - child.selected = this.selected; - child.edges = this.edges; - child.clippable = this.clippable; - child.pickable = this.pickable; - child.collidable = this.collidable; - child.castsShadow = this.castsShadow; - child.receivesShadow = this.receivesShadow; - child.colorize = this.colorize; - child.opacity = this.opacity; - child.offset = this.offset; + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push(" if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push(" }"); + } + src.push(" if (dist > 0.0) { discard; }"); + src.push(" }"); } - child._setWorldMatrixDirty(); - child._setAABBDirty(); - this._numTriangles += child.numTriangles; - return child; + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue + src.push("}"); + return src; } - /** - * Removes the given child Node or {@link Mesh}. - * - * @param {Node|Mesh} child Child to remove. - */ - removeChild(child) { - for (let i = 0, len = this._children.length; i < len; i++) { - if (this._children[i].id === child.id) { - child._parentNode = null; - this._children = this._children.splice(i, 1); - child._setWorldMatrixDirty(); - child._setAABBDirty(); - this._setAABBDirty(); - this._numTriangles -= child.numTriangles; - return; - } - } + webglContextRestored() { + this._program = null; } - /** - * Removes all child Nodes and {@link Mesh}es. - */ - removeChildren() { - let child; - for (let i = 0, len = this._children.length; i < len; i++) { - child = this._children[i]; - child._parentNode = null; - child._setWorldMatrixDirty(); - child._setAABBDirty(); - this._numTriangles -= child.numTriangles; + destroy() { + if (this._program) { + this._program.destroy(); } - this._children = []; - this._setAABBDirty(); + this._program = null; } +} - /** - * Number of child Nodes or {@link Mesh}es. - * - * @type {Number} - */ - get numChildren() { - return this._children.length; - } +/** + * @private + */ +class PointsBatchingRenderers { - /** - * Array of child Nodes or {@link Mesh}es. - * - * @type {Array} - */ - get children() { - return this._children; + constructor(scene) { + this._scene = scene; } - /** - * The parent Node. - * - * The parent Node may also be set by passing the Node to the parent's {@link Node#addChild} method. - * - * @type {Node} - */ - set parent(node) { - if (utils.isNumeric(node) || utils.isString(node)) { - const nodeId = node; - node = this.scene.components[nodeId]; - if (!node) { - this.warn("Node not found: " + utils.inQuotes(nodeId)); - return; - } - if (!node.isNode) { - this.error("Not a Node: " + node.id); - return; - } + _compile() { + if (this._colorRenderer && (!this._colorRenderer.getValid())) { + this._colorRenderer.destroy(); + this._colorRenderer = null; } - if (node.scene.id !== this.scene.id) { - this.error("Node not in same Scene: " + node.id); - return; + if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { + this._silhouetteRenderer.destroy(); + this._silhouetteRenderer = null; } - if (this._parentNode && this._parentNode.id === node.id) { - this.warn("Already a child of Node: " + node.id); - return; + if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { + this._pickMeshRenderer.destroy(); + this._pickMeshRenderer = null; + } + if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { + this._pickDepthRenderer.destroy(); + this._pickDepthRenderer = null; + } + if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { + this._occlusionRenderer.destroy(); + this._occlusionRenderer = null; } - node.addChild(this); } - /** - * The parent Node. - * - * @type {Node} - */ - get parent() { - return this._parentNode; + get colorRenderer() { + if (!this._colorRenderer) { + this._colorRenderer = new PointsBatchingColorRenderer(this._scene); + } + return this._colorRenderer; } - /** - * Sets the Node's local translation. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - */ - set position(value) { - this._position.set(value || [0, 0, 0]); - this._setLocalMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); + get silhouetteRenderer() { + if (!this._silhouetteRenderer) { + this._silhouetteRenderer = new PointsBatchingSilhouetteRenderer(this._scene); + } + return this._silhouetteRenderer; } - /** - * Gets the Node's local translation. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - */ - get position() { - return this._position; + get pickMeshRenderer() { + if (!this._pickMeshRenderer) { + this._pickMeshRenderer = new PointsBatchingPickMeshRenderer(this._scene); + } + return this._pickMeshRenderer; } - /** - * Sets the Node's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - */ - set rotation(value) { - this._rotation.set(value || [0, 0, 0]); - math.eulerToQuaternion(this._rotation, "XYZ", this._quaternion); - this._setLocalMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); + get pickDepthRenderer() { + if (!this._pickDepthRenderer) { + this._pickDepthRenderer = new PointsBatchingPickDepthRenderer(this._scene); + } + return this._pickDepthRenderer; } - /** - * Gets the Node's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * - * Default value is ````[0,0,0]````. - * - * @type {Number[]} - */ - get rotation() { - return this._rotation; + get occlusionRenderer() { + if (!this._occlusionRenderer) { + this._occlusionRenderer = new PointsBatchingOcclusionRenderer(this._scene); + } + return this._occlusionRenderer; } - /** - * Sets the Node's local rotation quaternion. - * - * Default value is ````[0,0,0,1]````. - * - * @type {Number[]} - */ - set quaternion(value) { - this._quaternion.set(value || [0, 0, 0, 1]); - math.quaternionToEuler(this._quaternion, "XYZ", this._rotation); - this._setLocalMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); + _destroy() { + if (this._colorRenderer) { + this._colorRenderer.destroy(); + } + if (this._silhouetteRenderer) { + this._silhouetteRenderer.destroy(); + } + if (this._pickMeshRenderer) { + this._pickMeshRenderer.destroy(); + } + if (this._pickDepthRenderer) { + this._pickDepthRenderer.destroy(); + } + if (this._occlusionRenderer) { + this._occlusionRenderer.destroy(); + } } +} - /** - * Gets the Node's local rotation quaternion. - * - * Default value is ````[0,0,0,1]````. - * - * @type {Number[]} - */ - get quaternion() { - return this._quaternion; - } +const cachedRenderers$1 = {}; - /** - * Sets the Node's local scale. - * - * Default value is ````[1,1,1]````. - * - * @type {Number[]} - */ - set scale(value) { - this._scale.set(value || [1, 1, 1]); - this._setLocalMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); +/** + * @private + */ +function getPointsBatchingRenderers(scene) { + const sceneId = scene.id; + let renderers = cachedRenderers$1[sceneId]; + if (!renderers) { + renderers = new PointsBatchingRenderers(scene); + cachedRenderers$1[sceneId] = renderers; + renderers._compile(); + scene.on("compile", () => { + renderers._compile(); + }); + scene.on("destroyed", () => { + delete cachedRenderers$1[sceneId]; + renderers._destroy(); + }); } + return renderers; +} - /** - * Gets the Node's local scale. - * - * Default value is ````[1,1,1]````. - * - * @type {Number[]} - */ - get scale() { - return this._scale; - } +/** + * @private + */ +class PointsBatchingBuffer { - /** - * Sets the Node's local modeling transform matrix. - * - * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. - * - * @type {Number[]} - */ - set matrix(value) { - if (!this._localMatrix) { - this._localMatrix = math.identityMat4(); + constructor(maxGeometryBatchSize = 5000000) { + + if (maxGeometryBatchSize > 5000000) { + maxGeometryBatchSize = 5000000; } - this._localMatrix.set(value || identityMat); - math.decomposeMat4(this._localMatrix, this._position, this._quaternion, this._scale); - this._localMatrixDirty = false; - this._setWorldMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); + + this.maxVerts = maxGeometryBatchSize; + this.maxIndices = maxGeometryBatchSize * 3; // Rough rule-of-thumb + this.positions = []; + this.colors = []; + this.intensities = []; + this.pickColors = []; + this.flags = []; + this.flags2 = []; + this.offsets = []; } +} + +const tempVec3a$g = math.vec4(); +const tempVec3b$5 = math.vec4(); +const tempVec4a$6 = math.vec4([0, 0, 0, 1]); +const tempVec4b$6 = math.vec4([0, 0, 0, 1]); +const tempVec4c$3 = math.vec4([0, 0, 0, 1]); +const tempOBB3 = math.OBB3(); + +/** + * @private + */ +class PointsBatchingLayer { /** - * Gets the Node's local modeling transform matrix. - * - * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. - * - * @type {Number[]} + * @param model + * @param cfg + * @param cfg.layerIndex + * @param cfg.positionsDecodeMatrix + * @param cfg.maxGeometryBatchSize + * @param cfg.origin + * @param cfg.scratchMemory */ - get matrix() { - if (this._localMatrixDirty) { - if (!this._localMatrix) { - this._localMatrix = math.identityMat4(); - } - math.composeMat4(this._position, this._quaternion, this._scale, this._localMatrix); - this._localMatrixDirty = false; + constructor(cfg) { + + /** + * Owner model + * @type {VBOSceneModel} + */ + this.model = cfg.model; + + /** + * State sorting key. + * @type {string} + */ + this.sortId = "PointsBatchingLayer"; + + /** + * Index of this PointsBatchingLayer in {@link VBOSceneModel#_layerList}. + * @type {Number} + */ + this.layerIndex = cfg.layerIndex; + + this._pointsBatchingRenderers = getPointsBatchingRenderers(cfg.model.scene); + + this._buffer = new PointsBatchingBuffer(cfg.maxGeometryBatchSize); + this._scratchMemory = cfg.scratchMemory; + + this._state = new RenderState({ + positionsBuf: null, + offsetsBuf: null, + colorsBuf: null, + flagsBuf: null, + flags2Buf: null, + positionsDecodeMatrix: math.mat4(), + origin: null + }); + + // These counts are used to avoid unnecessary render passes + this._numPortions = 0; + this._numVisibleLayerPortions = 0; + this._numTransparentLayerPortions = 0; + this._numXRayedLayerPortions = 0; + this._numSelectedLayerPortions = 0; + this._numHighlightedLayerPortions = 0; + this._numClippableLayerPortions = 0; + this._numPickableLayerPortions = 0; + this._numCulledLayerPortions = 0; + + this._modelAABB = math.collapseAABB3(); // Model-space AABB + this._portions = []; + + this._finalized = false; + + if (cfg.positionsDecodeMatrix) { + this._state.positionsDecodeMatrix.set(cfg.positionsDecodeMatrix); + this._preCompressedPositionsExpected = true; + } else { + this._preCompressedPositionsExpected = false; } - return this._localMatrix; - } - /** - * Gets the Node's World matrix. - * - * @property worldMatrix - * @type {Number[]} - */ - get worldMatrix() { - if (this._worldMatrixDirty) { - this._buildWorldMatrix(); + if (cfg.origin) { + this._state.origin = math.vec3(cfg.origin); } - return this._worldMatrix; - } - /** - * Rotates the Node about the given local axis by the given increment. - * - * @param {Number[]} axis Local axis about which to rotate. - * @param {Number} angle Angle increment in degrees. - */ - rotate(axis, angle) { - angleAxis[0] = axis[0]; - angleAxis[1] = axis[1]; - angleAxis[2] = axis[2]; - angleAxis[3] = angle * math.DEGTORAD; - math.angleAxisToQuaternion(angleAxis, q1); - math.mulQuaternions(this.quaternion, q1, q2); - this.quaternion = q2; - this._setLocalMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); - return this; + /** + * The axis-aligned World-space boundary of this PointsBatchingLayer's positions. + * @type {*|Float64Array} + */ + this.aabb = math.collapseAABB3(); } /** - * Rotates the Node about the given World-space axis by the given increment. + * Tests if there is room for another portion in this PointsBatchingLayer. * - * @param {Number[]} axis Local axis about which to rotate. - * @param {Number} angle Angle increment in degrees. + * @param lenPositions Number of positions we'd like to create in the portion. + * @returns {Boolean} True if OK to create another portion. */ - rotateOnWorldAxis(axis, angle) { - angleAxis[0] = axis[0]; - angleAxis[1] = axis[1]; - angleAxis[2] = axis[2]; - angleAxis[3] = angle * math.DEGTORAD; - math.angleAxisToQuaternion(angleAxis, q1); - math.mulQuaternions(q1, this.quaternion, q1); - //this.quaternion.premultiply(q1); - return this; + canCreatePortion(lenPositions) { + if (this._finalized) { + throw "Already finalized"; + } + return ((this._buffer.positions.length + lenPositions) < (this._buffer.maxVerts * 3)); } /** - * Rotates the Node about the local X-axis by the given increment. + * Creates a new portion within this PointsBatchingLayer, returns the new portion ID. * - * @param {Number} angle Angle increment in degrees. - */ - rotateX(angle) { - return this.rotate(xAxis, angle); - } - - /** - * Rotates the Node about the local Y-axis by the given increment. + * Gives the portion the specified geometry, color and matrix. * - * @param {Number} angle Angle increment in degrees. + * @param cfg.positions Flat float Local-space positions array. + * @param cfg.positionsCompressed Flat quantized positions array - decompressed with PointsBatchingLayer positionsDecodeMatrix + * @param [cfg.colorsCompressed] Quantized RGB colors [0..255,0..255,0..255,0..255] + * @param [cfg.colors] Flat float colors array. + * @param cfg.color Float RGB color [0..1,0..1,0..1] + * @param [cfg.meshMatrix] Flat float 4x4 matrix + * @param [cfg.worldMatrix] Flat float 4x4 matrix + * @param cfg.worldAABB Flat float AABB World-space AABB + * @param cfg.pickColor Quantized pick color + * @returns {number} Portion ID */ - rotateY(angle) { - return this.rotate(yAxis, angle); - } + createPortion(cfg) { - /** - * Rotates the Node about the local Z-axis by the given increment. - * - * @param {Number} angle Angle increment in degrees. - */ - rotateZ(angle) { - return this.rotate(zAxis, angle); - } + if (this._finalized) { + throw "Already finalized"; + } - /** - * Translates the Node along local space vector by the given increment. - * - * @param {Number[]} axis Normalized local space 3D vector along which to translate. - * @param {Number} distance Distance to translate along the vector. - */ - translate(axis, distance) { - math.vec3ApplyQuaternion(this.quaternion, axis, veca); - math.mulVec3Scalar(veca, distance, vecb); - math.addVec3(this.position, vecb, this.position); - this._setLocalMatrixDirty(); - this._setAABBDirty(); - this.glRedraw(); - return this; - } + const positions = cfg.positions; + const positionsCompressed = cfg.positionsCompressed; + const color = cfg.color; + const colorsCompressed = cfg.colorsCompressed; + const colors = cfg.colors; + const meshMatrix = cfg.meshMatrix; + const worldMatrix = cfg.worldMatrix; + const worldAABB = cfg.worldAABB; + const pickColor = cfg.pickColor; - /** - * Translates the Node along the local X-axis by the given increment. - * - * @param {Number} distance Distance to translate along the X-axis. - */ - translateX(distance) { - return this.translate(xAxis, distance); - } + const buffer = this._buffer; + const positionsIndex = buffer.positions.length; + const vertsIndex = positionsIndex / 3; - /** - * Translates the Node along the local Y-axis by the given increment. - * - * @param {Number} distance Distance to translate along the Y-axis. - */ - translateY(distance) { - return this.translate(yAxis, distance); - } + let numVerts; - /** - * Translates the Node along the local Z-axis by the given increment. - * - * @param {Number} distance Distance to translate along the Z-axis. - */ - translateZ(distance) { - return this.translate(zAxis, distance); - } + if (this._preCompressedPositionsExpected) { - //------------------------------------------------------------------------------------------------------------------ - // Component members - //------------------------------------------------------------------------------------------------------------------ + if (!positionsCompressed) { + throw "positionsCompressed expected"; + } - /** - @private - */ - get type() { - return "Node"; - } + for (let i = 0, len = positionsCompressed.length; i < len; i++) { + buffer.positions.push(positionsCompressed[i]); + } - /** - * Destroys this Node. - */ - destroy() { - super.destroy(); - if (this._parentNode) { - this._parentNode.removeChild(this); - } - if (this._isObject) { - this.scene._deregisterObject(this); - if (this._visible) { - this.scene._objectVisibilityUpdated(this, false); + const bounds = geometryCompressionUtils.getPositionsBounds(positionsCompressed); + + const min = geometryCompressionUtils.decompressPosition(bounds.min, this._state.positionsDecodeMatrix, tempVec3a$g); + const max = geometryCompressionUtils.decompressPosition(bounds.max, this._state.positionsDecodeMatrix, tempVec3b$5); + + worldAABB[0] = min[0]; + worldAABB[1] = min[1]; + worldAABB[2] = min[2]; + worldAABB[3] = max[0]; + worldAABB[4] = max[1]; + worldAABB[5] = max[2]; + + if (worldMatrix) { + math.AABB3ToOBB3(worldAABB, tempOBB3); + math.transformOBB3(worldMatrix, tempOBB3); + math.OBB3ToAABB3(tempOBB3, worldAABB); } - if (this._xrayed) { - this.scene._objectXRayedUpdated(this, false); + + numVerts = positionsCompressed.length / 3; + + } else { + + if (!positions) { + throw "positions expected"; } - if (this._selected) { - this.scene._objectSelectedUpdated(this, false); + + numVerts = positions.length / 3; + + const lenPositions = positions.length; + const positionsBase = buffer.positions.length; + + for (let i = 0, len = positions.length; i < len; i++) { + buffer.positions.push(positions[i]); } - if (this._highlighted) { - this.scene._objectHighlightedUpdated(this, false); + + if (meshMatrix) { + + for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { + + tempVec4a$6[0] = buffer.positions[i + 0]; + tempVec4a$6[1] = buffer.positions[i + 1]; + tempVec4a$6[2] = buffer.positions[i + 2]; + + math.transformPoint4(meshMatrix, tempVec4a$6, tempVec4b$6); + + buffer.positions[i + 0] = tempVec4b$6[0]; + buffer.positions[i + 1] = tempVec4b$6[1]; + buffer.positions[i + 2] = tempVec4b$6[2]; + + math.expandAABB3Point3(this._modelAABB, tempVec4b$6); + + if (worldMatrix) { + math.transformPoint4(worldMatrix, tempVec4b$6, tempVec4c$3); + math.expandAABB3Point3(worldAABB, tempVec4c$3); + } else { + math.expandAABB3Point3(worldAABB, tempVec4b$6); + } + } + + } else { + + for (let i = positionsBase, len = positionsBase + lenPositions; i < len; i += 3) { + + tempVec4a$6[0] = buffer.positions[i + 0]; + tempVec4a$6[1] = buffer.positions[i + 1]; + tempVec4a$6[2] = buffer.positions[i + 2]; + + math.expandAABB3Point3(this._modelAABB, tempVec4a$6); + + if (worldMatrix) { + math.transformPoint4(worldMatrix, tempVec4a$6, tempVec4b$6); + math.expandAABB3Point3(worldAABB, tempVec4b$6); + } else { + math.expandAABB3Point3(worldAABB, tempVec4a$6); + } + } } - this.scene._objectColorizeUpdated(this, false); - this.scene._objectOpacityUpdated(this, false); - this.scene._objectOffsetUpdated(this, false); + + } - if (this._isModel) { - this.scene._deregisterModel(this); + + if (this._state.origin) { + const origin = this._state.origin; + worldAABB[0] += origin[0]; + worldAABB[1] += origin[1]; + worldAABB[2] += origin[2]; + worldAABB[3] += origin[0]; + worldAABB[4] += origin[1]; + worldAABB[5] += origin[2]; } - if (this._children.length) { - // Clone the _children before iterating, so our children don't mess us up when calling removeChild(). - const tempChildList = this._children.splice(); - let child; - for (let i = 0, len = tempChildList.length; i < len; i++) { - child = tempChildList[i]; - child.destroy(); + + math.expandAABB3(this.aabb, worldAABB); + + if (colorsCompressed) { + for (let i = 0, len = colorsCompressed.length; i < len; i++) { + buffer.colors.push(colorsCompressed[i]); } - } - this._children = []; - this._setAABBDirty(); - this.scene._aabbDirty = true; - } -} + } else if (colors) { + for (let i = 0, len = colors.length; i < len; i++) { + buffer.colors.push(colors[i] * 255); + } -const memoryStats = stats.memory; -const tempAABB$1 = math.AABB3(); + } else if (color) { -/** - * @desc A {@link Geometry} that keeps its geometry data solely in GPU memory, without retaining it in browser memory. - * - * VBOGeometry uses less memory than {@link ReadableGeometry}, which keeps its geometry data in both browser and GPU memory. - * - * ## Usage - * - * Creating a {@link Mesh} with a VBOGeometry that defines a single triangle, plus a {@link PhongMaterial} with diffuse {@link Texture}: - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_VBOGeometry)] - * - * ````javascript - * import {Viewer, Mesh, VBOGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * new Mesh(viewer.scene, { - * geometry: new VBOGeometry(viewer.scene, { - * primitive: "triangles", - * positions: [0.0, 3, 0.0, -3, -3, 0.0, 3, -3, 0.0], - * normals: [0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0], - * uv: [0.0, 0.0, 0.5, 1.0, 1.0, 0.0], - * indices: [0, 1, 2] - * }), - * material: new PhongMaterial(viewer.scene, { - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }), - * backfaces: true - * }) - * }); - * ```` - */ -class VBOGeometry extends Geometry { - - /** - @private - */ - get type() { - return "VBOGeometry"; - } - - /** - * @private - * @returns {boolean} - */ - get isVBOGeometry() { - return true; - } + const r = color[0]; // Color is pre-quantized by VBOSceneModel + const g = color[1]; + const b = color[2]; + const a = 1.0; - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {String} [cfg.primitive="triangles"] The primitive type. Accepted values are 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'. - * @param {Number[]} [cfg.positions] Positions array. - * @param {Number[]} [cfg.normals] Vertex normal vectors array. - * @param {Number[]} [cfg.uv] UVs array. - * @param {Number[]} [cfg.colors] Vertex colors. - * @param {Number[]} [cfg.indices] Indices array. - * @param {Number} [cfg.edgeThreshold=10] When autogenerating edges for supporting {@link Drawable#edges}, this indicates the threshold angle (in degrees) between the face normals of adjacent triangles below which the edge is discarded. - */ - constructor(owner, cfg = {}) { + for (let i = 0; i < numVerts; i++) { + buffer.colors.push(r); + buffer.colors.push(g); + buffer.colors.push(b); + buffer.colors.push(a); + } + } - super(owner, cfg); + { + const pickColorsBase = buffer.pickColors.length; + const lenPickColors = numVerts * 4; + for (let i = pickColorsBase, len = pickColorsBase + lenPickColors; i < len; i += 4) { + buffer.pickColors.push(pickColor[0]); + buffer.pickColors.push(pickColor[1]); + buffer.pickColors.push(pickColor[2]); + buffer.pickColors.push(pickColor[3]); + } + } - this._state = new RenderState({ // Arrays for emphasis effects are got from xeokit.GeometryLite friend methods - compressGeometry: true, - primitive: null, // WebGL enum - primitiveName: null, // String - positionsDecodeMatrix: null, // Set when compressGeometry == true - uvDecodeMatrix: null, // Set when compressGeometry == true - positionsBuf: null, - normalsBuf: null, - colorsbuf: null, - uvBuf: null, - indicesBuf: null, - hash: "" - }); + if (this.model.scene.entityOffsetsEnabled) { + for (let i = 0; i < numVerts; i++) { + buffer.offsets.push(0); + buffer.offsets.push(0); + buffer.offsets.push(0); + } + } - this._numTriangles = 0; + const portionId = this._portions.length / 2; - this._edgeThreshold = cfg.edgeThreshold || 10.0; - this._aabb = null; - this._obb = math.OBB3(); + this._portions.push(vertsIndex); + this._portions.push(numVerts); - const state = this._state; - const gl = this.scene.canvas.gl; + this._numPortions++; + this.model.numPortions++; - cfg.primitive = cfg.primitive || "triangles"; - switch (cfg.primitive) { - case "points": - state.primitive = gl.POINTS; - state.primitiveName = cfg.primitive; - break; - case "lines": - state.primitive = gl.LINES; - state.primitiveName = cfg.primitive; - break; - case "line-loop": - state.primitive = gl.LINE_LOOP; - state.primitiveName = cfg.primitive; - break; - case "line-strip": - state.primitive = gl.LINE_STRIP; - state.primitiveName = cfg.primitive; - break; - case "triangles": - state.primitive = gl.TRIANGLES; - state.primitiveName = cfg.primitive; - break; - case "triangle-strip": - state.primitive = gl.TRIANGLE_STRIP; - state.primitiveName = cfg.primitive; - break; - case "triangle-fan": - state.primitive = gl.TRIANGLE_FAN; - state.primitiveName = cfg.primitive; - break; - default: - this.error("Unsupported value for 'primitive': '" + cfg.primitive + - "' - supported values are 'points', 'lines', 'line-loop', 'line-strip', 'triangles', " + - "'triangle-strip' and 'triangle-fan'. Defaulting to 'triangles'."); - state.primitive = gl.TRIANGLES; - state.primitiveName = cfg.primitive; - } + return portionId; + } - if (!cfg.positions) { - this.error("Config expected: positions"); - return; // TODO: Recover? - } + /** + * Builds batch VBOs from appended geometries. + * No more portions can then be created. + */ + finalize() { - if (!cfg.indices) { - this.error("Config expected: indices"); - return; // TODO: Recover? + if (this._finalized) { + this.model.error("Already finalized"); + return; } - var positions; - - { - const positionsDecodeMatrix = cfg.positionsDecodeMatrix; - - if (positionsDecodeMatrix) ; else { - - // Uncompressed positions + const state = this._state; + const gl = this.model.scene.canvas.gl; + const buffer = this._buffer; - const bounds = geometryCompressionUtils.getPositionsBounds(cfg.positions); - const result = geometryCompressionUtils.compressPositions(cfg.positions, bounds.min, bounds.max); - positions = result.quantized; - state.positionsDecodeMatrix = result.decodeMatrix; - state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, positions, positions.length, 3, gl.STATIC_DRAW); - memoryStats.positions += state.positionsBuf.numItems; - math.positions3ToAABB3(cfg.positions, this._aabb); - math.positions3ToAABB3(positions, tempAABB$1, state.positionsDecodeMatrix); - math.AABB3ToOBB3(tempAABB$1, this._obb); + if (buffer.positions.length > 0) { + if (this._preCompressedPositionsExpected) { + const positions = new Uint16Array(buffer.positions); + state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, positions, buffer.positions.length, 3, gl.STATIC_DRAW); + } else { + const positions = new Float32Array(buffer.positions); + const quantizedPositions = quantizePositions(positions, this._modelAABB, state.positionsDecodeMatrix); + state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, buffer.positions.length, 3, gl.STATIC_DRAW); } } - if (cfg.colors) { - const colors = cfg.colors.constructor === Float32Array ? cfg.colors : new Float32Array(cfg.colors); - state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, colors.length, 4, gl.STATIC_DRAW); - memoryStats.colors += state.colorsBuf.numItems; + if (buffer.colors.length > 0) { + const colors = new Uint8Array(buffer.colors); + let normalized = false; + state.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colors, buffer.colors.length, 4, gl.STATIC_DRAW, normalized); } - if (cfg.uv) { - const bounds = geometryCompressionUtils.getUVBounds(cfg.uv); - const result = geometryCompressionUtils.compressUVs(cfg.uv, bounds.min, bounds.max); - const uv = result.quantized; - state.uvDecodeMatrix = result.decodeMatrix; - state.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uv, uv.length, 2, gl.STATIC_DRAW); - memoryStats.uvs += state.uvBuf.numItems; + if (buffer.positions.length > 0) { // Because we build flags arrays here, get their length from the positions array + const flagsLength = (buffer.positions.length / 3) * 4; + const flags = new Uint8Array(flagsLength); + const flags2 = new Uint8Array(flagsLength); + let notNormalized = false; + let normalized = true; + state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags, flags.length, 4, gl.DYNAMIC_DRAW, notNormalized); + state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, flags2, flags2.length, 4, gl.DYNAMIC_DRAW, normalized); } - if (cfg.normals) { - const normals = geometryCompressionUtils.compressNormals(cfg.normals); - let normalized = state.compressGeometry; - state.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, normals, normals.length, 3, gl.STATIC_DRAW, normalized); - memoryStats.normals += state.normalsBuf.numItems; + if (buffer.pickColors.length > 0) { + const pickColors = new Uint8Array(buffer.pickColors); + let normalized = false; + state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, pickColors, buffer.pickColors.length, 4, gl.STATIC_DRAW, normalized); } - { - const indices = (cfg.indices.constructor === Uint32Array || cfg.indices.constructor === Uint16Array) ? cfg.indices : new Uint32Array(cfg.indices); - state.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, indices, indices.length, 1, gl.STATIC_DRAW); - memoryStats.indices += state.indicesBuf.numItems; - const edgeIndices = buildEdgeIndices(positions, indices, state.positionsDecodeMatrix, this._edgeThreshold); - this._edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, edgeIndices, edgeIndices.length, 1, gl.STATIC_DRAW); - - if (this._state.primitiveName === "triangles") { - this._numTriangles = (cfg.indices.length / 3); + if (this.model.scene.entityOffsetsEnabled) { + if (buffer.offsets.length > 0) { + const offsets = new Float32Array(buffer.offsets); + state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, offsets, buffer.offsets.length, 3, gl.DYNAMIC_DRAW); } } - this._buildHash(); - - memoryStats.meshes++; + this._buffer = null; + this._finalized = true; } - _buildHash() { - const state = this._state; - const hash = ["/g"]; - hash.push("/" + state.primitive + ";"); - if (state.positionsBuf) { - hash.push("p"); + initFlags(portionId, flags, meshTransparent) { + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; } - if (state.colorsBuf) { - hash.push("c"); + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; } - if (state.normalsBuf || state.autoVertexNormals) { - hash.push("n"); + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; } - if (state.uvBuf) { - hash.push("u"); + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; } - hash.push("cp"); // Always compressed - hash.push(";"); - state.hash = hash.join(""); + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } + if (meshTransparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } + this._setFlags(portionId, flags, meshTransparent); + this._setFlags2(portionId, flags); } - _getEdgeIndices() { - return this._edgeIndicesBuf; + setVisible(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } else { + this._numVisibleLayerPortions--; + this.model.numVisibleLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Gets the primitive type. - * - * Possible types are: 'points', 'lines', 'line-loop', 'line-strip', 'triangles', 'triangle-strip' and 'triangle-fan'. - * - * @type {String} - */ - get primitive() { - return this._state.primitiveName; + setHighlighted(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } else { + this._numHighlightedLayerPortions--; + this.model.numHighlightedLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Gets the local-space axis-aligned 3D boundary (AABB). - * - * The AABB is represented by a six-element Float64Array containing the min/max extents of the axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. - * - * @type {Number[]} - */ - get aabb() { - return this._aabb; + setXRayed(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } else { + this._numXRayedLayerPortions--; + this.model.numXRayedLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Gets the local-space oriented 3D boundary (OBB). - * - * The OBB is represented by a 32-element Float64Array containing the eight vertices of the box, where each vertex is a homogeneous coordinate having [x,y,z,w] elements. - * - * @type {Number[]} - */ - get obb() { - return this._obb; + setSelected(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } else { + this._numSelectedLayerPortions--; + this.model.numSelectedLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * Approximate number of triangles in this VBOGeometry. - * - * Will be zero if {@link VBOGeometry#primitive} is not 'triangles', 'triangle-strip' or 'triangle-fan'. - * - * @type {Number} - */ - get numTriangles() { - return this._numTriangles; + setEdges(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; + } + // Not applicable to point clouds } - /** @private */ - _getState() { - return this._state; + setClippable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } else { + this._numClippableLayerPortions--; + this.model.numClippableLayerPortions--; + } + this._setFlags2(portionId, flags); } - /** - * Destroys this component. - */ - destroy() { - super.destroy(); - const state = this._state; - if (state.indicesBuf) { - state.indicesBuf.destroy(); - } - if (state.positionsBuf) { - state.positionsBuf.destroy(); + setCulled(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; } - if (state.normalsBuf) { - state.normalsBuf.destroy(); + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } else { + this._numCulledLayerPortions--; + this.model.numCulledLayerPortions--; } - if (state.uvBuf) { - state.uvBuf.destroy(); + this._setFlags(portionId, flags, transparent); + } + + setCollidable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; } - if (state.colorsBuf) { - state.colorsBuf.destroy(); + } + + setPickable(portionId, flags, transparent) { + if (!this._finalized) { + throw "Not finalized"; } - if (this._edgeIndicesBuf) { - this._edgeIndicesBuf.destroy(); + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } else { + this._numPickableLayerPortions--; + this.model.numPickableLayerPortions--; } - state.destroy(); - memoryStats.meshes--; + this._setFlags(portionId, flags, transparent); } -} - -const modes = {"opaque": 0, "mask": 1, "blend": 2}; -const modeNames = ["opaque", "mask", "blend"]; -/** - * @desc Configures the normal rendered appearance of {@link Mesh}es using the physically-accurate *metallic-roughness* shading model. - * - * * Useful for conductive materials, such as metal, but also appropriate for insulators. - * * {@link SpecularMaterial} is best for insulators, such as wood, ceramics and plastic. - * * {@link PhongMaterial} is appropriate for non-realistic objects. - * * {@link LambertMaterial} is appropriate for high-detail models that need to render as efficiently as possible. - * - * ## Usage - * - * In the example below we'll create a {@link Mesh} with {@link MetallicMaterial} and {@link ReadableGeometry} loaded from OBJ. - * - * Note that in this example we're providing separate {@link Texture} for the {@link MetallicMaterial#metallic} and {@link MetallicMaterial#roughness} - * channels, which allows us a little creative flexibility. Then, in the next example further down, we'll combine those channels - * within the same {@link Texture} for efficiency. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_MetallicMaterial)] - * - * ````javascript - * import {Viewer, Mesh, loadOBJGeometry, ReadableGeometry, MetallicMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0.57, 1.37, 1.14]; - * viewer.scene.camera.look = [0.04, 0.58, 0.00]; - * viewer.scene.camera.up = [-0.22, 0.84, -0.48]; - * - * loadOBJGeometry(viewer.scene, { - * src: "models/obj/fireHydrant/FireHydrantMesh.obj" - * }) - * .then(function (geometry) { - * - * // Success - * - * new Mesh(viewer.scene, { - * - * geometry: new ReadableGeometry(viewer.scene, geometry), - * - * material: new MetallicMaterial(viewer.scene, { - * - * baseColor: [1, 1, 1], - * metallic: 1.0, - * roughness: 1.0, - * - * baseColorMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", - * encoding: "sRGB" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" - * }), - * roughnessMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Roughness.png" - * }), - * metallicMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Metallic.png" - * }), - * occlusionMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" - * }), - * - * specularF0: 0.7 - * }) - * }); - * }, function () { - * // Error - * }); - * ```` - * - * ## Background Theory - * - * For an introduction to physically-based rendering (PBR) concepts, try these articles: - * - * * Joe Wilson's [Basic Theory of Physically-Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/) - * * Jeff Russel's [Physically-based Rendering, and you can too!](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/) - * * Sebastien Legarde's [Adapting a physically-based shading model](http://seblagarde.wordpress.com/tag/physically-based-rendering/) - * - * ## MetallicMaterial Properties - * - * The following table summarizes MetallicMaterial properties: - * - * | Property | Type | Range | Default Value | Space | Description | - * |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:| - * | {@link MetallicMaterial#baseColor} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the base color of the material. | - * | {@link MetallicMaterial#metallic} | Number | [0, 1] | 1 | linear | The metallic-ness the material (1 for metals, 0 for non-metals). | - * | {@link MetallicMaterial#roughness} | Number | [0, 1] | 1 | linear | The roughness of the material surface. | - * | {@link MetallicMaterial#specularF0} | Number | [0, 1] | 1 | linear | The specular Fresnel of the material surface. | - * | {@link MetallicMaterial#emissive} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the emissive color of the material. | - * | {@link MetallicMaterial#alpha} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). | - * | {@link MetallicMaterial#baseColorMap} | {@link Texture} | | null | sRGB | Texture RGB components multiplying by {@link MetallicMaterial#baseColor}. If the fourth component (A) is present, it multiplies by {@link MetallicMaterial#alpha}. | - * | {@link MetallicMaterial#metallicMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#metallic}. | - * | {@link MetallicMaterial#roughnessMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#roughness}. | - * | {@link MetallicMaterial#metallicRoughnessMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#metallic} and second component multiplying by {@link MetallicMaterial#roughness}. | - * | {@link MetallicMaterial#emissiveMap} | {@link Texture} | | null | linear | Texture with RGB components multiplying by {@link MetallicMaterial#emissive}. | - * | {@link MetallicMaterial#alphaMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link MetallicMaterial#alpha}. | - * | {@link MetallicMaterial#occlusionMap} | {@link Texture} | | null | linear | Ambient occlusion texture multiplying by surface's reflected diffuse and specular light. | - * | {@link MetallicMaterial#normalMap} | {@link Texture} | | null | linear | Tangent-space normal map. | - * | {@link MetallicMaterial#alphaMode} | String | "opaque", "blend", "mask" | "blend" | | Alpha blend mode. | - * | {@link MetallicMaterial#alphaCutoff} | Number | [0..1] | 0.5 | | Alpha cutoff value. | - * | {@link MetallicMaterial#backfaces} | Boolean | | false | | Whether to render {@link ReadableGeometry} backfaces. | - * | {@link MetallicMaterial#frontface} | String | "ccw", "cw" | "ccw" | | The winding order for {@link ReadableGeometry} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. | - * - * - * ## Combining Channels Within the Same Textures - * - * In the previous example we provided separate {@link Texture} for the {@link MetallicMaterial#metallic} and - * {@link MetallicMaterial#roughness} channels, but we can combine those channels into the same {@link Texture} to - * reduce download time, memory footprint and rendering time (and also for glTF compatibility). - * - * Here's the {@link Mesh} again, with our MetallicMaterial with those channels combined in the {@link MetallicMaterial#metallicRoughnessMap} - * {@link Texture}, where the *R* component multiplies by {@link MetallicMaterial#metallic} and *G* multiplies - * by {@link MetallicMaterial#roughness}. - * - * ````javascript - * new Mesh(viewer.scene, { - * - * geometry: geometry, - * - * material: new MetallicMaterial(viewer.scene, { - * - * baseColor: [1, 1, 1], - * metallic: 1.0, - * roughness: 1.0, - * - * baseColorMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", - * encoding: "sRGB" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" - * }), - * metallicRoughnessMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" - * }), - * metallicRoughnessMap : new Texture(viewer.scene, { // <<----------- Added - * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" // R component multiplies by metallic - * }), // G component multiplies by roughness - * occlusionMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" - * }), - * - * specularF0: 0.7 - * }) - * ```` - * - * Although not shown in this example, we can also texture {@link MetallicMaterial#alpha} with the *A* component of - * {@link MetallicMaterial#baseColorMap}'s {@link Texture}, if required. - * - * ## Alpha Blending - * - * Let's make our {@link Mesh} transparent. - * - * We'll update the {@link MetallicMaterial#alpha} and {@link MetallicMaterial#alphaMode}, causing it to blend 50% - * with the background: - * - * ````javascript - * hydrant.material.alpha = 0.5; - * hydrant.material.alphaMode = "blend"; - * ```` - * - * ## Alpha Masking - * - * Let's apply an alpha mask to our {@link Mesh}. - * - * We'll configure an {@link MetallicMaterial#alphaMap} to multiply by {@link MetallicMaterial#alpha}, - * with {@link MetallicMaterial#alphaMode} and {@link MetallicMaterial#alphaCutoff} to treat it as an alpha mask: - * - * ````javascript - * new Mesh(viewer.scene, { - * - * geometry: geometry, - * - * material: new MetallicMaterial(viewer.scene, { - * - * baseColor: [1, 1, 1], - * metallic: 1.0, - * roughness: 1.0, - * alpha: 1.0, - * alphaMode : "mask", // <<---------------- Added - * alphaCutoff : 0.2, // <<---------------- Added - * - * alphaMap : new Texture(viewer.scene{ // <<---------------- Added - * src: "textures/alphaMap.jpg" - * }), - * baseColorMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", - * encoding: "sRGB" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" - * }), - * metallicRoughnessMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" - * }), - * metallicRoughnessMap : new Texture(viewer.scene, { // <<----------- Added - * src: "models/obj/fireHydrant/fire_hydrant_MetallicRoughness.png" // R component multiplies by metallic - * }), // G component multiplies by roughness - * occlusionMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" - * }), - * - * specularF0: 0.7 - * }) - * ```` - */ -class MetallicMaterial extends Material { + setColor(portionId, color) { + if (!this._finalized) { + throw "Not finalized"; + } + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstColor = vertexBase * 4; + const lenColor = numVerts * 4; + const tempArray = this._scratchMemory.getUInt8Array(lenColor); + const r = color[0]; + const g = color[1]; + const b = color[2]; + for (let i = 0; i < lenColor; i += 4) { + tempArray[i + 0] = r; + tempArray[i + 1] = g; + tempArray[i + 2] = b; + } + this._state.colorsBuf.setData(tempArray, firstColor, lenColor); + } - /** - @private - */ - get type() { - return "MetallicMaterial"; + setTransparent(portionId, flags, transparent) { + if (transparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } else { + this._numTransparentLayerPortions--; + this.model.numTransparentLayerPortions--; + } + this._setFlags(portionId, flags, transparent); } - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this MetallicMaterial as well. - * @param {*} [cfg] The MetallicMaterial configuration. - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number[]} [cfg.baseColor=[1,1,1]] RGB diffuse color of this MetallicMaterial. Multiplies by the RGB components of {@link MetallicMaterial#baseColorMap}. - * @param {Number} [cfg.metallic=1.0] Factor in the range ````[0..1]```` indicating how metallic this MetallicMaterial is. ````1```` is metal, ````0```` is non-metal. Multiplies by the *R* component of {@link MetallicMaterial#metallicMap} and the *A* component of {@link MetallicMaterial#metallicRoughnessMap}. - * @param {Number} [cfg.roughness=1.0] Factor in the range ````[0..1]```` indicating the roughness of this MetallicMaterial. ````0```` is fully smooth, ````1```` is fully rough. Multiplies by the *R* component of {@link MetallicMaterial#roughnessMap}. - * @param {Number} [cfg.specularF0=0.0] Factor in the range ````[0..1]```` indicating specular Fresnel. - * @param {Number[]} [cfg.emissive=[0,0,0]] RGB emissive color of this MetallicMaterial. Multiplies by the RGB components of {@link MetallicMaterial#emissiveMap}. - * @param {Number} [cfg.alpha=1.0] Factor in the range ````[0..1]```` indicating the alpha of this MetallicMaterial. Multiplies by the *R* component of {@link MetallicMaterial#alphaMap} and the *A* component, if present, of {@link MetallicMaterial#baseColorMap}. The value of {@link MetallicMaterial#alphaMode} indicates how alpha is interpreted when rendering. - * @param {Texture} [cfg.baseColorMap=undefined] RGBA {@link Texture} containing the diffuse color of this MetallicMaterial, with optional *A* component for alpha. The RGB components multiply by the {@link MetallicMaterial#baseColor} property, while the *A* component, if present, multiplies by the {@link MetallicMaterial#alpha} property. - * @param {Texture} [cfg.alphaMap=undefined] RGB {@link Texture} containing this MetallicMaterial's alpha in its *R* component. The *R* component multiplies by the {@link MetallicMaterial#alpha} property. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {Texture} [cfg.metallicMap=undefined] RGB {@link Texture} containing this MetallicMaterial's metallic factor in its *R* component. The *R* component multiplies by the {@link MetallicMaterial#metallic} property. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {Texture} [cfg.roughnessMap=undefined] RGB {@link Texture} containing this MetallicMaterial's roughness factor in its *R* component. The *R* component multiplies by the {@link MetallicMaterial#roughness} property. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {Texture} [cfg.metallicRoughnessMap=undefined] RGB {@link Texture} containing this MetallicMaterial's metalness in its *R* component and roughness in its *G* component. Its *R* component multiplies by the {@link MetallicMaterial#metallic} property, while its *G* component multiplies by the {@link MetallicMaterial#roughness} property. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {Texture} [cfg.emissiveMap=undefined] RGB {@link Texture} containing the emissive color of this MetallicMaterial. Multiplies by the {@link MetallicMaterial#emissive} property. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {Texture} [cfg.occlusionMap=undefined] RGB ambient occlusion {@link Texture}. Within shaders, multiplies by the specular and diffuse light reflected by surfaces. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {Texture} [cfg.normalMap=undefined] RGB tangent-space normal {@link Texture}. Must be within the same {@link Scene} as this MetallicMaterial. - * @param {String} [cfg.alphaMode="opaque"] The alpha blend mode, which specifies how alpha is to be interpreted. Accepted values are "opaque", "blend" and "mask". See the {@link MetallicMaterial#alphaMode} property for more info. - * @param {Number} [cfg.alphaCutoff=0.5] The alpha cutoff value. See the {@link MetallicMaterial#alphaCutoff} property for more info. - * @param {Boolean} [cfg.backfaces=false] Whether to render {@link ReadableGeometry} backfaces. - * @param {Boolean} [cfg.frontface="ccw"] The winding order for {@link ReadableGeometry} front faces - ````"cw"```` for clockwise, or ````"ccw"```` for counter-clockwise. - * @param {Number} [cfg.lineWidth=1] Scalar that controls the width of lines for {@link ReadableGeometry} with {@link ReadableGeometry#primitive} set to "lines". - * @param {Number} [cfg.pointSize=1] Scalar that controls the size of points for {@link ReadableGeometry} with {@link ReadableGeometry#primitive} set to "points". - */ - constructor(owner, cfg = {}) { + _setFlags(portionId, flags, transparent) { - super(owner, cfg); + if (!this._finalized) { + throw "Not finalized"; + } - this._state = new RenderState({ - type: "MetallicMaterial", - baseColor: math.vec4([1.0, 1.0, 1.0]), - emissive: math.vec4([0.0, 0.0, 0.0]), - metallic: null, - roughness: null, - specularF0: null, - alpha: null, - alphaMode: null, // "opaque" - alphaCutoff: null, - lineWidth: null, - pointSize: null, - backfaces: null, - frontface: null, // Boolean for speed; true == "ccw", false == "cw" - hash: null - }); + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstFlag = vertexBase * 4; + const lenFlags = numVerts * 4; + const tempArray = this._scratchMemory.getUInt8Array(lenFlags); - this.baseColor = cfg.baseColor; - this.metallic = cfg.metallic; - this.roughness = cfg.roughness; - this.specularF0 = cfg.specularF0; - this.emissive = cfg.emissive; - this.alpha = cfg.alpha; + const visible = !!(flags & ENTITY_FLAGS.VISIBLE); + const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); + const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); + const selected = !!(flags & ENTITY_FLAGS.SELECTED); + const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); + const culled = !!(flags & ENTITY_FLAGS.CULLED); - if (cfg.baseColorMap) { - this._baseColorMap = this._checkComponent("Texture", cfg.baseColorMap); + // Normal fill + + let f0; + if (!visible || culled || xrayed + || (highlighted && !this.model.scene.highlightMaterial.glowThrough) + || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { + f0 = RENDER_PASSES.NOT_RENDERED; + } else { + if (transparent) { + f0 = RENDER_PASSES.COLOR_TRANSPARENT; + } else { + f0 = RENDER_PASSES.COLOR_OPAQUE; + } } - if (cfg.metallicMap) { - this._metallicMap = this._checkComponent("Texture", cfg.metallicMap); + // Emphasis fill + + let f1; + if (!visible || culled) { + f1 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f1 = RENDER_PASSES.SILHOUETTE_SELECTED; + } else if (highlighted) { + f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; + } else if (xrayed) { + f1 = RENDER_PASSES.SILHOUETTE_XRAYED; + } else { + f1 = RENDER_PASSES.NOT_RENDERED; } - if (cfg.roughnessMap) { - this._roughnessMap = this._checkComponent("Texture", cfg.roughnessMap); + + // Pick + + let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; + + for (let i = 0; i < lenFlags; i += 4) { + tempArray[i + 0] = f0; // x - normal fill + tempArray[i + 1] = f1; // y - emphasis fill + tempArray[i + 2] = 0; // z - edges - don't care + tempArray[i + 3] = f3; // w - pick } - if (cfg.metallicRoughnessMap) { - this._metallicRoughnessMap = this._checkComponent("Texture", cfg.metallicRoughnessMap); + + this._state.flagsBuf.setData(tempArray, firstFlag, lenFlags); + } + + _setFlags2(portionId, flags) { + + if (!this._finalized) { + throw "Not finalized"; } - if (cfg.emissiveMap) { - this._emissiveMap = this._checkComponent("Texture", cfg.emissiveMap); + + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstFlag = vertexBase * 4; + const lenFlags = numVerts * 4; + const tempArray = this._scratchMemory.getUInt8Array(lenFlags); + + const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; + + for (let i = 0; i < lenFlags; i += 4) { + tempArray[i + 0] = clippable; } - if (cfg.occlusionMap) { - this._occlusionMap = this._checkComponent("Texture", cfg.occlusionMap); + + this._state.flags2Buf.setData(tempArray, firstFlag, lenFlags); + } + + setOffset(portionId, offset) { + if (!this._finalized) { + throw "Not finalized"; } - if (cfg.alphaMap) { - this._alphaMap = this._checkComponent("Texture", cfg.alphaMap); + if (!this.model.scene.entityOffsetsEnabled) { + this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled + return; } - if (cfg.normalMap) { - this._normalMap = this._checkComponent("Texture", cfg.normalMap); + const portionsIdx = portionId * 2; + const vertexBase = this._portions[portionsIdx]; + const numVerts = this._portions[portionsIdx + 1]; + const firstOffset = vertexBase * 3; + const lenOffsets = numVerts * 3; + const tempArray = this._scratchMemory.getFloat32Array(lenOffsets); + const x = offset[0]; + const y = offset[1]; + const z = offset[2]; + for (let i = 0; i < lenOffsets; i += 3) { + tempArray[i + 0] = x; + tempArray[i + 1] = y; + tempArray[i + 2] = z; } - - this.alphaMode = cfg.alphaMode; - this.alphaCutoff = cfg.alphaCutoff; - this.backfaces = cfg.backfaces; - this.frontface = cfg.frontface; - this.lineWidth = cfg.lineWidth; - this.pointSize = cfg.pointSize; - - this._makeHash(); + this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets); } - _makeHash() { - const state = this._state; - const hash = ["/met"]; - if (this._baseColorMap) { - hash.push("/bm"); - if (this._baseColorMap._state.hasMatrix) { - hash.push("/mat"); - } - hash.push("/" + this._baseColorMap._state.encoding); + //-- NORMAL RENDERING ---------------------------------------------------------------------------------------------- + + drawColorOpaque(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; } - if (this._metallicMap) { - hash.push("/mm"); - if (this._metallicMap._state.hasMatrix) { - hash.push("/mat"); - } + if (this._pointsBatchingRenderers.colorRenderer) { + this._pointsBatchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); } - if (this._roughnessMap) { - hash.push("/rm"); - if (this._roughnessMap._state.hasMatrix) { - hash.push("/mat"); - } + } + + drawColorTransparent(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { + return; } - if (this._metallicRoughnessMap) { - hash.push("/mrm"); - if (this._metallicRoughnessMap._state.hasMatrix) { - hash.push("/mat"); - } + if (this._pointsBatchingRenderers.colorRenderer) { + this._pointsBatchingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); } - if (this._emissiveMap) { - hash.push("/em"); - if (this._emissiveMap._state.hasMatrix) { - hash.push("/mat"); - } + } + + // -- RENDERING SAO POST EFFECT TARGETS ---------------------------------------------------------------------------- + + drawDepth(renderFlags, frameCtx) { + } + + drawNormals(renderFlags, frameCtx) { + } + + // -- EMPHASIS RENDERING ------------------------------------------------------------------------------------------- + + drawSilhouetteXRayed(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + return; } - if (this._occlusionMap) { - hash.push("/ocm"); - if (this._occlusionMap._state.hasMatrix) { - hash.push("/mat"); - } + if (this._pointsBatchingRenderers.silhouetteRenderer) { + this._pointsBatchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); } - if (this._alphaMap) { - hash.push("/am"); - if (this._alphaMap._state.hasMatrix) { - hash.push("/mat"); - } + } + + drawSilhouetteHighlighted(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + return; } - if (this._normalMap) { - hash.push("/nm"); - if (this._normalMap._state.hasMatrix) { - hash.push("/mat"); - } + if (this._pointsBatchingRenderers.silhouetteRenderer) { + this._pointsBatchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); } - hash.push(";"); - state.hash = hash.join(""); } - - /** - * Sets the RGB diffuse color. - * - * Multiplies by the RGB components of {@link MetallicMaterial#baseColorMap}. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * @type {Number[]} - */ - set baseColor(value) { - let baseColor = this._state.baseColor; - if (!baseColor) { - baseColor = this._state.baseColor = new Float32Array(3); - } else if (value && baseColor[0] === value[0] && baseColor[1] === value[1] && baseColor[2] === value[2]) { + drawSilhouetteSelected(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { return; } - if (value) { - baseColor[0] = value[0]; - baseColor[1] = value[1]; - baseColor[2] = value[2]; - } else { - baseColor[0] = 1; - baseColor[1] = 1; - baseColor[2] = 1; + if (this._pointsBatchingRenderers.silhouetteRenderer) { + this._pointsBatchingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); } - this.glRedraw(); } - /** - * Gets the RGB diffuse color. - * - * Multiplies by the RGB components of {@link MetallicMaterial#baseColorMap}. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * @type {Number[]} - */ - get baseColor() { - return this._state.baseColor; + //-- EDGES RENDERING ----------------------------------------------------------------------------------------------- + + drawEdgesColorOpaque(renderFlags, frameCtx) { } + drawEdgesColorTransparent(renderFlags, frameCtx) { + } - /** - * Gets the RGB {@link Texture} containing the diffuse color of this MetallicMaterial, with optional *A* component for alpha. - * - * The RGB components multiply by {@link MetallicMaterial#baseColor}, while the *A* component, if present, multiplies by {@link MetallicMaterial#alpha}. - * - * @type {Texture} - */ - get baseColorMap() { - return this._baseColorMap; + drawEdgesHighlighted(renderFlags, frameCtx) { } - /** - * Sets the metallic factor. - * - * This is in the range ````[0..1]```` and indicates how metallic this MetallicMaterial is. - * - * ````1```` is metal, ````0```` is non-metal. - * - * Multiplies by the *R* component of {@link MetallicMaterial#metallicMap} and the *A* component of {@link MetallicMaterial#metallicRoughnessMap}. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set metallic(value) { - value = (value !== undefined && value !== null) ? value : 1.0; - if (this._state.metallic === value) { - return; - } - this._state.metallic = value; - this.glRedraw(); + drawEdgesSelected(renderFlags, frameCtx) { } - /** - * Gets the metallic factor. - * - * @type {Number} - */ - get metallic() { - return this._state.metallic; + drawEdgesXRayed(renderFlags, frameCtx) { } - /** - * Gets the RGB {@link Texture} containing this MetallicMaterial's metallic factor in its *R* component. - * - * The *R* component multiplies by {@link MetallicMaterial#metallic}. - * - * @type {Texture} - */ - get metallicMap() { - return this._attached.metallicMap; - } + //---- PICKING ---------------------------------------------------------------------------------------------------- - /** - * Sets the roughness factor. - * - * This factor is in the range ````[0..1]````, where ````0```` is fully smooth,````1```` is fully rough. - * - * Multiplies by the *R* component of {@link MetallicMaterial#roughnessMap}. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set roughness(value) { - value = (value !== undefined && value !== null) ? value : 1.0; - if (this._state.roughness === value) { + drawPickMesh(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { return; } - this._state.roughness = value; - this.glRedraw(); + if (this._pointsBatchingRenderers.pickMeshRenderer) { + this._pointsBatchingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } } - /** - * Gets the roughness factor. - * - * @type {Number} - */ - get roughness() { - return this._state.roughness; + drawPickDepths(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + if (this._pointsBatchingRenderers.pickDepthRenderer) { + this._pointsBatchingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } } - /** - * Gets the RGB {@link Texture} containing this MetallicMaterial's roughness factor in its *R* component. - * - * The *R* component multiplies by {@link MetallicMaterial#roughness}. - * - * @type {Texture} - */ - get roughnessMap() { - return this._attached.roughnessMap; + drawPickNormals(renderFlags, frameCtx) { } - /** - * Gets the RGB {@link Texture} containing this MetallicMaterial's metalness in its *R* component and roughness in its *G* component. - * - * Its *B* component multiplies by the {@link MetallicMaterial#metallic} property, while its *G* component multiplies by the {@link MetallicMaterial#roughness} property. - * - * @type {Texture} - */ - get metallicRoughnessMap() { - return this._attached.metallicRoughnessMap; - } + //---- OCCLUSION TESTING ------------------------------------------------------------------------------------------- - /** - * Sets the factor in the range [0..1] indicating specular Fresnel value. - * - * Default value is ````0.0````. - * - * @type {Number} - */ - set specularF0(value) { - value = (value !== undefined && value !== null) ? value : 0.0; - if (this._state.specularF0 === value) { + drawOcclusion(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { return; } - this._state.specularF0 = value; - this.glRedraw(); + if (this._pointsBatchingRenderers.occlusionRenderer) { + this._pointsBatchingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } } - /** - * Gets the factor in the range [0..1] indicating specular Fresnel value. - * - * @type {Number} - */ - get specularF0() { - return this._state.specularF0; + //---- SHADOWS ----------------------------------------------------------------------------------------------------- + + drawShadow(renderFlags, frameCtx) { } - /** - * Sets the RGB emissive color. - * - * Multiplies by {@link MetallicMaterial#emissiveMap}. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @type {Number[]} - */ - set emissive(value) { - let emissive = this._state.emissive; - if (!emissive) { - emissive = this._state.emissive = new Float32Array(3); - } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) { - return; + destroy() { + const state = this._state; + if (state.positionsBuf) { + state.positionsBuf.destroy(); + state.positionsBuf = null; } - if (value) { - emissive[0] = value[0]; - emissive[1] = value[1]; - emissive[2] = value[2]; - } else { - emissive[0] = 0; - emissive[1] = 0; - emissive[2] = 0; + if (state.offsetsBuf) { + state.offsetsBuf.destroy(); + state.offsetsBuf = null; } - this.glRedraw(); + if (state.colorsBuf) { + state.colorsBuf.destroy(); + state.colorsBuf = null; + } + if (state.flagsBuf) { + state.flagsBuf.destroy(); + state.flagsBuf = null; + } + if (state.flags2Buf) { + state.flags2Buf.destroy(); + state.flags2Buf = null; + } + if (state.pickColorsBuf) { + state.pickColorsBuf.destroy(); + state.pickColorsBuf = null; + } + state.destroy(); } +} - /** - * Gets the RGB emissive color. - * - * @type {Number[]} - */ - get emissive() { - return this._state.emissive; +const tempVec3a$f = math.vec3(); + +/** + * @private + */ +class PointsInstancingColorRenderer { + + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - /** - * Gets the RGB emissive map. - * - * Multiplies by {@link MetallicMaterial#emissive}. - * - * @type {Texture} - */ - get emissiveMap() { - return this._attached.emissiveMap; + getValid() { + return this._hash === this._getHash(); } - /** - * Gets the RGB ambient occlusion map. - * - * Multiplies by the specular and diffuse light reflected by surfaces. - * - * @type {Texture} - */ - get occlusionMap() { - return this._attached.occlusionMap; + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; } - /** - * Sets factor in the range ````[0..1]```` that indicates the alpha value. - * - * Multiplies by the *R* component of {@link MetallicMaterial#alphaMap} and the *A* component, if present, of {@link MetallicMaterial#baseColorMap}. - * - * The value of {@link MetallicMaterial#alphaMode} indicates how alpha is interpreted when rendering. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set alpha(value) { - value = (value !== undefined && value !== null) ? value : 1.0; - if (this._state.alpha === value) { - return; + drawLayer(frameCtx, instancingLayer, renderPass) { + + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + const geometry = instancingLayer.geometry; + + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } } - this._state.alpha = value; - this.glRedraw(); - } - /** - * Gets factor in the range ````[0..1]```` that indicates the alpha value. - * - * @type {Number} - */ - get alpha() { - return this._state.alpha; - } + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - /** - * Gets the RGB {@link Texture} containing this MetallicMaterial's alpha in its *R* component. - * - * The *R* component multiplies by the {@link MetallicMaterial#alpha} property. - * - * @type {Texture} - */ - get alphaMap() { - return this._attached.alphaMap; - } + gl.uniform1i(this._uRenderPass, renderPass); - /** - * Gets the RGB tangent-space normal map {@link Texture}. - * - * @type {Texture} - */ - get normalMap() { - return this._attached.normalMap; - } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - /** - * Sets the alpha rendering mode. - * - * This specifies how alpha is interpreted. Alpha is the combined result of the {@link MetallicMaterial#alpha} and {@link MetallicMaterial#alphaMap} properties. - * - * Accepted values are: - * - * * "opaque" - The alpha value is ignored and the rendered output is fully opaque (default). - * * "mask" - The rendered output is either fully opaque or fully transparent depending on the alpha and {@link MetallicMaterial#alphaCutoff}. - * * "blend" - The alpha value is used to composite the source and destination areas. The rendered output is combined with the background using the normal painting operation (i.e. the Porter and Duff over operator). - * - * @type {String} - */ - set alphaMode(alphaMode) { - alphaMode = alphaMode || "opaque"; - let value = modes[alphaMode]; - if (value === undefined) { - this.error("Unsupported value for 'alphaMode': " + alphaMode + " defaulting to 'opaque'"); - value = "opaque"; + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + this._aColor.bindArrayBuffer(geometry.colorsBuf); + + if (pointsMaterial.filterIntensity) { + gl.uniform2f(this._uIntensityRange, pointsMaterial.minIntensity, pointsMaterial.maxIntensity); } - if (this._state.alphaMode === value) { - return; + + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$f); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - this._state.alphaMode = value; - this.glRedraw(); - } - /** - * Gets the alpha rendering mode. - * - * @type {String} - */ - get alphaMode() { - return modeNames[this._state.alphaMode]; - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - /** - * Sets the alpha cutoff value. - * - * Specifies the cutoff threshold when {@link MetallicMaterial#alphaMode} equals "mask". If the alpha is greater than or equal to this value then it is rendered as fully opaque, otherwise, it is rendered as fully transparent. A value greater than 1.0 will render the entire - * material as fully transparent. This value is ignored for other modes. - * - * Alpha is the combined result of the {@link MetallicMaterial#alpha} and {@link MetallicMaterial#alphaMap} properties. - * - * Default value is ````0.5````. - * - * @type {Number} - */ - set alphaCutoff(alphaCutoff) { - if (alphaCutoff === null || alphaCutoff === undefined) { - alphaCutoff = 0.5; + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - if (this._state.alphaCutoff === alphaCutoff) { - return; + + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - this._state.alphaCutoff = alphaCutoff; - } - /** - * Gets the alpha cutoff value. - * - * @type {Number} - */ - get alphaCutoff() { - return this._state.alphaCutoff; - } + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - /** - * Sets whether backfaces are visible on attached {@link Mesh}es. - * - * The backfaces will belong to {@link ReadableGeometry} compoents that are also attached to the {@link Mesh}es. - * - * Default is ````false````. - * - * @type {Boolean} - */ - set backfaces(value) { - value = !!value; - if (this._state.backfaces === value) { - return; + gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + + frameCtx.drawArrays++; + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + + gl.vertexAttribDivisor(this._aFlags.location, 0); + + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - this._state.backfaces = value; - this.glRedraw(); - } - /** - * Gets whether backfaces are visible on attached {@link Mesh}es. - * - * @type {Boolean} - */ - get backfaces() { - return this._state.backfaces; + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } } - /** - * Sets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. - * - * Default value is ````"ccw"````. - * - * @type {String} - */ - set frontface(value) { - value = value !== "cw"; - if (this._state.frontface === value) { + _allocate() { + + const scene = this._scene; + const pointsMaterial = scene.pointsMaterial._state; + const gl = scene.canvas.gl; + + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; return; } - this._state.frontface = value; - this.glRedraw(); - } - /** - * Gets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. -* - * @type {String} - */ - get frontface() { - return this._state.frontface ? "ccw" : "cw"; - } + const program = this._program; - /** - * Sets the MetallicMaterial's line width. - * - * This is not supported by WebGL implementations based on DirectX [2019]. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set lineWidth(value) { - this._state.lineWidth = value || 1.0; - this.glRedraw(); - } + this._uRenderPass = program.getLocation("renderPass"); - /** - * Gets the MetallicMaterial's line width. - * - * @type {Number} - */ - get lineWidth() { - return this._state.lineWidth; - } + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); - /** - * Sets the MetallicMaterial's point size. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set pointSize(value) { - this._state.pointSize = value || 1.0; - this.glRedraw(); - } + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - /** - * Gets the MetallicMaterial's point size. - * - * @type {Number} - */ - get pointSize() { - return this._state.pointSize; - } + this._uSectionPlanes = []; - /** - * Destroys this MetallicMaterial. - */ - destroy() { - super.destroy(); - this._state.destroy(); - } -} + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } -const alphaModes = {"opaque": 0, "mask": 1, "blend": 2}; -const alphaModeNames = ["opaque", "mask", "blend"]; + this._aPosition = program.getAttribute("position"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aOffset = program.getAttribute("offset"); -/** - * @desc Configures the normal rendered appearance of {@link Mesh}es using the physically-accurate *specular-glossiness* shading model. - * - * * Useful for insulators, such as wood, ceramics and plastic. - * * {@link MetallicMaterial} is best for conductive materials, such as metal. - * * {@link PhongMaterial} is appropriate for non-realistic objects. - * * {@link LambertMaterial} is appropriate for high-detail models that need to render as efficiently as possible. - * - * ## Usage - * - * In the example below we'll create a {@link Mesh} with a {@link buildTorusGeometry} and a SpecularMaterial. - * - * Note that in this example we're providing separate {@link Texture} for the {@link SpecularMaterial#specular} and {@link SpecularMaterial#glossiness} - * channels, which allows us a little creative flexibility. Then, in the next example further down, we'll combine those channels - * within the same {@link Texture} for efficiency. - * - * ````javascript - * import {Viewer, Mesh, buildTorusGeometry, SpecularMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ canvasId: "myCanvas" }); - * - * const myMesh = new Mesh(viewer.scene,{ - * - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry()), - * - * material: new SpecularMaterial(viewer.scene,{ - * - * // Channels with default values, just to show them - * - * diffuse: [1.0, 1.0, 1.0], - * specular: [1.0, 1.0, 1.0], - * glossiness: 1.0, - * emissive: [0.0, 0.0, 0.0] - * alpha: 1.0, - * - * // Textures to multiply some of the channels - * - * diffuseMap: new Texture(viewer.scene, { // RGB components multiply by diffuse - * src: "textures/diffuse.jpg" - * }), - * specularMap: new Texture(viewer.scene, { // RGB component multiplies by specular - * src: "textures/specular.jpg" - * }), - * glossinessMap: new Texture(viewer.scene, { // R component multiplies by glossiness - * src: "textures/glossiness.jpg" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "textures/normalMap.jpg" - * }) - * }) - * }); - * ```` - * - * ## Combining Channels Within the Same Textures - * - * In the previous example we provided separate {@link Texture} for the {@link SpecularMaterial#specular} and - * {@link SpecularMaterial#glossiness} channels, but we can combine those channels into the same {@link Texture} to reduce - * download time, memory footprint and rendering time (and also for glTF compatibility). - * - * Here's our SpecularMaterial again with those channels combined in the {@link SpecularMaterial#specularGlossinessMap} - * {@link Texture}, where the *RGB* component multiplies by {@link SpecularMaterial#specular} and *A* multiplies by {@link SpecularMaterial#glossiness}. - * - * ````javascript - * const myMesh = new Mesh(viewer.scene,{ - * - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry()), - * - * material: new SpecularMaterial(viewer.scene,{ - * - * // Channels with default values, just to show them - * - * diffuse: [1.0, 1.0, 1.0], - * specular: [1.0, 1.0, 1.0], - * glossiness: 1.0, - * emissive: [0.0, 0.0, 0.0] - * alpha: 1.0, - * - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse.jpg" - * }), - * specularGlossinessMap: new Texture(viewer.scene, { // RGB multiplies by specular, A by glossiness - * src: "textures/specularGlossiness.jpg" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "textures/normalMap.jpg" - * }) - * }) - * }); - * ```` - * - * Although not shown in this example, we can also texture {@link SpecularMaterial#alpha} with - * the *A* component of {@link SpecularMaterial#diffuseMap}'s {@link Texture}, if required. - * - * ## Alpha Blending - * - * Let's make our {@link Mesh} transparent. We'll redefine {@link SpecularMaterial#alpha} - * and {@link SpecularMaterial#alphaMode}, causing it to blend 50% with the background: - * - * ````javascript - * const myMesh = new Mesh(viewer.scene,{ - * - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry()), - * - * material: new SpecularMaterial(viewer.scene,{ - * - * // Channels with default values, just to show them - * - * diffuse: [1.0, 1.0, 1.0], - * specular: [1.0, 1.0, 1.0], - * glossiness: 1.0, - * emissive: [0.0, 0.0, 0.0] - * alpha: 0.5, // <<----------- Changed - * alphaMode: "blend", // <<----------- Added - * - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse.jpg" - * }), - * specularGlossinessMap: new Texture(viewer.scene, { // RGB multiplies by specular, A by glossiness - * src: "textures/specularGlossiness.jpg" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "textures/normalMap.jpg" - * }) - * }) - * }); - * ```` - * - * ## Alpha Masking - * - * Now let's make holes in our {@link Mesh}. We'll give its SpecularMaterial an {@link SpecularMaterial#alphaMap} - * and configure {@link SpecularMaterial#alpha}, {@link SpecularMaterial#alphaMode}, - * and {@link SpecularMaterial#alphaCutoff} to treat it as an alpha mask: - * - * ````javascript - * const myMesh = new Mesh(viewer.scene,{ - * - * geometry: buildTorusGeometry(viewer.scene, ReadableGeometry, {}), - * - * material: new SpecularMaterial(viewer.scene, { - * - * // Channels with default values, just to show them - * - * diffuse: [1.0, 1.0, 1.0], - * specular: [1.0, 1.0, 1.0], - * glossiness: 1.0, - * emissive: [0.0, 0.0, 0.0] - * alpha: 1.0, // <<----------- Changed - * alphaMode: "mask", // <<----------- Changed - * alphaCutoff: 0.2, // <<----------- Added - * - * alphaMap: new Texture(viewer.scene, { // <<---------- Added - * src: "textures/diffuse/crossGridColorMap.jpg" - * }), - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse.jpg" - * }), - * specularGlossinessMap: new Texture(viewer.scene, { // RGB multiplies by specular, A by glossiness - * src: "textures/specularGlossiness.jpg" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "textures/normalMap.jpg" - * }) - * }) - * }); - * ```` - * - * ## Background Theory - * - * For an introduction to physically-based rendering (PBR) concepts, try these articles: - * - * * Joe Wilson's [Basic Theory of Physically-Based Rendering](https://www.marmoset.co/posts/basic-theory-of-physically-based-rendering/) - * * Jeff Russel's [Physically-based Rendering, and you can too!](https://www.marmoset.co/posts/physically-based-rendering-and-you-can-too/) - * * Sebastien Legarde's [Adapting a physically-based shading model](http://seblagarde.wordpress.com/tag/physically-based-rendering/) - * - * ## SpecularMaterial Properties - * - * The following table summarizes SpecularMaterial properties: - * - * | Property | Type | Range | Default Value | Space | Description | - * |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:| - * | {@link SpecularMaterial#diffuse} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the diffuse color of the material. | - * | {@link SpecularMaterial#specular} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the specular color of the material. | - * | {@link SpecularMaterial#glossiness} | Number | [0, 1] | 1 | linear | The glossiness the material. | - * | {@link SpecularMaterial#specularF0} | Number | [0, 1] | 1 | linear | The specularF0 of the material surface. | - * | {@link SpecularMaterial#emissive} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the emissive color of the material. | - * | {@link SpecularMaterial#alpha} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). | - * | {@link SpecularMaterial#diffuseMap} | {@link Texture} | | null | sRGB | Texture RGB components multiplying by {@link SpecularMaterial#diffuse}. If the fourth component (A) is present, it multiplies by {@link SpecularMaterial#alpha}. | - * | {@link SpecularMaterial#specularMap} | {@link Texture} | | null | sRGB | Texture RGB components multiplying by {@link SpecularMaterial#specular}. If the fourth component (A) is present, it multiplies by {@link SpecularMaterial#alpha}. | - * | {@link SpecularMaterial#glossinessMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link SpecularMaterial#glossiness}. | - * | {@link SpecularMaterial#specularGlossinessMap} | {@link Texture} | | null | linear | Texture with first three components multiplying by {@link SpecularMaterial#specular} and fourth component multiplying by {@link SpecularMaterial#glossiness}. | - * | {@link SpecularMaterial#emissiveMap} | {@link Texture} | | null | linear | Texture with RGB components multiplying by {@link SpecularMaterial#emissive}. | - * | {@link SpecularMaterial#alphaMap} | {@link Texture} | | null | linear | Texture with first component multiplying by {@link SpecularMaterial#alpha}. | - * | {@link SpecularMaterial#occlusionMap} | {@link Texture} | | null | linear | Ambient occlusion texture multiplying by surface's reflected diffuse and specular light. | - * | {@link SpecularMaterial#normalMap} | {@link Texture} | | null | linear | Tangent-space normal map. | - * | {@link SpecularMaterial#alphaMode} | String | "opaque", "blend", "mask" | "blend" | | Alpha blend mode. | - * | {@link SpecularMaterial#alphaCutoff} | Number | [0..1] | 0.5 | | Alpha cutoff value. | - * | {@link SpecularMaterial#backfaces} | Boolean | | false | | Whether to render {@link Geometry} backfaces. | - * | {@link SpecularMaterial#frontface} | String | "ccw", "cw" | "ccw" | | The winding order for {@link Geometry} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. | - * - */ -class SpecularMaterial extends Material { + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - /** - @private - */ - get type() { - return "SpecularMaterial"; + this._uOcclusionTexture = "uOcclusionTexture"; + + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); + + if (pointsMaterial.filterIntensity) { + this._uIntensityRange = program.getLocation("intensityRange"); + } + + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - /** - * - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] The SpecularMaterial configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number[]} [cfg.diffuse=[1,1,1]] RGB diffuse color of this SpecularMaterial. Multiplies by the RGB components of {@link SpecularMaterial#diffuseMap}. - * @param {Texture} [cfg.diffuseMap=undefined] RGBA {@link Texture} containing the diffuse color of this SpecularMaterial, with optional *A* component for alpha. The RGB components multiply by {@link SpecularMaterial#diffuse}, while the *A* component, if present, multiplies by {@link SpecularMaterial#alpha}. - * @param {Number} [cfg.specular=[1,1,1]] RGB specular color of this SpecularMaterial. Multiplies by the {@link SpecularMaterial#specularMap} and the *RGB* components of {@link SpecularMaterial#specularGlossinessMap}. - * @param {Texture} [cfg.specularMap=undefined] RGB texture containing the specular color of this SpecularMaterial. Multiplies by the {@link SpecularMaterial#specular} property. Must be within the same {@link Scene} as this SpecularMaterial. - * @param {Number} [cfg.glossiness=1.0] Factor in the range [0..1] indicating how glossy this SpecularMaterial is. 0 is no glossiness, 1 is full glossiness. Multiplies by the *R* component of {@link SpecularMaterial#glossinessMap} and the *A* component of {@link SpecularMaterial#specularGlossinessMap}. - * @param {Texture} [cfg.specularGlossinessMap=undefined] RGBA {@link Texture} containing this SpecularMaterial's specular color in its *RGB* component and glossiness in its *A* component. Its *RGB* components multiply by {@link SpecularMaterial#specular}, while its *A* component multiplies by {@link SpecularMaterial#glossiness}. Must be within the same {@link Scene} as this SpecularMaterial. - * @param {Number} [cfg.specularF0=0.0] Factor in the range 0..1 indicating how reflective this SpecularMaterial is. - * @param {Number[]} [cfg.emissive=[0,0,0]] RGB emissive color of this SpecularMaterial. Multiplies by the RGB components of {@link SpecularMaterial#emissiveMap}. - * @param {Texture} [cfg.emissiveMap=undefined] RGB {@link Texture} containing the emissive color of this SpecularMaterial. Multiplies by the {@link SpecularMaterial#emissive} property. Must be within the same {@link Scene} as this SpecularMaterial. - * @param {Texture} [cfg.occlusionMap=undefined] RGB ambient occlusion {@link Texture}. Within shaders, multiplies by the specular and diffuse light reflected by surfaces. Must be within the same {@link Scene} as this SpecularMaterial. - * @param {Texture} [cfg.normalMap=undefined] {Texture} RGB tangent-space normal {@link Texture}. Must be within the same {@link Scene} as this SpecularMaterial. - * @param {Number} [cfg.alpha=1.0] Factor in the range 0..1 indicating how transparent this SpecularMaterial is. A value of 0.0 indicates fully transparent, 1.0 is fully opaque. Multiplies by the *R* component of {@link SpecularMaterial#alphaMap} and the *A* component, if present, of {@link SpecularMaterial#diffuseMap}. - * @param {Texture} [cfg.alphaMap=undefined] RGB {@link Texture} containing this SpecularMaterial's alpha in its *R* component. The *R* component multiplies by the {@link SpecularMaterial#alpha} property. Must be within the same {@link Scene} as this SpecularMaterial. - * @param {String} [cfg.alphaMode="opaque"] The alpha blend mode - accepted values are "opaque", "blend" and "mask". See the {@link SpecularMaterial#alphaMode} property for more info. - * @param {Number} [cfg.alphaCutoff=0.5] The alpha cutoff value. See the {@link SpecularMaterial#alphaCutoff} property for more info. - * @param {Boolean} [cfg.backfaces=false] Whether to render {@link Geometry} backfaces. - * @param {Boolean} [cfg.frontface="ccw"] The winding order for {@link Geometry} front faces - "cw" for clockwise, or "ccw" for counter-clockwise. - * @param {Number} [cfg.lineWidth=1] Scalar that controls the width of {@link Geometry lines. - * @param {Number} [cfg.pointSize=1] Scalar that controls the size of {@link Geometry} points. - */ - constructor(owner, cfg = {}) { + _bindProgram() { - super(owner, cfg); + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - this._state = new RenderState({ - type: "SpecularMaterial", - diffuse: math.vec3([1.0, 1.0, 1.0]), - emissive: math.vec3([0.0, 0.0, 0.0]), - specular: math.vec3([1.0, 1.0, 1.0]), - glossiness: null, - specularF0: null, - alpha: null, - alphaMode: null, - alphaCutoff: null, - lineWidth: null, - pointSize: null, - backfaces: null, - frontface: null, // Boolean for speed; true == "ccw", false == "cw" - hash: null - }); + this._program.bind(); - this.diffuse = cfg.diffuse; - this.specular = cfg.specular; - this.glossiness = cfg.glossiness; - this.specularF0 = cfg.specularF0; - this.emissive = cfg.emissive; - this.alpha = cfg.alpha; + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - if (cfg.diffuseMap) { - this._diffuseMap = this._checkComponent("Texture", cfg.diffuseMap); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - if (cfg.emissiveMap) { - this._emissiveMap = this._checkComponent("Texture", cfg.emissiveMap); + } + + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } + + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push('#version 300 es'); + src.push("// Points instancing color vertex shader"); + + src.push("uniform int renderPass;"); + + src.push("in vec3 position;"); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - if (cfg.specularMap) { - this._specularMap = this._checkComponent("Texture", cfg.specularMap); + + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); } - if (cfg.glossinessMap) { - this._glossinessMap = this._checkComponent("Texture", cfg.glossinessMap); + + if (pointsMaterial.filterIntensity) { + src.push("uniform vec2 intensityRange;"); } - if (cfg.specularGlossinessMap) { - this._specularGlossinessMap = this._checkComponent("Texture", cfg.specularGlossinessMap); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); } - if (cfg.occlusionMap) { - this._occlusionMap = this._checkComponent("Texture", cfg.occlusionMap); + + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - if (cfg.alphaMap) { - this._alphaMap = this._checkComponent("Texture", cfg.alphaMap); + src.push("out vec4 vColor;"); + + src.push("void main(void) {"); + + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE | COLOR_TRANSPARENT + + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + + if (pointsMaterial.filterIntensity) { + src.push("float intensity = float(color.a) / 255.0;"); + src.push("if (intensity < intensityRange[0] || intensity > intensityRange[1]) {"); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); } - if (cfg.normalMap) { - this._normalMap = this._checkComponent("Texture", cfg.normalMap); + + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); } - this.alphaMode = cfg.alphaMode; - this.alphaCutoff = cfg.alphaCutoff; - this.backfaces = cfg.backfaces; - this.frontface = cfg.frontface; + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); - this.lineWidth = cfg.lineWidth; - this.pointSize = cfg.pointSize; + src.push("vColor = vec4(float(color.r) / 255.0, float(color.g) / 255.0, float(color.b) / 255.0, 1.0);"); - this._makeHash(); - } + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } - _makeHash() { - const state = this._state; - const hash = ["/spe"]; - if (this._diffuseMap) { - hash.push("/dm"); - if (this._diffuseMap.hasMatrix) { - hash.push("/mat"); - } - hash.push("/" + this._diffuseMap.encoding); + src.push("vec4 clipPos = projMatrix * viewPosition;"); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); } - if (this._emissiveMap) { - hash.push("/em"); - if (this._emissiveMap.hasMatrix) { - hash.push("/mat"); - } + + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); } - if (this._glossinessMap) { - hash.push("/gm"); - if (this._glossinessMap.hasMatrix) { - hash.push("/mat"); - } + src.push("}"); + if (pointsMaterial.filterIntensity) { + src.push("}"); } - if (this._specularMap) { - hash.push("/sm"); - if (this._specularMap.hasMatrix) { - hash.push("/mat"); - } + src.push("}"); + return src; + } + + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Points instancing color fragment shader"); + + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); } - if (this._specularGlossinessMap) { - hash.push("/sgm"); - if (this._specularGlossinessMap.hasMatrix) { - hash.push("/mat"); + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } } - if (this._occlusionMap) { - hash.push("/ocm"); - if (this._occlusionMap.hasMatrix) { - hash.push("/mat"); - } + src.push("in vec4 vColor;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); } - if (this._normalMap) { - hash.push("/nm"); - if (this._normalMap.hasMatrix) { - hash.push("/mat"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); } - if (this._alphaMap) { - hash.push("/opm"); - if (this._alphaMap.hasMatrix) { - hash.push("/mat"); - } + src.push(" outColor = vColor;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); } - hash.push(";"); - state.hash = hash.join(""); + src.push("}"); + return src; } - /** - * Sets the RGB diffuse color of this SpecularMaterial. - * - * Multiplies by the *RGB* components of {@link SpecularMaterial#diffuseMap}. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * @type {Number[]} - */ - set diffuse(value) { - let diffuse = this._state.diffuse; - if (!diffuse) { - diffuse = this._state.diffuse = new Float32Array(3); - } else if (value && diffuse[0] === value[0] && diffuse[1] === value[1] && diffuse[2] === value[2]) { - return; - } - if (value) { - diffuse[0] = value[0]; - diffuse[1] = value[1]; - diffuse[2] = value[2]; - } else { - diffuse[0] = 1; - diffuse[1] = 1; - diffuse[2] = 1; - } - this.glRedraw(); + webglContextRestored() { + this._program = null; } - /** - * Gets the RGB diffuse color of this SpecularMaterial. - * - * @type {Number[]} - */ - get diffuse() { - return this._state.diffuse; + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; } +} - /** - * Gets the RGB {@link Texture} containing the diffuse color of this SpecularMaterial, with optional *A* component for alpha. - * - * The *RGB* components multipliues by the {@link SpecularMaterial#diffuse} property, while the *A* component, if present, multiplies by the {@link SpecularMaterial#alpha} property. - * - * @type {Texture} - */ - get diffuseMap() { - return this._diffuseMap; +const tempVec3a$e = math.vec3(); + +/** + * @private + */ +class PointsInstancingSilhouetteRenderer { + + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } - /** - * Sets the RGB specular color of this SpecularMaterial. - * - * Multiplies by {@link SpecularMaterial#specularMap} and the *A* component of {@link SpecularMaterial#specularGlossinessMap}. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @type {Number[]} - */ - set specular(value) { - let specular = this._state.specular; - if (!specular) { - specular = this._state.specular = new Float32Array(3); - } else if (value && specular[0] === value[0] && specular[1] === value[1] && specular[2] === value[2]) { - return; + getValid() { + return this._hash === this._getHash(); + }; + + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + } + + drawLayer(frameCtx, instancingLayer, renderPass) { + + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + const geometry = instancingLayer.geometry; + + if (!this._program) { + this._allocate(instancingLayer.model.scene); + if (this.errors) { + return; + } } - if (value) { - specular[0] = value[0]; - specular[1] = value[1]; - specular[2] = value[2]; + + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } + + gl.uniform1i(this._uRenderPass, renderPass); + + if (renderPass === RENDER_PASSES.SILHOUETTE_XRAYED) { + const material = scene.xrayMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_HIGHLIGHTED) { + const material = scene.highlightMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + + } else if (renderPass === RENDER_PASSES.SILHOUETTE_SELECTED) { + const material = scene.selectedMaterial._state; + const fillColor = material.fillColor; + const fillAlpha = material.fillAlpha; + gl.uniform4f(this._uColor, fillColor[0], fillColor[1], fillColor[2], fillAlpha); + } else { - specular[0] = 1; - specular[1] = 1; - specular[2] = 1; + gl.uniform4fv(this._uColor, math.vec3([1, 1, 1])); } - this.glRedraw(); - } - /** - * Gets the RGB specular color of this SpecularMaterial. - * - * @type {Number[]} - */ - get specular() { - return this._state.specular; - } + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - /** - * Gets the RGB texture containing the specular color of this SpecularMaterial. - * - * Multiplies by {@link SpecularMaterial#specular}. - * - * @type {Texture} - */ - get specularMap() { - return this._specularMap; - } + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$e); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } + } - /** - * Gets the RGBA texture containing this SpecularMaterial's specular color in its *RGB* components and glossiness in its *A* component. - * - * The *RGB* components multiplies {@link SpecularMaterial#specular}, while the *A* component multiplies by {@link SpecularMaterial#glossiness}. - * - * @type {Texture} - */ - get specularGlossinessMap() { - return this._specularGlossinessMap; - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - /** - * Sets the Factor in the range [0..1] indicating how glossy this SpecularMaterial is. - * - * ````0```` is no glossiness, ````1```` is full glossiness. - * - * Multiplies by the *R* component of {@link SpecularMaterial#glossinessMap} and the *A* component of {@link SpecularMaterial#specularGlossinessMap}. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set glossiness(value) { - value = (value !== undefined && value !== null) ? value : 1.0; - if (this._state.glossiness === value) { - return; + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); + + this._aPosition.bindArrayBuffer(geometry.positionsBuf); + + this._aFlags.bindArrayBuffer(state.flagsBuf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf, gl.UNSIGNED_BYTE, true); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - this._state.glossiness = value; - this.glRedraw(); - } - /** - * Gets the Factor in the range ````[0..1]```` indicating how glossy this SpecularMaterial is. + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - * @type {Number} - */ - get glossiness() { - return this._state.glossiness; - } + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - /** - * Gets the RGB texture containing this SpecularMaterial's glossiness in its *R* component. - * - * The *R* component multiplies by {@link SpecularMaterial#glossiness}. - ** @type {Texture} - */ - get glossinessMap() { - return this._glossinessMap; - } + gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); - /** - * Sets the factor in the range ````[0..1]```` indicating amount of specular Fresnel. - * - * Default value is ````0.0````. - * - * @type {Number} - */ - set specularF0(value) { - value = (value !== undefined && value !== null) ? value : 0.0; - if (this._state.specularF0 === value) { - return; + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); // TODO: Is this needed + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + + gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { + gl.vertexAttribDivisor(this._aFlags2.location, 0); + } + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } - this._state.specularF0 = value; - this.glRedraw(); } - /** - * Gets the factor in the range ````[0..1]```` indicating amount of specular Fresnel. - * - * @type {Number} - */ - get specularF0() { - return this._state.specularF0; - } + _allocate() { - /** - * Sets the RGB emissive color of this SpecularMaterial. - * - * Multiplies by {@link SpecularMaterial#emissiveMap}. + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @type {Number[]} - */ - set emissive(value) { - let emissive = this._state.emissive; - if (!emissive) { - emissive = this._state.emissive = new Float32Array(3); - } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) { + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; return; } - if (value) { - emissive[0] = value[0]; - emissive[1] = value[1]; - emissive[2] = value[2]; - } else { - emissive[0] = 0; - emissive[1] = 0; - emissive[2] = 0; + + const program = this._program; + + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uColor = program.getLocation("color"); + this._uSectionPlanes = []; + + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - this.glRedraw(); - } - /** - * Gets the RGB emissive color of this SpecularMaterial. - * - * @type {Number[]} - */ - get emissive() { - return this._state.emissive; - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - /** - * Gets the RGB texture containing the emissive color of this SpecularMaterial. - * - * Multiplies by {@link SpecularMaterial#emissive}. - * - * @type {Texture} - */ - get emissiveMap() { - return this._emissiveMap; - } + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - /** - * Sets the factor in the range [0..1] indicating how transparent this SpecularMaterial is. - * - * A value of ````0.0```` is fully transparent, while ````1.0```` is fully opaque. - * - * Multiplies by the *R* component of {@link SpecularMaterial#alphaMap} and the *A* component, if present, of {@link SpecularMaterial#diffuseMap}. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set alpha(value) { - value = (value !== undefined && value !== null) ? value : 1.0; - if (this._state.alpha === value) { - return; + if ( scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); } - this._state.alpha = value; - this.glRedraw(); } - /** - * Gets the factor in the range [0..1] indicating how transparent this SpecularMaterial is. - * - * @type {Number} - */ - get alpha() { - return this._state.alpha; - } + _bindProgram() { - /** - * Gets the RGB {@link Texture} with alpha in its *R* component. - * - * The *R* component multiplies by the {@link SpecularMaterial#alpha} property. - * - * @type {Texture} - */ - get alphaMap() { - return this._alphaMap; - } + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - /** - * Gets the RGB tangent-space normal {@link Texture} attached to this SpecularMaterial. - * - * @type {Texture} - */ - get normalMap() { - return this._normalMap; - } + this._program.bind(); - /** - * Gets the RGB ambient occlusion {@link Texture} attached to this SpecularMaterial. - * - * Multiplies by the specular and diffuse light reflected by surfaces. - * - * @type {Texture} - */ - get occlusionMap() { - return this._occlusionMap; - } + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - /** - * Sets the alpha rendering mode. - * - * This governs how alpha is treated. Alpha is the combined result of the {@link SpecularMaterial#alpha} and {@link SpecularMaterial#alphaMap} properties. - * - * Accepted values are: - * - * * "opaque" - The alpha value is ignored and the rendered output is fully opaque (default). - * * "mask" - The rendered output is either fully opaque or fully transparent depending on the alpha value and the specified alpha cutoff value. - * * "blend" - The alpha value is used to composite the source and destination areas. The rendered output is combined with the background using the normal painting operation (i.e. the Porter and Duff over operator) - * - * @type {String} - */ - set alphaMode(alphaMode) { - alphaMode = alphaMode || "opaque"; - let value = alphaModes[alphaMode]; - if (value === undefined) { - this.error("Unsupported value for 'alphaMode': " + alphaMode + " defaulting to 'opaque'"); - value = "opaque"; - } - if (this._state.alphaMode === value) { - return; + if ( scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - this._state.alphaMode = value; - this.glRedraw(); } - get alphaMode() { - return alphaModeNames[this._state.alphaMode]; + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - /** - * Sets the alpha cutoff value. - * - * Specifies the cutoff threshold when {@link SpecularMaterial#alphaMode} equals "mask". If the alpha is greater than or equal to this value then it is rendered as fully opaque, otherwise, it is rendered as fully transparent. A value greater than 1.0 will render the entire material as fully transparent. This value is ignored for other modes. - * - * Alpha is the combined result of the {@link SpecularMaterial#alpha} and {@link SpecularMaterial#alphaMap} properties. - * - * Default value is ````0.5````. - * - * @type {Number} - */ - set alphaCutoff(alphaCutoff) { - if (alphaCutoff === null || alphaCutoff === undefined) { - alphaCutoff = 0.5; - } - if (this._state.alphaCutoff === alphaCutoff) { - return; + _buildVertexShader() { + + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push ('#version 300 es'); + src.push("// Points instancing silhouette vertex shader"); + + src.push("uniform int renderPass;"); + + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - this._state.alphaCutoff = alphaCutoff; - } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); - /** - * Gets the alpha cutoff value. + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); - * @type {Number} - */ - get alphaCutoff() { - return this._state.alphaCutoff; - } + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - /** - * Sets whether backfaces are visible on attached {@link Mesh}es. - * - * The backfaces will belong to {@link ReadableGeometry} compoents that are also attached to the {@link Mesh}es. - * - * Default is ````false````. - * - * @type {Boolean} - */ - set backfaces(value) { - value = !!value; - if (this._state.backfaces === value) { - return; + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); } - this._state.backfaces = value; - this.glRedraw(); - } - /** - * Gets whether backfaces are visible on attached {@link Mesh}es. - * - * @type {Boolean} - */ - get backfaces() { - return this._state.backfaces; - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - /** - * Sets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. - * - * Default value is ````"ccw"````. - * - * @type {String} - */ - set frontface(value) { - value = value !== "cw"; - if (this._state.frontface === value) { - return; + src.push("uniform vec4 color;"); + + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); } - this._state.frontface = value; - this.glRedraw(); - } - /** - * Gets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. - * - * @type {String} - */ - get frontface() { - return this._state.frontface ? "ccw" : "cw"; - } + src.push("void main(void) {"); - /** - * Sets the SpecularMaterial's line width. - * - * This is not supported by WebGL implementations based on DirectX [2019]. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set lineWidth(value) { - this._state.lineWidth = value || 1.0; - this.glRedraw(); - } + // flags.y = NOT_RENDERED | SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED + // renderPass = SILHOUETTE_HIGHLIGHTED | SILHOUETTE_SELECTED | | SILHOUETTE_XRAYED - /** - * Gets the SpecularMaterial's line width. - * - * @type {Number} - */ - get lineWidth() { - return this._state.lineWidth; + src.push(`if (int(flags.y) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + + src.push("vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push("worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push("vec4 viewPosition = viewMatrix * worldPosition; "); + + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); + } + src.push("}"); + src.push("}"); + return src; } - /** - * Sets the SpecularMaterial's point size. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set pointSize(value) { - this._state.pointSize = value || 1; - this.glRedraw(); + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points instancing silhouette fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } + src.push("uniform vec4 color;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); + } + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("outColor = color;"); + src.push("}"); + return src; } - /** - * Sets the SpecularMaterial's point size. - * - * @type {Number} - */ - get pointSize() { - return this._state.pointSize; + webglContextRestored() { + this._program = null; } - /** - * Destroys this SpecularMaterial. - */ destroy() { - super.destroy(); - this._state.destroy(); + if (this._program) { + this._program.destroy(); + } + this._program = null; } } -function ensureImageSizePowerOfTwo$1(image) { - if (!isPowerOfTwo$1(image.width) || !isPowerOfTwo$1(image.height)) { - const canvas = document.createElement("canvas"); - canvas.width = nextHighestPowerOfTwo$1(image.width); - canvas.height = nextHighestPowerOfTwo$1(image.height); - const ctx = canvas.getContext("2d"); - ctx.drawImage(image, - 0, 0, image.width, image.height, - 0, 0, canvas.width, canvas.height); - image = canvas; - } - return image; -} +const tempVec3a$d = math.vec3(); -function isPowerOfTwo$1(x) { - return (x & (x - 1)) === 0; -} +/** + * @private + */ +class PointsInstancingPickMeshRenderer { -function nextHighestPowerOfTwo$1(x) { - --x; - for (let i = 1; i < 32; i <<= 1) { - x = x | x >> i; + constructor(scene) { + + this._scene = scene; + this._hash = this._getHash(); + + this._allocate(); } - return x + 1; -} -/** - * @desc A 2D texture map. - * - * * Textures are attached to {@link Material}s, which are attached to {@link Mesh}es. - * * To create a Texture from an image file, set {@link Texture#src} to the image file path. - * * To create a Texture from an HTMLImageElement, set the Texture's {@link Texture#image} to the HTMLImageElement. - * - * ## Usage - * - * In this example we have a Mesh with a {@link PhongMaterial} which applies diffuse {@link Texture}, and a {@link buildTorusGeometry} which builds a {@link ReadableGeometry}. - * - * Note that xeokit will ignore {@link PhongMaterial#diffuse} and {@link PhongMaterial#specular}, since we override those - * with {@link PhongMaterial#diffuseMap} and {@link PhongMaterial#specularMap}. The {@link Texture} pixel colors directly - * provide the diffuse and specular components for each fragment across the {@link ReadableGeometry} surface. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_Texture)] - * - * ```` javascript - * import {Viewer, Mesh, buildTorusGeometry, - * ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [0, 0, 5]; - * viewer.camera.look = [0, 0, 0]; - * viewer.camera.up = [0, 1, 0]; - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ - * center: [0, 0, 0], - * radius: 1.5, - * tube: 0.5, - * radialSegments: 32, - * tubeSegments: 24, - * arc: Math.PI * 2.0 - * }), - * material: new PhongMaterial(viewer.scene, { - * ambient: [0.9, 0.3, 0.9], - * shininess: 30, - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }) - * }) - * }); - *```` - */ -class Texture extends Component { + getValid() { + return this._hash === this._getHash(); + }; - /** - @private - */ - get type() { - return "Texture"; + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; } - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this Texture as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for this Texture, unique among all components in the parent scene, generated automatically when omitted. - * @param {String} [cfg.src=null] Path to image file to load into this Texture. See the {@link Texture#src} property for more info. - * @param {HTMLImageElement} [cfg.image=null] HTML Image object to load into this Texture. See the {@link Texture#image} property for more info. - * @param {Number} [cfg.minFilter=LinearMipmapLinearFilter] How the texture is sampled when a texel covers less than one pixel. - * Supported values are {@link LinearMipmapLinearFilter}, {@link LinearMipMapNearestFilter}, {@link NearestMipMapNearestFilter}, {@link NearestMipMapLinearFilter} and {@link LinearMipMapLinearFilter}. - * @param {Number} [cfg.magFilter=LinearFilter] How the texture is sampled when a texel covers more than one pixel. Supported values are {@link LinearFilter} and {@link NearestFilter}. - * @param {Number} [cfg.wrapS=RepeatWrapping] Wrap parameter for texture coordinate *S*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. - * @param {Number} [cfg.wrapT=RepeatWrapping] Wrap parameter for texture coordinate *T*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}.. - * @param {Boolean} [cfg.flipY=false] Flips this Texture's source data along its vertical axis when ````true````. - * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. - * @param {Number[]} [cfg.translate=[0,0]] 2D translation vector that will be added to texture's *S* and *T* coordinates. - * @param {Number[]} [cfg.scale=[1,1]] 2D scaling vector that will be applied to texture's *S* and *T* coordinates. - * @param {Number} [cfg.rotate=0] Rotation, in degrees, that will be applied to texture's *S* and *T* coordinates. - */ - constructor(owner, cfg = {}) { + drawLayer(frameCtx, instancingLayer, renderPass) { - super(owner, cfg); + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + const geometry = instancingLayer.geometry; - this._state = new RenderState({ - texture: new Texture2D({gl: this.scene.canvas.gl}), - matrix: math.identityMat4(), - hasMatrix: (cfg.translate && (cfg.translate[0] !== 0 || cfg.translate[1] !== 0)) || (!!cfg.rotate) || (cfg.scale && (cfg.scale[0] !== 0 || cfg.scale[1] !== 0)), - minFilter: this._checkMinFilter(cfg.minFilter), - magFilter: this._checkMagFilter(cfg.magFilter), - wrapS: this._checkWrapS(cfg.wrapS), - wrapT: this._checkWrapT(cfg.wrapT), - flipY: this._checkFlipY(cfg.flipY), - encoding: this._checkEncoding(cfg.encoding) - }); + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } + } - // Data source + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx); + } - this._src = null; - this._image = null; + gl.uniform1i(this._uRenderPass, renderPass); - // Transformation + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - this._translate = math.vec2([0, 0]); - this._scale = math.vec2([1, 1]); - this._rotate = math.vec2([0, 0]); + gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - this._matrixDirty = false; + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); - // Transform + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(camera.project.far + 1.0) / Math.LN2); // TODO: Far from pick project matrix? + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } - this.translate = cfg.translate; - this.scale = cfg.scale; - this.rotate = cfg.rotate; + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - // Data source + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - if (cfg.src) { - this.src = cfg.src; // Image file - } else if (cfg.image) { - this.image = cfg.image; // Image object - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - stats.memory.textures++; - } + this._aPickColor.bindArrayBuffer(state.pickColorsBuf); + gl.vertexAttribDivisor(this._aPickColor.location, 1); - _checkMinFilter(value) { - value = value || LinearMipMapLinearFilter; - if (value !== LinearFilter && - value !== LinearMipMapNearestFilter && - value !== LinearMipMapLinearFilter && - value !== NearestMipMapLinearFilter && - value !== NearestMipMapNearestFilter) { - this.error("Unsupported value for 'minFilter' - supported values are LinearFilter, LinearMipMapNearestFilter, NearestMipMapNearestFilter, " + - "NearestMipMapLinearFilter and LinearMipMapLinearFilter. Defaulting to LinearMipMapLinearFilter."); - value = LinearMipMapLinearFilter; - } - return value; - } + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - _checkMagFilter(value) { - value = value || LinearFilter; - if (value !== LinearFilter && value !== NearestFilter) { - this.error("Unsupported value for 'magFilter' - supported values are LinearFilter and NearestFilter. Defaulting to LinearFilter."); - value = LinearFilter; + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - return value; - } - _checkWrapS(value) { - value = value || RepeatWrapping; - if (value !== ClampToEdgeWrapping && value !== MirroredRepeatWrapping && value !== RepeatWrapping) { - this.error("Unsupported value for 'wrapS' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping."); - value = RepeatWrapping; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - return value; - } - _checkWrapT(value) { - value = value || RepeatWrapping; - if (value !== ClampToEdgeWrapping && value !== MirroredRepeatWrapping && value !== RepeatWrapping) { - this.error("Unsupported value for 'wrapT' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping."); - value = RepeatWrapping; + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); + + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$d); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } } - return value; - } - _checkFlipY(value) { - return !!value; - } + gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); - _checkEncoding(value) { - value = value || LinearEncoding; - if (value !== LinearEncoding && value !== sRGBEncoding) { - this.error("Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); - value = LinearEncoding; + // Cleanup + + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aPickColor.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); + + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - return value; - } - _webglContextRestored() { - this._state.texture = new Texture2D({gl: this.scene.canvas.gl}); - if (this._image) { - this.image = this._image; - } else if (this._src) { - this.src = this._src; + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } } - _update() { - const state = this._state; - if (this._matrixDirty) { - let matrix; - let t; - if (this._translate[0] !== 0 || this._translate[1] !== 0) { - matrix = math.translationMat4v([this._translate[0], this._translate[1], 0], this._state.matrix); - } - if (this._scale[0] !== 1 || this._scale[1] !== 1) { - t = math.scalingMat4v([this._scale[0], this._scale[1], 1]); - matrix = matrix ? math.mulMat4(matrix, t) : t; - } - if (this._rotate !== 0) { - t = math.rotationMat4v(this._rotate * 0.0174532925, [0, 0, 1]); - matrix = matrix ? math.mulMat4(matrix, t) : t; - } - if (matrix) { - state.matrix = matrix; - } - this._matrixDirty = false; + _allocate() { + + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; + + this._program = new Program(gl, this._buildShader()); + + if (this._program.errors) { + this.errors = this._program.errors; + return; } - this.glRedraw(); - } + const program = this._program; - /** - * Sets an HTML DOM Image object to source this Texture from. - * - * Sets {@link Texture#src} null. - * - * @type {HTMLImageElement} - */ - set image(value) { - this._image = ensureImageSizePowerOfTwo$1(value); - this._image.crossOrigin = "Anonymous"; - this._state.texture.setImage(this._image, this._state); - this._src = null; - this.glRedraw(); - } + this._uPickInvisible = program.getLocation("pickInvisible"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; - /** - * Gets HTML DOM Image object this Texture is sourced from, if any. - * - * Returns null if not set. - * - * @type {HTMLImageElement} - */ - get image() { - return this._image; - } + const clips = sectionPlanesState.sectionPlanes; - /** - * Sets path to an image file to source this Texture from. - * - * Sets {@link Texture#image} null. - * - * @type {String} - */ - set src(src) { - this.scene.loading++; - this.scene.canvas.spinner.processes++; - const self = this; - let image = new Image(); - image.onload = function () { - image = ensureImageSizePowerOfTwo$1(image); - self._state.texture.setImage(image, self._state); - self.scene.loading--; - self.glRedraw(); - self.scene.canvas.spinner.processes--; - }; - image.src = src; - this._src = src; - this._image = null; - } + for (let i = 0, len = clips.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } - /** - * Gets path to the image file this Texture from, if any. - * - * Returns null if not set. - * - * @type {String} - */ - get src() { - return this._src; - } + this._uRenderPass = program.getLocation("renderPass"); + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aPickColor = program.getAttribute("pickColor"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - /** - * Sets the 2D translation vector added to this Texture's *S* and *T* UV coordinates. - * - * Default value is ````[0, 0]````. - * - * @type {Number[]} - */ - set translate(value) { - this._translate.set(value || [0, 0]); - this._matrixDirty = true; - this._needUpdate(); - } + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - /** - * Gets the 2D translation vector added to this Texture's *S* and *T* UV coordinates. - * - * Default value is ````[0, 0]````. - * - * @type {Number[]} - */ - get translate() { - return this._translate; + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } } - /** - * Sets the 2D scaling vector that will be applied to this Texture's *S* and *T* UV coordinates. - * - * Default value is ````[1, 1]````. - * - * @type {Number[]} - */ - set scale(value) { - this._scale.set(value || [1, 1]); - this._matrixDirty = true; - this._needUpdate(); + _bindProgram(frameCtx) { + + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + + program.bind(); + + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); } - /** - * Gets the 2D scaling vector that will be applied to this Texture's *S* and *T* UV coordinates. - * - * Default value is ````[1, 1]````. - * - * @type {Number[]} - */ - get scale() { - return this._scale; + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - /** - * Sets the rotation angles, in degrees, that will be applied to this Texture's *S* and *T* UV coordinates. - * - * Default value is ````0````. - * - * @type {Number} - */ - set rotate(value) { - value = value || 0; - if (this._rotate === value) { - return; + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push ('#version 300 es'); + src.push("// Points instancing pick mesh vertex shader"); + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - this._rotate = value; - this._matrixDirty = true; - this._needUpdate(); - } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("in vec4 pickColor;"); - /** - * Gets the rotation angles, in degrees, that will be applied to this Texture's *S* and *T* UV coordinates. - * - * Default value is ````0````. - * - * @type {Number} - */ - get rotate() { - return this._rotate; - } + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); - /** - * Gets how this Texture is sampled when a texel covers less than one pixel. - * - * Options are: - * - * * NearestFilter - Uses the value of the texture element that is nearest - * (in Manhattan distance) to the center of the pixel being textured. - * - * * LinearFilter - Uses the weighted average of the four texture elements that are - * closest to the center of the pixel being textured. - * - * * NearestMipMapNearestFilter - Chooses the mipmap that most closely matches the - * size of the pixel being textured and uses the "nearest" criterion (the texture - * element nearest to the center of the pixel) to produce a texture value. - * - * * LinearMipMapNearestFilter - Chooses the mipmap that most closely matches the size of - * the pixel being textured and uses the "linear" criterion (a weighted average of the - * four texture elements that are closest to the center of the pixel) to produce a - * texture value. - * - * * NearestMipMapLinearFilter - Chooses the two mipmaps that most closely - * match the size of the pixel being textured and uses the "nearest" criterion - * (the texture element nearest to the center of the pixel) to produce a texture - * value from each mipmap. The final texture value is a weighted average of those two - * values. - * - * * LinearMipMapLinearFilter - (default) - Chooses the two mipmaps that most closely match the size - * of the pixel being textured and uses the "linear" criterion (a weighted average - * of the four texture elements that are closest to the center of the pixel) to - * produce a texture value from each mipmap. The final texture value is a weighted - * average of those two values. - * - * Default value is LinearMipMapLinearFilter. - * - * @type {Number} - */ - get minFilter() { - return this._state.minFilter; - } + src.push("uniform bool pickInvisible;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - /** - * Gets how this Texture is sampled when a texel covers more than one pixel. - * - * * NearestFilter - Uses the value of the texture element that is nearest - * (in Manhattan distance) to the center of the pixel being textured. - * * LinearFilter - (default) - Uses the weighted average of the four texture elements that are - * closest to the center of the pixel being textured. - * - * Default value is LinearMipMapLinearFilter. - * - * @type {Number} - */ - get magFilter() { - return this._state.magFilter; - } + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); + } - /** - * Gets the wrap parameter for this Texture's *S* coordinate. - * - * Values can be: - * - * * ClampToEdgeWrapping - causes *S* coordinates to be clamped to the size of the texture. - * * MirroredRepeatWrapping - causes the *S* coordinate to be set to the fractional part of the texture coordinate - * if the integer part of *S* is even; if the integer part of *S* is odd, then the *S* texture coordinate is - * set to *1 - frac ⁡ S* , where *frac ⁡ S* represents the fractional part of *S*. - * * RepeatWrapping - (default) - causes the integer part of the *S* coordinate to be ignored; xeokit uses only the - * fractional part, thereby creating a repeating pattern. - * - * Default value is RepeatWrapping. - * - * @type {Number} - */ - get wrapS() { - return this._state.wrapS; - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - /** - * Gets the wrap parameter for this Texture's *T* coordinate. - * - * Values can be: - * - * * ClampToEdgeWrapping - causes *S* coordinates to be clamped to the size of the texture. - * * MirroredRepeatWrapping - causes the *S* coordinate to be set to the fractional part of the texture coordinate - * if the integer part of *S* is even; if the integer part of *S* is odd, then the *S* texture coordinate is - * set to *1 - frac ⁡ S* , where *frac ⁡ S* represents the fractional part of *S*. - * * RepeatWrapping - (default) - causes the integer part of the *S* coordinate to be ignored; xeokit uses only the - * fractional part, thereby creating a repeating pattern. - * - * Default value is RepeatWrapping. - * - * @type {Number} - */ - get wrapT() { - return this._state.wrapT; + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } + src.push("out vec4 vPickColor;"); + src.push("void main(void) {"); + + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK + + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + + src.push("} else {"); + + + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + + src.push(" vPickColor = vec4(float(pickColor.r) / 255.0, float(pickColor.g) / 255.0, float(pickColor.b) / 255.0, float(pickColor.a) / 255.0);"); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); + } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); + } + src.push("}"); + src.push("}"); + return src; } - /** - * Gets if this Texture's source data is flipped along its vertical axis. - * - * @type {Number} - */ - get flipY() { - return this._state.flipY; + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points instancing pick mesh fragment shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } + src.push("in vec4 vPickColor;"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); + } + + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("outColor = vPickColor; "); + src.push("}"); + return src; } - /** - * Gets the Texture's encoding format. - * - * @type {Number} - */ - get encoding() { - return this._state.encoding; + webglContextRestored() { + this._program = null; } - /** - * Destroys this Texture - */ destroy() { - super.destroy(); - if (this._state.texture) { - this._state.texture.destroy(); + if (this._program) { + this._program.destroy(); } - this._state.destroy(); - stats.memory.textures--; + this._program = null; } } +const tempVec3a$c = math.vec3(); + /** * @private */ -class GLTFSceneGraphLoader { - - constructor(cfg) { // TODO: Loading options fallbacks on loader, eg. handleGLTFNode etc - } - - load(plugin, modelNode, src, options, ok, error) { - options = options || {}; - var spinner = modelNode.scene.canvas.spinner; - spinner.processes++; - loadGLTF$1(plugin, modelNode, src, options, function () { - spinner.processes--; - core.scheduleTask(function () { - modelNode.scene.fire("modelLoaded", modelNode.id); // FIXME: Assumes listeners know order of these two events - modelNode.fire("loaded", true, false); - }); - if (ok) { - ok(); - } - }, - function (msg) { - spinner.processes--; - modelNode.error(msg); - if (error) { - error(msg); - } - modelNode.fire("error", msg); - }); - } +class PointsInstancingPickDepthRenderer { - parse(plugin, modelNode, gltf, options, ok, error) { - options = options || {}; - var spinner = modelNode.scene.canvas.spinner; - spinner.processes++; - parseGLTF$2(plugin, gltf, "", options, modelNode, function () { - spinner.processes--; - modelNode.scene.fire("modelLoaded", modelNode.id); // FIXME: Assumes listeners know order of these two events - modelNode.fire("loaded", true, false); - if (ok) { - ok(); - } - }, - function (msg) { - spinner.processes--; - modelNode.error(msg); - modelNode.fire("error", msg); - if (error) { - error(msg); - } - }); + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); } -} - -var loadGLTF$1 = (function () { - return function (plugin, modelNode, src, options, ok, error) { - plugin.dataSource.getGLTF(src, function (json) { // OK - options.basePath = getBasePath(src); - parseGLTF$2(plugin, json, src, options, modelNode, ok, error); - }, - error); + getValid() { + return this._hash === this._getHash(); }; - function getBasePath(src) { - var i = src.lastIndexOf("/"); - return (i !== 0) ? src.substring(0, i + 1) : ""; + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; } -})(); - -var parseGLTF$2 = (function () { - const WEBGL_COMPONENT_TYPES = { - 5120: Int8Array, - 5121: Uint8Array, - 5122: Int16Array, - 5123: Uint16Array, - 5125: Uint32Array, - 5126: Float32Array - }; + drawLayer(frameCtx, instancingLayer, renderPass) { - const WEBGL_TYPE_SIZES = { - 'SCALAR': 1, - 'VEC2': 2, - 'VEC3': 3, - 'VEC4': 4, - 'MAT2': 4, - 'MAT3': 9, - 'MAT4': 16 - }; + const model = instancingLayer.model; + const scene = model.scene; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + const geometry = instancingLayer.geometry; - return function (plugin, json, src, options, modelNode, ok) { - modelNode.clear(); - var ctx = { - src: src, - loadBuffer: options.loadBuffer, - basePath: options.basePath, - prioritizeGLTFNode: options.prioritizeGLTFNode, - handleGLTFNode: options.handleGLTFNode, - ignoreMaterials: !!options.ignoreMaterials, - edgeThreshold: options.edgeThreshold, - readableGeometry: !!options.readableGeometry, - json: json, - scene: modelNode.scene, - plugin: plugin, - modelNode: modelNode, - modelNodeProps: { - visible: modelNode.visible, - culled: modelNode.culled, - xrayed: modelNode.xrayed, - highlighted: modelNode.highlighted, - selected: modelNode.selected, - outlined: modelNode.outlined, - clippable: modelNode.clippable, - pickable: modelNode.pickable, - collidable: modelNode.collidable, - castsShadow: modelNode.castsShadow, - receivesShadow: modelNode.receivesShadow, - colorize: modelNode.colorize, - opacity: modelNode.opacity, - edges: modelNode.edges + if (!this._program) { + this._allocate(instancingLayer); + if (this.errors) { + return; } - }; + } - modelNode.scene.loading++; // Disables (re)compilation + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - loadBuffers(ctx, function () { + const camera = scene.camera; - loadBufferViews(ctx); - loadAccessors(ctx); - loadTextures(ctx); - loadMaterials(ctx); - loadMeshes(ctx); - loadDefaultScene(ctx); + gl.uniform1i(this._uRenderPass, renderPass); - modelNode.scene.loading--; // Re-enables (re)compilation + gl.uniform1i(this._uPickInvisible, frameCtx.pickInvisible); - ok(); - }); - }; + const pickViewMatrix = frameCtx.pickViewMatrix || camera.viewMatrix; + const rtcPickViewMatrix = (origin) ? createRTCViewMat(pickViewMatrix, origin) : pickViewMatrix; - function loadBuffers(ctx, ok) { - var buffers = ctx.json.buffers; - if (buffers) { - var numToLoad = buffers.length; - for (var i = 0, len = buffers.length; i < len; i++) { - loadBuffer(ctx, buffers[i], function () { - if (--numToLoad === 0) { - ok(); - } - }, function (msg) { - ctx.plugin.error(msg); - if (--numToLoad === 0) { - ok(); - } - }); - } - } else { - ok(); - } - } + gl.uniformMatrix4fv(this._uViewMatrix, false, rtcPickViewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - function loadBuffer(ctx, bufferInfo, ok, err) { - var uri = bufferInfo.uri; - if (uri) { - ctx.plugin.dataSource.getArrayBuffer(ctx.src, uri, function (data) { - bufferInfo._buffer = data; - ok(); - }, - err); - } else { - err('gltf/handleBuffer missing uri in ' + JSON.stringify(bufferInfo)); + gl.uniformMatrix4fv(this._uProjMatrix, false, frameCtx.pickProjMatrix); + + gl.uniform1f(this._uPickZNear, frameCtx.pickZNear); + gl.uniform1f(this._uPickZFar, frameCtx.pickZFar); + + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(frameCtx.pickZFar + 1.0) / Math.LN2); // TODO: Far from pick project matrix + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); } - } - function loadBufferViews(ctx) { - var bufferViewsInfo = ctx.json.bufferViews; - if (bufferViewsInfo) { - for (var i = 0, len = bufferViewsInfo.length; i < len; i++) { - loadBufferView(ctx, bufferViewsInfo[i]); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$c); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } } } - } - function loadBufferView(ctx, bufferViewInfo) { + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - var buffer = ctx.json.buffers[bufferViewInfo.buffer]; + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - bufferViewInfo._typedArray = null; + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - var byteLength = bufferViewInfo.byteLength || 0; - var byteOffset = bufferViewInfo.byteOffset || 0; + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - bufferViewInfo._buffer = buffer._buffer.slice(byteOffset, byteOffset + byteLength); - } + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); - function loadAccessors(ctx) { - var accessorsInfo = ctx.json.accessors; - if (accessorsInfo) { - for (var i = 0, len = accessorsInfo.length; i < len; i++) { - loadAccessor(ctx, accessorsInfo[i]); - } + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - } - function loadAccessor(ctx, accessorInfo) { - var bufferViewInfo = ctx.json.bufferViews[accessorInfo.bufferView]; - var itemSize = WEBGL_TYPE_SIZES[accessorInfo.type]; - var TypedArray = WEBGL_COMPONENT_TYPES[accessorInfo.componentType]; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. - var elementBytes = TypedArray.BYTES_PER_ELEMENT; - var itemBytes = elementBytes * itemSize; + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - // The buffer is not interleaved if the stride is the item size in bytes. - if (accessorInfo.byteStride && accessorInfo.byteStride !== itemBytes) ; else { - accessorInfo._typedArray = new TypedArray(bufferViewInfo._buffer, accessorInfo.byteOffset || 0, accessorInfo.count * itemSize); - accessorInfo._itemSize = itemSize; - } - } + gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); + // Cleanup - function loadTextures(ctx) { - var texturesInfo = ctx.json.textures; - if (texturesInfo) { - for (var i = 0, len = texturesInfo.length; i < len; i++) { - loadTexture(ctx, texturesInfo[i]); - } - } - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); - function loadTexture(ctx, textureInfo) { - let uri = ctx.json.images[textureInfo.source].uri; - if (uri && !uri.match(/^data:(.*?)(;base64)?,(.*)$/)) { - uri = ctx.basePath + uri; + gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - textureInfo._texture = new Texture(ctx.modelNode, { - src: uri, - flipY: !!textureInfo.flipY, - //encoding: "sRGB" - encoding: "linear" - }); - } - function loadMaterials(ctx) { - var materialsInfo = ctx.json.materials; - if (materialsInfo) { - var materialInfo; - var material; - for (var i = 0, len = materialsInfo.length; i < len; i++) { - materialInfo = materialsInfo[i]; - material = loadMaterial(ctx, materialInfo); - materialInfo._material = material; - } + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } } - function loadMaterial(ctx, materialInfo) { + _allocate() { - var json = ctx.json; - var cfg = {}; - var textureInfo; + const scene = this._scene; + const gl = scene.canvas.gl; - // Common attributes + this._program = new Program(gl, this._buildShader()); - var normalTexture = materialInfo.normalTexture; - if (normalTexture) { - textureInfo = json.textures[normalTexture.index]; - if (textureInfo) { - cfg.normalMap = textureInfo._texture; - //cfg.normalMap.encoding = "linear"; - } + if (this._program.errors) { + this.errors = this._program.errors; + return; } - var occlusionTexture = materialInfo.occlusionTexture; - if (occlusionTexture) { - textureInfo = json.textures[occlusionTexture.index]; - if (textureInfo) { - cfg.occlusionMap = textureInfo._texture; - } - } + const program = this._program; - var emissiveTexture = materialInfo.emissiveTexture; - if (emissiveTexture) { - textureInfo = json.textures[emissiveTexture.index]; - if (textureInfo) { - cfg.emissiveMap = textureInfo._texture; - //cfg.emissiveMap.encoding = "sRGB"; - } - } + this._uRenderPass = program.getLocation("renderPass"); + this._uPickInvisible = program.getLocation("pickInvisible"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; - var emissiveFactor = materialInfo.emissiveFactor; - if (emissiveFactor) { - cfg.emissive = emissiveFactor; + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); } - cfg.backfaces = !!materialInfo.doubleSided; + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - var alphaMode = materialInfo.alphaMode; - switch (alphaMode) { - case "NORMAL_OPAQUE": - cfg.alphaMode = "opaque"; - break; - case "MASK": - cfg.alphaMode = "mask"; - break; - case "BLEND": - cfg.alphaMode = "blend"; - break; - } + this._uPickZNear = program.getLocation("pickZNear"); + this._uPickZFar = program.getLocation("pickZFar"); - var alphaCutoff = materialInfo.alphaCutoff; - if (alphaCutoff !== undefined) { - cfg.alphaCutoff = alphaCutoff; - } + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - var extensions = materialInfo.extensions; - if (extensions) { + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } + } - // Specular PBR material + _bindProgram() { + this._program.bind(); - var specularPBR = extensions["KHR_materials_pbrSpecularGlossiness"]; - if (specularPBR) { + } - var diffuseFactor = specularPBR.diffuseFactor; - if (diffuseFactor !== null && diffuseFactor !== undefined) { - cfg.diffuse = diffuseFactor.slice(0, 3); - cfg.alpha = diffuseFactor[3]; - } + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - var diffuseTexture = specularPBR.diffuseTexture; - if (diffuseTexture) { - textureInfo = json.textures[diffuseTexture.index]; - if (textureInfo) { - cfg.diffuseMap = textureInfo._texture; - //cfg.diffuseMap.encoding = "sRGB"; - } - } + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; - var specularFactor = specularPBR.specularFactor; - if (specularFactor !== null && specularFactor !== undefined) { - cfg.specular = specularFactor.slice(0, 3); - } + src.push ('#version 300 es'); + src.push("// Points instancing pick depth vertex shader"); - var glossinessFactor = specularPBR.glossinessFactor; - if (glossinessFactor !== null && glossinessFactor !== undefined) { - cfg.glossiness = glossinessFactor; - } + src.push("uniform int renderPass;"); - var specularGlossinessTexture = specularPBR.specularGlossinessTexture; - if (specularGlossinessTexture) { - textureInfo = json.textures[specularGlossinessTexture.index]; - if (textureInfo) { - cfg.specularGlossinessMap = textureInfo._texture; - //cfg.specularGlossinessMap.encoding = "linear"; - } - } + src.push("in vec3 position;"); - return new SpecularMaterial(ctx.modelNode, cfg); - } + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } - // Common Phong, Blinn, Lambert or Constant materials + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); - var common = extensions["KHR_materials_common"]; - if (common) { + src.push("uniform bool pickInvisible;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - var technique = common.technique; - var values = common.values || {}; + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); + } - var blinn = technique === "BLINN"; - var phong = technique === "PHONG"; - var lambert = technique === "LAMBERT"; + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } - var shininess = values.shininess; - if ((blinn || phong) && shininess !== null && shininess !== undefined) { - cfg.shininess = shininess; - } else { - cfg.shininess = 0; - } - var texture; - var diffuse = values.diffuse; - if (diffuse && (blinn || phong || lambert)) { - if (utils.isString(diffuse)) { - texture = json.textures[diffuse]; - if (texture) { - cfg.diffuseMap = texture; - // cfg.diffuseMap.encoding = "sRGB"; - } - } else { - cfg.diffuse = diffuse.slice(0, 3); - } - } else { - cfg.diffuse = [0, 0, 0]; - } + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } - var specular = values.specular; - if (specular && (blinn || phong)) { - if (utils.isString(specular)) { - texture = json.textures[specular]; - if (texture) { - cfg.specularMap = texture; - } - } else { - cfg.specular = specular.slice(0, 3); - } - } else { - cfg.specular = [0, 0, 0]; - } + src.push("out vec4 vViewPosition;"); + src.push("void main(void) {"); - var emission = values.emission; - if (emission) { - if (utils.isString(emission)) { - texture = json.textures[emission]; - if (texture) { - cfg.emissiveMap = texture; - } - } else { - cfg.emissive = emission.slice(0, 3); - } - } else { - cfg.emissive = [0, 0, 0]; - } + // flags.w = NOT_RENDERED | PICK + // renderPass = PICK - var transparency = values.transparency; - if (transparency !== null && transparency !== undefined) { - cfg.alpha = transparency; - } else { - cfg.alpha = 1.0; - } + src.push(`if (int(flags.w) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - values.transparent; + src.push("} else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); - return new PhongMaterial(ctx.scene, cfg); - } + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + src.push(" vFlags2 = flags2;"); + } + src.push(" vViewPosition = viewPosition;"); + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); } + src.push("}"); + src.push("}"); + return src; + } - // Metallic PBR naterial + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points instancing pick depth fragment shader"); - var metallicPBR = materialInfo.pbrMetallicRoughness; - if (metallicPBR) { + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); - var baseColorFactor = metallicPBR.baseColorFactor; - if (baseColorFactor) { - cfg.baseColor = baseColorFactor.slice(0, 3); - cfg.alpha = baseColorFactor[3]; - } + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } - var colorTexture = metallicPBR.colorTexture; - if (colorTexture) { - textureInfo = json.textures[colorTexture.index]; - if (textureInfo) { - cfg.baseColorMap = textureInfo._texture; - //cfg.baseColorMap.encoding = "sRGB"; - } - } + src.push("uniform float pickZNear;"); + src.push("uniform float pickZFar;"); - var metallicFactor = metallicPBR.metallicFactor; - if (metallicFactor !== null && metallicFactor !== undefined) { - cfg.metallic = metallicFactor; + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); } + } + src.push("in vec4 vViewPosition;"); + src.push("vec4 packDepth(const in float depth) {"); + src.push(" const vec4 bitShift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);"); + src.push(" const vec4 bitMask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);"); + src.push(" vec4 res = fract(depth * bitShift);"); + src.push(" res -= res.xxyz * bitMask;"); + src.push(" return res;"); + src.push("}"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); - var roughnessFactor = metallicPBR.roughnessFactor; - if (roughnessFactor !== null && roughnessFactor !== undefined) { - cfg.roughness = roughnessFactor; - } + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); + } - var metallicRoughnessTexture = metallicPBR.metallicRoughnessTexture; - if (metallicRoughnessTexture) { - textureInfo = json.textures[metallicRoughnessTexture.index]; - if (textureInfo) { - cfg.metallicRoughnessMap = textureInfo._texture; - // cfg.metallicRoughnessMap.encoding = "linear"; - } + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } - - return new MetallicMaterial(ctx.scene, cfg); + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" float zNormalizedDepth = abs((pickZNear + vViewPosition.z) / (pickZFar - pickZNear));"); + src.push(" outColor = packDepth(zNormalizedDepth); "); // Must be linear depth + src.push("}"); + return src; + } - // Default material - - return new PhongMaterial(ctx.scene, cfg); + webglContextRestored() { + this._program = null; } - function loadMeshes(ctx) { - var meshes = ctx.json.meshes; - if (meshes) { - for (var i = 0, len = meshes.length; i < len; i++) { - loadMesh(ctx, meshes[i]); - } + destroy() { + if (this._program) { + this._program.destroy(); } + this._program = null; } +} - function loadMesh(ctx, meshInfo) { - var json = ctx.json; - var mesh = []; - var primitivesInfo = meshInfo.primitives; - var materialIndex; - var materialInfo; - var accessorInfo; - var attributes; - - if (primitivesInfo) { - - var primitiveInfo; - var indicesIndex; - var positionsIndex; - var normalsIndex; - var uv0Index; - var geometryCfg; - var meshCfg; - var geometry; - - for (var i = 0, len = primitivesInfo.length; i < len; i++) { - primitiveInfo = primitivesInfo[i]; - if (primitiveInfo.mode < 4 ) { - continue; - } - geometryCfg = { - primitive: "triangles", - compressGeometry: true, - edgeThreshold: ctx.edgeThreshold - }; - - indicesIndex = primitiveInfo.indices; - - if (indicesIndex !== null && indicesIndex !== undefined) { - accessorInfo = json.accessors[indicesIndex]; - geometryCfg.indices = accessorInfo._typedArray; - } +const tempVec3a$b = math.vec3(); - attributes = primitiveInfo.attributes; - if (!attributes) { - continue; - } +/** + * @private + */ +class PointsInstancingOcclusionRenderer { - positionsIndex = attributes.POSITION; + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } - if (positionsIndex !== null && positionsIndex !== undefined) { - accessorInfo = json.accessors[positionsIndex]; - geometryCfg.positions = accessorInfo._typedArray; - } + getValid() { + return this._hash === this._getHash(); + }; - normalsIndex = attributes.NORMAL; + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + } - if (normalsIndex !== null && normalsIndex !== undefined) { - accessorInfo = json.accessors[normalsIndex]; - geometryCfg.normals = accessorInfo._typedArray; - } + drawLayer(frameCtx, instancingLayer, renderPass) { - uv0Index = attributes.TEXCOORD_0; + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + const geometry = instancingLayer.geometry; - if (uv0Index !== null && uv0Index !== undefined) { - accessorInfo = json.accessors[uv0Index]; - geometryCfg.uv = accessorInfo._typedArray; - } + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } + } - meshCfg = {}; + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - if (ctx.readableGeometry) { - geometry = new ReadableGeometry(ctx.modelNode, geometryCfg); - } else { - geometry = new VBOGeometry(ctx.modelNode, geometryCfg); - } + gl.uniform1i(this._uRenderPass, renderPass); - meshCfg.geometry = geometry; + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); - materialIndex = primitiveInfo.material; - if (materialIndex !== null && materialIndex !== undefined) { - materialInfo = json.materials[materialIndex]; - if (materialInfo) { - meshCfg.material = materialInfo._material; + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$b); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); } } - - mesh.push(meshCfg); } } - meshInfo._mesh = mesh; - } - function loadDefaultScene(ctx) { - var json = ctx.json; - var scene = json.scene || 0; - var defaultSceneInfo = json.scenes[scene]; - if (!defaultSceneInfo) { - error(ctx, "glTF has no default scene"); - return; - } - loadScene(ctx, defaultSceneInfo); - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - function loadScene(ctx, sceneInfo) { - var nodes = sceneInfo.nodes; - if (!nodes) { - return; - } - var json = ctx.json; - var glTFNode; - for (var i = 0, len = nodes.length; i < len; i++) { - glTFNode = json.nodes[nodes[i]]; - if (!glTFNode) { - error(ctx, "Node not found: " + i); - continue; - } - loadNode(ctx, glTFNode, null, null); - } - } + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - function loadNode(ctx, glTFNode, matrix, parent) { + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - parent = parent || ctx.modelNode; + if (this._aColor) { + this._aColor.bindArrayBuffer(geometry.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); + } - var createEntity; + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - if (ctx.prioritizeGLTFNode) { - const priority = ctx.prioritizeGLTFNode(ctx.modelNode.id, glTFNode); - if (priority === undefined || priority === null) { - return; - } + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); } - if (ctx.handleGLTFNode) { - var actions = {}; - if (!ctx.handleGLTFNode(ctx.modelNode.id, glTFNode, actions)) { - return; - } - if (actions.createEntity) { - createEntity = actions.createEntity; - } + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); + + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); } - const json = ctx.json; - const modelNode = ctx.modelNode; - const hasChildNodes = glTFNode.children && glTFNode.children.length > 0; + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); - var localMatrix; + gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); - if (glTFNode.matrix) { - localMatrix = glTFNode.matrix; - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, math.mat4()); - } else { - matrix = localMatrix; - } - } + // Cleanup - if (glTFNode.translation) { - localMatrix = math.translationMat4v(glTFNode.translation); - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, localMatrix); - } else { - matrix = localMatrix; - } + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + if (this._aColor) { + gl.vertexAttribDivisor(this._aColor.location, 0); } - - if (glTFNode.rotation) { - localMatrix = math.quaternionToMat4(glTFNode.rotation); - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, localMatrix); - } else { - matrix = localMatrix; - } + gl.vertexAttribDivisor(this._aFlags.location, 0); + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); } - - if (glTFNode.scale) { - localMatrix = math.scalingMat4v(glTFNode.scale); - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, localMatrix); - } else { - matrix = localMatrix; - } + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); } + } - if (glTFNode.mesh !== undefined) { + _allocate() { - var meshInfo = json.meshes[glTFNode.mesh]; + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; - if (meshInfo) { + this._program = new Program(gl, this._buildShader()); - var meshesInfo = meshInfo._mesh; - var meshesInfoMesh; - var mesh; - var numMeshes = meshesInfo.length; + if (this._program.errors) { + this.errors = this._program.errors; + return; + } - if (!createEntity && numMeshes > 0 && !hasChildNodes) { + const program = this._program; - // Case 1: Not creating object, node has meshes, node has no child nodes + this._uRenderPass = program.getLocation("renderPass"); + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); + this._uSectionPlanes = []; - for (var i = 0, len = numMeshes; i < len; i++) { - meshesInfoMesh = meshesInfo[i]; - let meshCfg = { - geometry: meshesInfoMesh.geometry, - matrix: matrix - }; - utils.apply(ctx.modelNodeProps, meshCfg); - meshCfg.material = meshesInfoMesh.material; - mesh = new Mesh(modelNode, meshCfg); - parent.addChild(mesh, false); // Don't automatically inherit properties - } - return; - } + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } - if (createEntity && numMeshes === 1 && !hasChildNodes) { + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); - // Case 2: Creating object, node has one mesh, node has no child nodes + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - meshesInfoMesh = meshesInfo[0]; - let meshCfg = { - geometry: meshesInfoMesh.geometry, - matrix: matrix - }; - utils.apply(ctx.modelNodeProps, meshCfg); - meshCfg.material = meshesInfoMesh.material; - utils.apply(createEntity, meshCfg); - mesh = new Mesh(modelNode, meshCfg); - parent.addChild(mesh, false); // Don't automatically inherit properties - return; - } + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - if (createEntity && numMeshes > 0 && !hasChildNodes) { + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } + } - // Case 3: Creating object, node has meshes, node has no child nodes + _bindProgram() { - let nodeCfg = { - matrix: matrix - }; - utils.apply(ctx.modelNodeProps, nodeCfg); - utils.apply(createEntity, nodeCfg); - let childNode = new Node$1(modelNode, nodeCfg); - parent.addChild(childNode, false); - for (let i = 0, len = numMeshes; i < len; i++) { - meshesInfoMesh = meshesInfo[i]; - let meshCfg = { - geometry: meshesInfoMesh.geometry - }; - utils.apply(ctx.modelNodeProps, meshCfg); - meshCfg.material = meshesInfoMesh.material; - utils.apply(createEntity, meshCfg); - meshCfg.id = null; // Avoid ID clash with parent Node - mesh = new Mesh(modelNode, meshCfg); - childNode.addChild(mesh, false); - } - return; - } + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; - if (!createEntity && numMeshes > 0 && hasChildNodes) { + this._program.bind(); - // Case 4: Not creating object, node has meshes, node has child nodes + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - let nodeCfg = { - matrix: matrix - }; - utils.apply(ctx.modelNodeProps, nodeCfg); - let childNode = new Node$1(modelNode, nodeCfg); - parent.addChild(childNode, false); - for (let i = 0, len = numMeshes; i < len; i++) { - meshesInfoMesh = meshesInfo[i]; - let meshCfg = { - geometry: meshesInfoMesh.geometry - }; - utils.apply(nodeCfg, meshCfg); - meshCfg.id = null; // Avoid ID clash with parent Node - meshCfg.matrix = null; // Node has matrix - meshCfg.material = meshesInfoMesh.material; - mesh = new Mesh(modelNode, meshCfg); - childNode.addChild(mesh, false); - } - matrix = null; - parent = childNode; - } + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } + } - if (createEntity && numMeshes === 0 && hasChildNodes) { + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - // Case 5: Creating explicit object, node has meshes OR node has child nodes + _buildVertexShader() { - let nodeCfg = { - matrix: matrix - }; - utils.apply(ctx.modelNodeProps, nodeCfg); - utils.apply(createEntity, nodeCfg); - createEntity.matrix = matrix; - let childNode = new Node$1(modelNode, nodeCfg); - parent.addChild(childNode, false); // Don't automatically inherit properties - matrix = null; - parent = childNode; - } + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; - if (createEntity && numMeshes > 0 || hasChildNodes) { + src.push ('#version 300 es'); + src.push("// Points instancing occlusion vertex shader"); - // Case 6: Creating explicit object, node has meshes OR node has child nodes + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); - let nodeCfg = { - matrix: matrix - }; - utils.apply(ctx.modelNodeProps, nodeCfg); - if (createEntity) { - utils.apply(createEntity, nodeCfg); - } - let childNode = new Node$1(modelNode, nodeCfg); - parent.addChild(childNode, false); // Don't automatically inherit properties - for (let i = 0, len = numMeshes; i < len; i++) { - meshesInfoMesh = meshesInfo[i]; - let meshCfg = { - geometry: meshesInfoMesh.geometry - }; - utils.apply(ctx.modelProps, meshCfg); - meshCfg.material = meshesInfoMesh.material; - if (createEntity) { - utils.apply(createEntity, meshCfg); - } - meshCfg.id = null; // Avoid ID clash with parent Node - mesh = new Mesh(modelNode, meshCfg); - childNode.addChild(mesh, false); // Don't automatically inherit properties - } - matrix = null; - parent = childNode; - } - } + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); } - if (glTFNode.children) { - var children = glTFNode.children; - var childNodeInfo; - var childNodeIdx; - for (let i = 0, len = children.length; i < len; i++) { - childNodeIdx = children[i]; - childNodeInfo = json.nodes[childNodeIdx]; - if (!childNodeInfo) { - error(ctx, "Node not found: " + i); - continue; - } - loadNode(ctx, childNodeInfo, matrix, parent); + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + + src.push("in vec4 modelMatrixCol0;"); // Modeling matrix + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); + } + + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } + + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } + src.push("void main(void) {"); + + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE + + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); + + src.push("} else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); + + if (clipping) { + src.push(" vWorldPosition = worldPosition;"); + } + + src.push("vec4 clipPos = projMatrix * viewPosition;"); + + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); + } + src.push("}"); + src.push("}"); + return src; + } + + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Points instancing occlusion vertex shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); + } + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0; i < sectionPlanesState.sectionPlanes.length; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } + src.push(" outColor = vec4(0.0, 0.0, 1.0, 1.0); "); // Occluders are blue + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); } + src.push("}"); + return src; } - function error(ctx, msg) { - ctx.plugin.error(msg); + webglContextRestored() { + this._program = null; } -})(); -function assert$5(condition, message) { - if (!condition) { - throw new Error(message || 'loader assertion failed.'); - } + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; + } } -const isBrowser$4 = Boolean(typeof process !== 'object' || String(process) !== '[object process]' || process.browser); -const matches$1 = typeof process !== 'undefined' && process.version && /v([0-9]*)/.exec(process.version); -matches$1 && parseFloat(matches$1[1]) || 0; - -const VERSION$9 = "3.1.8" ; +const tempVec3a$a = math.vec3(); -function assert$4(condition, message) { - if (!condition) { - throw new Error(message || 'loaders.gl assertion failed.'); - } -} +/** + * @private + */ +class PointsInstancingDepthRenderer { -const globals$2 = { - self: typeof self !== 'undefined' && self, - window: typeof window !== 'undefined' && window, - global: typeof global !== 'undefined' && global, - document: typeof document !== 'undefined' && document -}; -const global_ = globals$2.global || globals$2.self || globals$2.window || {}; -const isBrowser$3 = typeof process !== 'object' || String(process) !== '[object process]' || process.browser; -const isWorker = typeof importScripts === 'function'; -const isMobile = typeof window !== 'undefined' && typeof window.orientation !== 'undefined'; -const matches = typeof process !== 'undefined' && process.version && /v([0-9]*)/.exec(process.version); -matches && parseFloat(matches[1]) || 0; + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._allocate(); + } -function _defineProperty(obj, key, value) { - if (key in obj) { - Object.defineProperty(obj, key, { - value: value, - enumerable: true, - configurable: true, - writable: true - }); - } else { - obj[key] = value; - } + getValid() { + return this._hash === this._getHash(); + }; - return obj; -} + _getHash() { + return this._scene._sectionPlanesState.getHash() + this._scene.pointsMaterial.hash; + } -class WorkerJob { - constructor(jobName, workerThread) { - _defineProperty(this, "name", void 0); + drawLayer(frameCtx, instancingLayer, renderPass) { - _defineProperty(this, "workerThread", void 0); + const model = instancingLayer.model; + const scene = model.scene; + const camera = scene.camera; + const gl = scene.canvas.gl; + const state = instancingLayer._state; + const origin = instancingLayer._state.origin; + const pointsMaterial = scene.pointsMaterial._state; + const geometry = instancingLayer.geometry; - _defineProperty(this, "isRunning", void 0); + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } + } - _defineProperty(this, "result", void 0); + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(); + } - _defineProperty(this, "_resolve", void 0); + gl.uniform1i(this._uRenderPass, renderPass); - _defineProperty(this, "_reject", void 0); + gl.uniformMatrix4fv(this._uWorldMatrix, false, model.worldMatrix); + gl.uniformMatrix4fv(this._uViewMatrix, false, (origin) ? createRTCViewMat(camera.viewMatrix, origin) : camera.viewMatrix); - this.name = jobName; - this.workerThread = workerThread; - this.isRunning = true; + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$a); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } + } - this._resolve = () => {}; + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - this._reject = () => {}; + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - this.result = new Promise((resolve, reject) => { - this._resolve = resolve; - this._reject = reject; - }); - } + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - postMessage(type, payload) { - this.workerThread.postMessage({ - source: 'loaders.gl', - type, - payload - }); - } + this._aPosition.bindArrayBuffer(geometry.positionsBuf); - done(value) { - assert$4(this.isRunning); - this.isRunning = false; + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - this._resolve(value); - } + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); - error(error) { - assert$4(this.isRunning); - this.isRunning = false; + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } - this._reject(error); - } + gl.uniform1f(this._uPointSize, pointsMaterial.pointSize); + const nearPlaneHeight = (scene.camera.projection === "ortho") ? 1.0 : (gl.drawingBufferHeight / (2 * Math.tan(0.5 * scene.camera.perspective.fov * Math.PI / 180.0))); + gl.uniform1f(this._uNearPlaneHeight, nearPlaneHeight); -} + gl.drawArraysInstanced(gl.POINTS, 0, geometry.positionsBuf.numItems, state.numInstances); -const workerURLCache = new Map(); -function getLoadableWorkerURL(props) { - assert$4(props.source && !props.url || !props.source && props.url); - let workerURL = workerURLCache.get(props.source || props.url); + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); - if (!workerURL) { - if (props.url) { - workerURL = getLoadableWorkerURLFromURL(props.url); - workerURLCache.set(props.url, workerURL); - } + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); + } - if (props.source) { - workerURL = getLoadableWorkerURLFromSource(props.source); - workerURLCache.set(props.source, workerURL); + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } } - } - assert$4(workerURL); - return workerURL; -} + _allocate() { -function getLoadableWorkerURLFromURL(url) { - if (!url.startsWith('http')) { - return url; - } + const scene = this._scene; + const gl = scene.canvas.gl; - const workerSource = buildScriptSource(url); - return getLoadableWorkerURLFromSource(workerSource); -} + this._program = new Program(gl, this._buildShader()); -function getLoadableWorkerURLFromSource(workerSource) { - const blob = new Blob([workerSource], { - type: 'application/javascript' - }); - return URL.createObjectURL(blob); -} + if (this._program.errors) { + this.errors = this._program.errors; + return; + } -function buildScriptSource(workerUrl) { - return "try {\n importScripts('".concat(workerUrl, "');\n} catch (error) {\n console.error(error);\n throw error;\n}"); -} + const program = this._program; -function getTransferList(object, recursive = true, transfers) { - const transfersSet = transfers || new Set(); + this._uRenderPass = program.getLocation("renderPass"); - if (!object) ; else if (isTransferable(object)) { - transfersSet.add(object); - } else if (isTransferable(object.buffer)) { - transfersSet.add(object.buffer); - } else if (ArrayBuffer.isView(object)) ; else if (recursive && typeof object === 'object') { - for (const key in object) { - getTransferList(object[key], recursive, transfersSet); - } - } + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uWorldMatrix = program.getLocation("worldMatrix"); + this._uViewMatrix = program.getLocation("viewMatrix"); + this._uProjMatrix = program.getLocation("projMatrix"); - return transfers === undefined ? Array.from(transfersSet) : []; -} + this._uSectionPlanes = []; -function isTransferable(object) { - if (!object) { - return false; - } + for (let i = 0, len = scene._sectionPlanesState.sectionPlanes.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } - if (object instanceof ArrayBuffer) { - return true; - } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); - if (typeof MessagePort !== 'undefined' && object instanceof MessagePort) { - return true; - } + this._uPointSize = program.getLocation("pointSize"); + this._uNearPlaneHeight = program.getLocation("nearPlaneHeight"); - if (typeof ImageBitmap !== 'undefined' && object instanceof ImageBitmap) { - return true; - } + if (scene.logarithmicDepthBufferEnabled) { + this._uLogDepthBufFC = program.getLocation("logDepthBufFC"); + } + } - if (typeof OffscreenCanvas !== 'undefined' && object instanceof OffscreenCanvas) { - return true; - } + _bindProgram() { - return false; -} + const scene = this._scene; + const gl = scene.canvas.gl; + const project = scene.camera.project; -const NOOP = () => {}; + this._program.bind(); -class WorkerThread { - static isSupported() { - return typeof Worker !== 'undefined'; - } + gl.uniformMatrix4fv(this._uProjMatrix, false, project.matrix); - constructor(props) { - _defineProperty(this, "name", void 0); + if (scene.logarithmicDepthBufferEnabled) { + const logDepthBufFC = 2.0 / (Math.log(project.far + 1.0) / Math.LN2); + gl.uniform1f(this._uLogDepthBufFC, logDepthBufFC); + } + } - _defineProperty(this, "source", void 0); + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; + } - _defineProperty(this, "url", void 0); + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const pointsMaterial = scene.pointsMaterial._state; + const src = []; + src.push('#version 300 es'); + src.push("// Points instancing depth vertex shader"); + src.push("uniform int renderPass;"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("in vec4 modelMatrixCol0;"); + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + src.push("uniform mat4 worldMatrix;"); + src.push("uniform mat4 viewMatrix;"); + src.push("uniform mat4 projMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); - _defineProperty(this, "terminated", false); + src.push("uniform float pointSize;"); + if (pointsMaterial.perspectivePoints) { + src.push("uniform float nearPlaneHeight;"); + } - _defineProperty(this, "worker", void 0); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("out float vFragDepth;"); + } + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } + src.push("void main(void) {"); - _defineProperty(this, "onMessage", void 0); + // flags.x = NOT_RENDERED | COLOR_OPAQUE | COLOR_TRANSPARENT + // renderPass = COLOR_OPAQUE - _defineProperty(this, "onError", void 0); + src.push(`if (int(flags.x) != renderPass) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex - _defineProperty(this, "_loadableURL", ''); + src.push("} else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = worldMatrix * vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push(" vec4 viewPosition = viewMatrix * worldPosition; "); - const { - name, - source, - url - } = props; - assert$4(source || url); - this.name = name; - this.source = source; - this.url = url; - this.onMessage = NOOP; + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } + src.push("vec4 clipPos = projMatrix * viewPosition;"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("vFragDepth = 1.0 + clipPos.w;"); + } + src.push("gl_Position = clipPos;"); + if (pointsMaterial.perspectivePoints) { + src.push("gl_PointSize = (nearPlaneHeight * pointSize) / clipPos.w;"); + src.push("gl_PointSize = max(gl_PointSize, " + Math.floor(pointsMaterial.minPerspectivePointSize) + ".0);"); + src.push("gl_PointSize = min(gl_PointSize, " + Math.floor(pointsMaterial.maxPerspectivePointSize) + ".0);"); + } else { + src.push("gl_PointSize = pointSize;"); + } + src.push("}"); + src.push("}"); + return src; + } - this.onError = error => console.log(error); + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + let i; + let len; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push('#version 300 es'); + src.push("// Points instancing depth vertex shader"); + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } - this.worker = this._createBrowserWorker(); - } + src.push("const float packUpScale = 256. / 255.;"); + src.push("const float unpackDownscale = 255. / 256.;"); + src.push("const vec3 packFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );"); + src.push("const vec4 unpackFactors = unpackDownscale / vec4( packFactors, 1. );"); + src.push("const float shiftRight8 = 1.0 / 256.;"); - destroy() { - this.onMessage = NOOP; - this.onError = NOOP; - this.worker.terminate(); - this.terminated = true; - } + src.push("vec4 packDepthToRGBA( const in float v ) {"); + src.push(" vec4 r = vec4( fract( v * packFactors ), v );"); + src.push(" r.yzw -= r.xyz * shiftRight8;"); + src.push(" return r * packUpScale;"); + src.push("}"); - get isRunning() { - return Boolean(this.onMessage); - } + src.push("out vec4 outColor;"); + src.push("void main(void) {"); - postMessage(data, transferList) { - transferList = transferList || getTransferList(data); - this.worker.postMessage(data, transferList); - } + if (scene.pointsMaterial.roundPoints) { + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); + } - _getErrorFromErrorEvent(event) { - let message = 'Failed to load '; - message += "worker ".concat(this.name, " from ").concat(this.url, ". "); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } + src.push(" outColor = packDepthToRGBA( gl_FragCoord.z); "); // Must be linear depth + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push("}"); + return src; + } - if (event.message) { - message += "".concat(event.message, " in "); + webglContextRestored() { + this._program = null; } - if (event.lineno) { - message += ":".concat(event.lineno, ":").concat(event.colno); + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; } +} - return new Error(message); - } +const tempVec3a$9 = math.vec3(); - _createBrowserWorker() { - this._loadableURL = getLoadableWorkerURL({ - source: this.source, - url: this.url - }); - const worker = new Worker(this._loadableURL, { - name: this.name - }); +/** + * Renders InstancingLayer fragment depths to a shadow map. + * + * @private + */ +class PointsInstancingShadowRenderer { - worker.onmessage = event => { - if (!event.data) { - this.onError(new Error('No data received')); - } else { - this.onMessage(event.data); - } - }; + constructor(scene) { + this._scene = scene; + this._hash = this._getHash(); + this._lastLightId = null; + this._allocate(); + } - worker.onerror = error => { - this.onError(this._getErrorFromErrorEvent(error)); - this.terminated = true; + getValid() { + return this._hash === this._getHash(); }; - worker.onmessageerror = event => console.error(event); + _getHash() { + return this._scene._sectionPlanesState.getHash(); + } - return worker; - } + drawLayer( frameCtx, instancingLayer) { -} + const model = instancingLayer.model; + const scene = model.scene; + const gl = scene.canvas.gl; + const state = instancingLayer._state; -class WorkerPool { - constructor(props) { - _defineProperty(this, "name", 'unnamed'); + if (!this._program) { + this._allocate(); + if (this.errors) { + return; + } + } - _defineProperty(this, "source", void 0); + if (frameCtx.lastProgramId !== this._program.id) { + frameCtx.lastProgramId = this._program.id; + this._bindProgram(frameCtx, instancingLayer); + } - _defineProperty(this, "url", void 0); + gl.uniformMatrix4fv(this._uPositionsDecodeMatrix, false, geometry.positionsDecodeMatrix); - _defineProperty(this, "maxConcurrency", 1); + this._aModelMatrixCol0.bindArrayBuffer(state.modelMatrixCol0Buf); + this._aModelMatrixCol1.bindArrayBuffer(state.modelMatrixCol1Buf); + this._aModelMatrixCol2.bindArrayBuffer(state.modelMatrixCol2Buf); - _defineProperty(this, "maxMobileConcurrency", 1); + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 1); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 1); - _defineProperty(this, "onDebug", () => {}); + this._aPosition.bindArrayBuffer(state.positionsBuf); - _defineProperty(this, "reuseWorkers", true); + if (this._aOffset) { + this._aOffset.bindArrayBuffer(state.offsetsBuf); + gl.vertexAttribDivisor(this._aOffset.location, 1); + } - _defineProperty(this, "props", {}); + this._aColor.bindArrayBuffer(state.colorsBuf); + gl.vertexAttribDivisor(this._aColor.location, 1); - _defineProperty(this, "jobQueue", []); + this._aFlags.bindArrayBuffer(state.flagsBuf); + gl.vertexAttribDivisor(this._aFlags.location, 1); - _defineProperty(this, "idleQueue", []); + if (this._aFlags2) { + this._aFlags2.bindArrayBuffer(state.flags2Buf); + gl.vertexAttribDivisor(this._aFlags2.location, 1); + } - _defineProperty(this, "count", 0); + // TODO: Section planes need to be set if RTC center has changed since last RTC center recorded on frameCtx - _defineProperty(this, "isDestroyed", false); + const numSectionPlanes = scene._sectionPlanesState.sectionPlanes.length; + if (numSectionPlanes > 0) { + const sectionPlanes = scene._sectionPlanesState.sectionPlanes; + const baseIndex = instancingLayer.layerIndex * numSectionPlanes; + const renderFlags = model.renderFlags; + const origin = instancingLayer._state.origin; + for (let sectionPlaneIndex = 0; sectionPlaneIndex < numSectionPlanes; sectionPlaneIndex++) { + const sectionPlaneUniforms = this._uSectionPlanes[sectionPlaneIndex]; + if (sectionPlaneUniforms) { + const active = renderFlags.sectionPlanesActivePerLayer[baseIndex + sectionPlaneIndex]; + gl.uniform1i(sectionPlaneUniforms.active, active ? 1 : 0); + if (active) { + const sectionPlane = sectionPlanes[sectionPlaneIndex]; + if (origin) { + const rtcSectionPlanePos = getPlaneRTCPos(sectionPlane.dist, sectionPlane.dir, origin, tempVec3a$9); + gl.uniform3fv(sectionPlaneUniforms.pos, rtcSectionPlanePos); + } else { + gl.uniform3fv(sectionPlaneUniforms.pos, sectionPlane.pos); + } + gl.uniform3fv(sectionPlaneUniforms.dir, sectionPlane.dir); + } + } + } + } - this.source = props.source; - this.url = props.url; - this.setProps(props); - } + gl.uniform1f(this._uPointSize, 10); - destroy() { - this.idleQueue.forEach(worker => worker.destroy()); - this.isDestroyed = true; - } + gl.drawArraysInstanced(gl.POINTS, 0, state.positionsBuf.numItems, state.numInstances); - setProps(props) { - this.props = { ...this.props, - ...props - }; + gl.vertexAttribDivisor(this._aModelMatrixCol0.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol1.location, 0); + gl.vertexAttribDivisor(this._aModelMatrixCol2.location, 0); + gl.vertexAttribDivisor(this._aColor.location, 0); + gl.vertexAttribDivisor(this._aFlags.location, 0); - if (props.name !== undefined) { - this.name = props.name; - } + if (this._aFlags2) { // Won't be in shader when not clipping + gl.vertexAttribDivisor(this._aFlags2.location, 0); + } - if (props.maxConcurrency !== undefined) { - this.maxConcurrency = props.maxConcurrency; + if (this._aOffset) { + gl.vertexAttribDivisor(this._aOffset.location, 0); + } } - if (props.maxMobileConcurrency !== undefined) { - this.maxMobileConcurrency = props.maxMobileConcurrency; + _allocate() { + const scene = this._scene; + const gl = scene.canvas.gl; + const sectionPlanesState = scene._sectionPlanesState; + this._program = new Program(gl, this._buildShader()); + if (this._program.errors) { + this.errors = this._program.errors; + return; + } + const program = this._program; + this._uPositionsDecodeMatrix = program.getLocation("positionsDecodeMatrix"); + this._uShadowViewMatrix = program.getLocation("shadowViewMatrix"); + this._uShadowProjMatrix = program.getLocation("shadowProjMatrix"); + this._uSectionPlanes = []; + const clips = sectionPlanesState.sectionPlanes; + for (let i = 0, len = clips.length; i < len; i++) { + this._uSectionPlanes.push({ + active: program.getLocation("sectionPlaneActive" + i), + pos: program.getLocation("sectionPlanePos" + i), + dir: program.getLocation("sectionPlaneDir" + i) + }); + } + this._aPosition = program.getAttribute("position"); + this._aOffset = program.getAttribute("offset"); + this._aColor = program.getAttribute("color"); + this._aFlags = program.getAttribute("flags"); + this._aFlags2 = program.getAttribute("flags2"); + this._aModelMatrixCol0 = program.getAttribute("modelMatrixCol0"); + this._aModelMatrixCol1 = program.getAttribute("modelMatrixCol1"); + this._aModelMatrixCol2 = program.getAttribute("modelMatrixCol2"); + this._uPointSize = program.getLocation("pointSize"); } - if (props.reuseWorkers !== undefined) { - this.reuseWorkers = props.reuseWorkers; + _bindProgram(frameCtx, instancingLayer) { + const scene = this._scene; + const gl = scene.canvas.gl; + const program = this._program; + program.bind(); + gl.uniformMatrix4fv(this._uShadowViewMatrix, false, frameCtx.shadowViewMatrix); + gl.uniformMatrix4fv(this._uShadowProjMatrix, false, frameCtx.shadowProjMatrix); + this._lastLightId = null; } - if (props.onDebug !== undefined) { - this.onDebug = props.onDebug; + _buildShader() { + return { + vertex: this._buildVertexShader(), + fragment: this._buildFragmentShader() + }; } - } - async startJob(name, onMessage = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) { - const startPromise = new Promise(onStart => { - this.jobQueue.push({ - name, - onMessage, - onError, - onStart - }); - return this; - }); + _buildVertexShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Instancing geometry shadow drawing vertex shader"); + src.push("in vec3 position;"); + if (scene.entityOffsetsEnabled) { + src.push("in vec3 offset;"); + } + src.push("in vec4 color;"); + src.push("in vec4 flags;"); + src.push("in vec4 flags2;"); + src.push("in vec4 modelMatrixCol0;"); + src.push("in vec4 modelMatrixCol1;"); + src.push("in vec4 modelMatrixCol2;"); + src.push("uniform mat4 shadowViewMatrix;"); + src.push("uniform mat4 shadowProjMatrix;"); + src.push("uniform mat4 positionsDecodeMatrix;"); + src.push("uniform float pointSize;"); + if (clipping) { + src.push("out vec4 vWorldPosition;"); + src.push("out vec4 vFlags2;"); + } + src.push("void main(void) {"); + src.push("bool visible = (float(flags.x) > 0.0);"); + src.push("bool transparent = ((float(color.a) / 255.0) < 1.0);"); + src.push(`if (!visible || transparent) {`); + src.push(" gl_Position = vec4(0.0, 0.0, 0.0, 0.0);"); // Cull vertex + src.push("} else {"); + src.push(" vec4 worldPosition = positionsDecodeMatrix * vec4(position, 1.0); "); + src.push(" worldPosition = vec4(dot(worldPosition, modelMatrixCol0), dot(worldPosition, modelMatrixCol1), dot(worldPosition, modelMatrixCol2), 1.0);"); + if (scene.entityOffsetsEnabled) { + src.push(" worldPosition.xyz = worldPosition.xyz + offset;"); + } + src.push(" vec4 viewPosition = shadowViewMatrix * worldPosition; "); - this._startQueuedJob(); + if (clipping) { + src.push("vWorldPosition = worldPosition;"); + src.push("vFlags2 = flags2;"); + } + src.push(" gl_Position = shadowProjMatrix * viewPosition;"); + src.push("}"); + src.push("gl_PointSize = pointSize;"); + src.push("}"); + return src; + } - return await startPromise; - } + _buildFragmentShader() { + const scene = this._scene; + const sectionPlanesState = scene._sectionPlanesState; + const clipping = sectionPlanesState.sectionPlanes.length > 0; + const src = []; + src.push ('#version 300 es'); + src.push("// Instancing geometry depth drawing fragment shader"); - async _startQueuedJob() { - if (!this.jobQueue.length) { - return; + src.push("#ifdef GL_FRAGMENT_PRECISION_HIGH"); + src.push("precision highp float;"); + src.push("precision highp int;"); + src.push("#else"); + src.push("precision mediump float;"); + src.push("precision mediump int;"); + src.push("#endif"); + if (scene.logarithmicDepthBufferEnabled) { + src.push("uniform float logDepthBufFC;"); + src.push("in float vFragDepth;"); + } + if (clipping) { + src.push("in vec4 vWorldPosition;"); + src.push("in vec4 vFlags2;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("uniform bool sectionPlaneActive" + i + ";"); + src.push("uniform vec3 sectionPlanePos" + i + ";"); + src.push("uniform vec3 sectionPlaneDir" + i + ";"); + } + } + src.push("in vec3 vViewNormal;"); + src.push("vec3 packNormalToRGB( const in vec3 normal ) {"); + src.push(" return normalize( normal ) * 0.5 + 0.5;"); + src.push("}"); + src.push("out vec4 outColor;"); + src.push("void main(void) {"); + src.push(" vec2 cxy = 2.0 * gl_PointCoord - 1.0;"); + src.push(" float r = dot(cxy, cxy);"); + src.push(" if (r > 1.0) {"); + src.push(" discard;"); + src.push(" }"); + if (clipping) { + src.push(" bool clippable = (float(vFlags2.x) > 0.0);"); + src.push(" if (clippable) {"); + src.push(" float dist = 0.0;"); + for (let i = 0, len = sectionPlanesState.sectionPlanes.length; i < len; i++) { + src.push("if (sectionPlaneActive" + i + ") {"); + src.push(" dist += clamp(dot(-sectionPlaneDir" + i + ".xyz, vWorldPosition.xyz - sectionPlanePos" + i + ".xyz), 0.0, 1000.0);"); + src.push("}"); + } + src.push("if (dist > 0.0) { discard; }"); + src.push("}"); + } + if (scene.logarithmicDepthBufferEnabled) { + src.push("gl_FragDepth = log2( vFragDepth ) * logDepthBufFC * 0.5;"); + } + src.push(" outColor = vec4(packNormalToRGB(vViewNormal), 1.0); "); + src.push("}"); + return src; } - const workerThread = this._getAvailableWorker(); + webglContextRestored() { + this._program = null; + } - if (!workerThread) { - return; + destroy() { + if (this._program) { + this._program.destroy(); + } + this._program = null; } +} - const queuedJob = this.jobQueue.shift(); +/** + * @private + */ +class PointsInstancingRenderers { - if (queuedJob) { - this.onDebug({ - message: 'Starting job', - name: queuedJob.name, - workerThread, - backlog: this.jobQueue.length - }); - const job = new WorkerJob(queuedJob.name, workerThread); + constructor(scene) { + this._scene = scene; + } - workerThread.onMessage = data => queuedJob.onMessage(job, data.type, data.payload); + _compile() { + if (this._colorRenderer && (!this._colorRenderer.getValid())) { + this._colorRenderer.destroy(); + this._colorRenderer = null; + } + if (this._depthRenderer && (!this._depthRenderer.getValid())) { + this._depthRenderer.destroy(); + this._depthRenderer = null; + } + if (this._silhouetteRenderer && (!this._silhouetteRenderer.getValid())) { + this._silhouetteRenderer.destroy(); + this._silhouetteRenderer = null; + } + if (this._pickMeshRenderer && (!this._pickMeshRenderer.getValid())) { + this._pickMeshRenderer.destroy(); + this._pickMeshRenderer = null; + } + if (this._pickDepthRenderer && (!this._pickDepthRenderer.getValid())) { + this._pickDepthRenderer.destroy(); + this._pickDepthRenderer = null; + } + if (this._occlusionRenderer && this._occlusionRenderer.getValid() === false) { + this._occlusionRenderer.destroy(); + this._occlusionRenderer = null; + } + if (this._shadowRenderer && (!this._shadowRenderer.getValid())) { + this._shadowRenderer.destroy(); + this._shadowRenderer = null; + } + } - workerThread.onError = error => queuedJob.onError(job, error); + get colorRenderer() { + if (!this._colorRenderer) { + this._colorRenderer = new PointsInstancingColorRenderer(this._scene, false); + } + return this._colorRenderer; + } - queuedJob.onStart(job); + get silhouetteRenderer() { + if (!this._silhouetteRenderer) { + this._silhouetteRenderer = new PointsInstancingSilhouetteRenderer(this._scene); + } + return this._silhouetteRenderer; + } - try { - await job.result; - } finally { - this.returnWorkerToQueue(workerThread); - } + get depthRenderer() { + if (!this._depthRenderer) { + this._depthRenderer = new PointsInstancingDepthRenderer(this._scene); + } + return this._depthRenderer; } - } - returnWorkerToQueue(worker) { - const shouldDestroyWorker = this.isDestroyed || !this.reuseWorkers || this.count > this._getMaxConcurrency(); + get pickMeshRenderer() { + if (!this._pickMeshRenderer) { + this._pickMeshRenderer = new PointsInstancingPickMeshRenderer(this._scene); + } + return this._pickMeshRenderer; + } - if (shouldDestroyWorker) { - worker.destroy(); - this.count--; - } else { - this.idleQueue.push(worker); + get pickDepthRenderer() { + if (!this._pickDepthRenderer) { + this._pickDepthRenderer = new PointsInstancingPickDepthRenderer(this._scene); + } + return this._pickDepthRenderer; } - if (!this.isDestroyed) { - this._startQueuedJob(); + get occlusionRenderer() { + if (!this._occlusionRenderer) { + this._occlusionRenderer = new PointsInstancingOcclusionRenderer(this._scene); + } + return this._occlusionRenderer; } - } - _getAvailableWorker() { - if (this.idleQueue.length > 0) { - return this.idleQueue.shift() || null; + get shadowRenderer() { + if (!this._shadowRenderer) { + this._shadowRenderer = new PointsInstancingShadowRenderer(this._scene); + } + return this._shadowRenderer; } - if (this.count < this._getMaxConcurrency()) { - this.count++; - const name = "".concat(this.name.toLowerCase(), " (#").concat(this.count, " of ").concat(this.maxConcurrency, ")"); - return new WorkerThread({ - name, - source: this.source, - url: this.url - }); + _destroy() { + if (this._colorRenderer) { + this._colorRenderer.destroy(); + } + if (this._depthRenderer) { + this._depthRenderer.destroy(); + } + if (this._silhouetteRenderer) { + this._silhouetteRenderer.destroy(); + } + if (this._pickMeshRenderer) { + this._pickMeshRenderer.destroy(); + } + if (this._pickDepthRenderer) { + this._pickDepthRenderer.destroy(); + } + if (this._occlusionRenderer) { + this._occlusionRenderer.destroy(); + } + if (this._shadowRenderer) { + this._shadowRenderer.destroy(); + } } - - return null; - } - - _getMaxConcurrency() { - return isMobile ? this.maxMobileConcurrency : this.maxConcurrency; - } - } -const DEFAULT_PROPS = { - maxConcurrency: 3, - maxMobileConcurrency: 1, - onDebug: () => {}, - reuseWorkers: true -}; -class WorkerFarm { - static isSupported() { - return WorkerThread.isSupported(); - } - - static getWorkerFarm(props = {}) { - WorkerFarm._workerFarm = WorkerFarm._workerFarm || new WorkerFarm({}); - - WorkerFarm._workerFarm.setProps(props); +const cachedRenderers = {}; - return WorkerFarm._workerFarm; - } +/** + * @private + */ +function getPointsInstancingRenderers(scene) { + const sceneId = scene.id; + let instancingRenderers = cachedRenderers[sceneId]; + if (!instancingRenderers) { + instancingRenderers = new PointsInstancingRenderers(scene); + cachedRenderers[sceneId] = instancingRenderers; + instancingRenderers._compile(); + scene.on("compile", () => { + instancingRenderers._compile(); + }); + scene.on("destroyed", () => { + delete cachedRenderers[sceneId]; + instancingRenderers._destroy(); + }); + } + return instancingRenderers; +} - constructor(props) { - _defineProperty(this, "props", void 0); +const tempUint8Vec4 = new Uint8Array(4); +const tempVec4a$5 = math.vec4([0, 0, 0, 1]); +const tempVec4b$5 = math.vec4([0, 0, 0, 1]); +const tempVec4c$2 = math.vec4([0, 0, 0, 1]); +const tempVec3fa = new Float32Array(3); - _defineProperty(this, "workerPools", new Map()); +/** + * @private + */ +class PointsInstancingLayer { - this.props = { ...DEFAULT_PROPS - }; - this.setProps(props); - this.workerPools = new Map(); - } + /** + * @param cfg + * @param cfg.layerIndex + * @param cfg.model + * @param cfg.geometry + * @param cfg.material + * @param cfg.origin + */ + constructor(cfg) { - destroy() { - for (const workerPool of this.workerPools.values()) { - workerPool.destroy(); - } - } + /** + * Owner model + * @type {VBOSceneModel} + */ + this.model = cfg.model; - setProps(props) { - this.props = { ...this.props, - ...props - }; + /** + * Shared geometry + * @type {VBOSceneModelGeometry} + */ + this.geometry = cfg.geometry; - for (const workerPool of this.workerPools.values()) { - workerPool.setProps(this._getWorkerPoolProps()); - } - } + /** + * Shared material + * @type {VBOSceneModelGeometry} + */ + this.material = cfg.material; - getWorkerPool(options) { - const { - name, - source, - url - } = options; - let workerPool = this.workerPools.get(name); + /** + * State sorting key. + * @type {string} + */ + this.sortId = "PointsInstancingLayer"; - if (!workerPool) { - workerPool = new WorkerPool({ - name, - source, - url - }); - workerPool.setProps(this._getWorkerPoolProps()); - this.workerPools.set(name, workerPool); - } + /** + * Index of this InstancingLayer in VBOSceneModel#_layerList + * @type {Number} + */ + this.layerIndex = cfg.layerIndex; - return workerPool; - } + this._pointsInstancingRenderers = getPointsInstancingRenderers(cfg.model.scene); + this._aabb = math.collapseAABB3(); - _getWorkerPoolProps() { - return { - maxConcurrency: this.props.maxConcurrency, - maxMobileConcurrency: this.props.maxMobileConcurrency, - reuseWorkers: this.props.reuseWorkers, - onDebug: this.props.onDebug - }; - } + this._state = new RenderState({ + obb: math.OBB3(), + numInstances: 0, + origin: cfg.origin ? math.vec3(cfg.origin) : null + }); -} + // These counts are used to avoid unnecessary render passes + this._numPortions = 0; + this._numVisibleLayerPortions = 0; + this._numTransparentLayerPortions = 0; + this._numXRayedLayerPortions = 0; + this._numHighlightedLayerPortions = 0; + this._numSelectedLayerPortions = 0; + this._numClippableLayerPortions = 0; + this._numEdgesLayerPortions = 0; + this._numPickableLayerPortions = 0; + this._numCulledLayerPortions = 0; -_defineProperty(WorkerFarm, "_workerFarm", void 0); + /** @private */ + this.numIndices = cfg.geometry.numIndices; -const NPM_TAG = 'latest'; -function getWorkerURL(worker, options = {}) { - const workerOptions = options[worker.id] || {}; - const workerFile = "".concat(worker.id, "-worker.js"); - let url = workerOptions.workerUrl; + // Per-instance arrays + this._pickColors = []; + this._offsets = []; - if (!url && worker.id === 'compression') { - url = options.workerUrl; - } + // Modeling matrix per instance, array for each column + this._modelMatrixCol0 = []; + this._modelMatrixCol1 = []; + this._modelMatrixCol2 = []; - if (options._workerType === 'test') { - url = "modules/".concat(worker.module, "/dist/").concat(workerFile); - } + this._portions = []; - if (!url) { - let version = worker.version; + this._finalized = false; - if (version === 'latest') { - version = NPM_TAG; + /** + * The axis-aligned World-space boundary of this InstancingLayer's positions. + * @type {*|Float64Array} + */ + this.aabb = math.collapseAABB3(); } - const versionTag = version ? "@".concat(version) : ''; - url = "https://unpkg.com/@loaders.gl/".concat(worker.module).concat(versionTag, "/dist/").concat(workerFile); - } + /** + * Creates a new portion within this InstancingLayer, returns the new portion ID. + * + * The portion will instance this InstancingLayer's geometry. + * + * Gives the portion the specified color and matrix. + * + * @param cfg Portion params + * @param cfg.meshMatrix Flat float 4x4 matrix. + * @param [cfg.worldMatrix] Flat float 4x4 matrix. + * @param cfg.aabb Flat float AABB. + * @param cfg.pickColor Quantized pick color + * @returns {number} Portion ID. + */ + createPortion(cfg) { - assert$4(url); - return url; -} + const meshMatrix = cfg.meshMatrix; + const worldMatrix = cfg.worldMatrix; + const worldAABB = cfg.aabb; + const pickColor = cfg.pickColor; -function validateWorkerVersion(worker, coreVersion = VERSION$9) { - assert$4(worker, 'no worker provided'); - const workerVersion = worker.version; + if (this._finalized) { + throw "Already finalized"; + } - if (!coreVersion || !workerVersion) { - return false; - } + if (this.model.scene.entityOffsetsEnabled) { + this._offsets.push(0); + this._offsets.push(0); + this._offsets.push(0); + } - return true; -} + this._modelMatrixCol0.push(meshMatrix[0]); + this._modelMatrixCol0.push(meshMatrix[4]); + this._modelMatrixCol0.push(meshMatrix[8]); + this._modelMatrixCol0.push(meshMatrix[12]); -var ChildProcessProxy = {}; + this._modelMatrixCol1.push(meshMatrix[1]); + this._modelMatrixCol1.push(meshMatrix[5]); + this._modelMatrixCol1.push(meshMatrix[9]); + this._modelMatrixCol1.push(meshMatrix[13]); -var node = /*#__PURE__*/Object.freeze({ - __proto__: null, - 'default': ChildProcessProxy -}); + this._modelMatrixCol2.push(meshMatrix[2]); + this._modelMatrixCol2.push(meshMatrix[6]); + this._modelMatrixCol2.push(meshMatrix[10]); + this._modelMatrixCol2.push(meshMatrix[14]); -const VERSION$8 = "3.1.8" ; -const loadLibraryPromises = {}; -async function loadLibrary(libraryUrl, moduleName = null, options = {}) { - if (moduleName) { - libraryUrl = getLibraryUrl(libraryUrl, moduleName, options); - } + // Per-instance pick colors - loadLibraryPromises[libraryUrl] = loadLibraryPromises[libraryUrl] || loadLibraryFromFile(libraryUrl); - return await loadLibraryPromises[libraryUrl]; -} -function getLibraryUrl(library, moduleName, options) { - if (library.startsWith('http')) { - return library; - } + this._pickColors.push(pickColor[0]); + this._pickColors.push(pickColor[1]); + this._pickColors.push(pickColor[2]); + this._pickColors.push(pickColor[3]); - const modules = options.modules || {}; + // Expand AABB - if (modules[library]) { - return modules[library]; - } + math.collapseAABB3(worldAABB); + const obb = this._state.obb; + const lenPositions = obb.length; + for (let i = 0; i < lenPositions; i += 4) { + tempVec4a$5[0] = obb[i + 0]; + tempVec4a$5[1] = obb[i + 1]; + tempVec4a$5[2] = obb[i + 2]; + math.transformPoint4(meshMatrix, tempVec4a$5, tempVec4b$5); + if (worldMatrix) { + math.transformPoint4(worldMatrix, tempVec4b$5, tempVec4c$2); + math.expandAABB3Point3(worldAABB, tempVec4c$2); + } else { + math.expandAABB3Point3(worldAABB, tempVec4b$5); + } + } - if (!isBrowser$3) { - return "modules/".concat(moduleName, "/dist/libs/").concat(library); - } + if (this._state.origin) { + const origin = this._state.origin; + worldAABB[0] += origin[0]; + worldAABB[1] += origin[1]; + worldAABB[2] += origin[2]; + worldAABB[3] += origin[0]; + worldAABB[4] += origin[1]; + worldAABB[5] += origin[2]; + } - if (options.CDN) { - assert$4(options.CDN.startsWith('http')); - return "".concat(options.CDN, "/").concat(moduleName, "@").concat(VERSION$8, "/dist/libs/").concat(library); - } + math.expandAABB3(this.aabb, worldAABB); - if (isWorker) { - return "../src/libs/".concat(library); - } + this._state.numInstances++; - return "modules/".concat(moduleName, "/src/libs/").concat(library); -} + const portionId = this._portions.length; + this._portions.push({}); -async function loadLibraryFromFile(libraryUrl) { - if (libraryUrl.endsWith('wasm')) { - const response = await fetch(libraryUrl); - return await response.arrayBuffer(); - } + this._numPortions++; + this.model.numPortions++; - if (!isBrowser$3) { - try { - return node && undefined && (await undefined(libraryUrl)); - } catch { - return null; + return portionId; } - } - if (isWorker) { - return importScripts(libraryUrl); - } + finalize() { + if (this._finalized) { + throw "Already finalized"; + } + const gl = this.model.scene.canvas.gl; + const flagsLength = this._pickColors.length; + if (flagsLength > 0) { + // Because we only build flags arrays here, + // get their length from the colors array + let notNormalized = false; + let normalized = true; + this._state.flagsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, notNormalized); + this._state.flags2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(flagsLength), flagsLength, 4, gl.DYNAMIC_DRAW, normalized); + } + if (this.model.scene.entityOffsetsEnabled) { + if (this._offsets.length > 0) { + const notNormalized = false; + this._state.offsetsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._offsets), this._offsets.length, 3, gl.DYNAMIC_DRAW, notNormalized); + this._offsets = []; // Release memory + } + } + if (this._modelMatrixCol0.length > 0) { + const normalized = false; + this._state.modelMatrixCol0Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol0), this._modelMatrixCol0.length, 4, gl.STATIC_DRAW, normalized); + this._state.modelMatrixCol1Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol1), this._modelMatrixCol1.length, 4, gl.STATIC_DRAW, normalized); + this._state.modelMatrixCol2Buf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Float32Array(this._modelMatrixCol2), this._modelMatrixCol2.length, 4, gl.STATIC_DRAW, normalized); + this._modelMatrixCol0 = []; + this._modelMatrixCol1 = []; + this._modelMatrixCol2 = []; + } + if (this._pickColors.length > 0) { + const normalized = false; + this._state.pickColorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, new Uint8Array(this._pickColors), this._pickColors.length, 4, gl.STATIC_DRAW, normalized); + this._pickColors = []; // Release memory + } + this._finalized = true; + } - const response = await fetch(libraryUrl); - const scriptSource = await response.text(); - return loadLibraryFromString(scriptSource, libraryUrl); -} + // The following setters are called by VBOSceneModelMesh, in turn called by VBOSceneModelNode, only after the layer is finalized. + // It's important that these are called after finalize() in order to maintain integrity of counts like _numVisibleLayerPortions etc. -function loadLibraryFromString(scriptSource, id) { - if (!isBrowser$3) { - return undefined ; - } + initFlags(portionId, flags, meshTransparent) { + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } + if (flags & ENTITY_FLAGS.EDGES) { + this._numEdgesLayerPortions++; + this.model.numEdgesLayerPortions++; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } + if (meshTransparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } + this._setFlags(portionId, flags, meshTransparent); + this._setFlags2(portionId, flags); + } - if (isWorker) { - eval.call(global_, scriptSource); - return null; - } + setVisible(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.VISIBLE) { + this._numVisibleLayerPortions++; + this.model.numVisibleLayerPortions++; + } else { + this._numVisibleLayerPortions--; + this.model.numVisibleLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - const script = document.createElement('script'); - script.id = id; + setHighlighted(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.HIGHLIGHTED) { + this._numHighlightedLayerPortions++; + this.model.numHighlightedLayerPortions++; + } else { + this._numHighlightedLayerPortions--; + this.model.numHighlightedLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - try { - script.appendChild(document.createTextNode(scriptSource)); - } catch (e) { - script.text = scriptSource; - } + setXRayed(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.XRAYED) { + this._numXRayedLayerPortions++; + this.model.numXRayedLayerPortions++; + } else { + this._numXRayedLayerPortions--; + this.model.numXRayedLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - document.body.appendChild(script); - return null; -} + setSelected(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.SELECTED) { + this._numSelectedLayerPortions++; + this.model.numSelectedLayerPortions++; + } else { + this._numSelectedLayerPortions--; + this.model.numSelectedLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } -function canParseWithWorker(loader, options) { - if (!WorkerFarm.isSupported()) { - return false; - } + setEdges(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.EDGES) { + this._numEdgesLayerPortions++; + this.model.numEdgesLayerPortions++; + } else { + this._numEdgesLayerPortions--; + this.model.numEdgesLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - return loader.worker && (options === null || options === void 0 ? void 0 : options.worker); -} -async function parseWithWorker(loader, data, options, context, parseOnMainThread) { - const name = loader.id; - const url = getWorkerURL(loader, options); - const workerFarm = WorkerFarm.getWorkerFarm(options); - const workerPool = workerFarm.getWorkerPool({ - name, - url - }); - options = JSON.parse(JSON.stringify(options)); - const job = await workerPool.startJob('process-on-worker', onMessage.bind(null, parseOnMainThread)); - job.postMessage('process', { - input: data, - options - }); - const result = await job.result; - return await result.result; -} + setClippable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CLIPPABLE) { + this._numClippableLayerPortions++; + this.model.numClippableLayerPortions++; + } else { + this._numClippableLayerPortions--; + this.model.numClippableLayerPortions--; + } + this._setFlags2(portionId, flags); + } -async function onMessage(parseOnMainThread, job, type, payload) { - switch (type) { - case 'done': - job.done(payload); - break; + setCollidable(portionId, flags) { + if (!this._finalized) { + throw "Not finalized"; + } + } - case 'error': - job.error(new Error(payload.error)); - break; + setPickable(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.PICKABLE) { + this._numPickableLayerPortions++; + this.model.numPickableLayerPortions++; + } else { + this._numPickableLayerPortions--; + this.model.numPickableLayerPortions--; + } + this._setFlags2(portionId, flags, meshTransparent); + } - case 'process': - const { - id, - input, - options - } = payload; + setCulled(portionId, flags, meshTransparent) { + if (!this._finalized) { + throw "Not finalized"; + } + if (flags & ENTITY_FLAGS.CULLED) { + this._numCulledLayerPortions++; + this.model.numCulledLayerPortions++; + } else { + this._numCulledLayerPortions--; + this.model.numCulledLayerPortions--; + } + this._setFlags(portionId, flags, meshTransparent); + } - try { - const result = await parseOnMainThread(input, options); - job.postMessage('done', { - id, - result - }); - } catch (error) { - const message = error instanceof Error ? error.message : 'unknown error'; - job.postMessage('error', { - id, - error: message - }); - } + setColor(portionId, color) { // RGBA color is normalized as ints + if (!this._finalized) { + throw "Not finalized"; + } + tempUint8Vec4[0] = color[0]; + tempUint8Vec4[1] = color[1]; + tempUint8Vec4[2] = color[2]; + this._state.colorsBuf.setData(tempUint8Vec4, portionId * 3, 3); + } - break; + setTransparent(portionId, flags, transparent) { + if (transparent) { + this._numTransparentLayerPortions++; + this.model.numTransparentLayerPortions++; + } else { + this._numTransparentLayerPortions--; + this.model.numTransparentLayerPortions--; + } + this._setFlags(portionId, flags, transparent); + } - default: - console.warn("parse-with-worker unknown message ".concat(type)); - } -} + // setMatrix(portionId, matrix) { + // + // if (!this._finalized) { + // throw "Not finalized"; + // } + // + // var offset = portionId * 4; + // + // tempFloat32Vec4[0] = matrix[0]; + // tempFloat32Vec4[1] = matrix[4]; + // tempFloat32Vec4[2] = matrix[8]; + // tempFloat32Vec4[3] = matrix[12]; + // + // this._state.modelMatrixCol0Buf.setData(tempFloat32Vec4, offset, 4); + // + // tempFloat32Vec4[0] = matrix[1]; + // tempFloat32Vec4[1] = matrix[5]; + // tempFloat32Vec4[2] = matrix[9]; + // tempFloat32Vec4[3] = matrix[13]; + // + // this._state.modelMatrixCol1Buf.setData(tempFloat32Vec4, offset, 4); + // + // tempFloat32Vec4[0] = matrix[2]; + // tempFloat32Vec4[1] = matrix[6]; + // tempFloat32Vec4[2] = matrix[10]; + // tempFloat32Vec4[3] = matrix[14]; + // + // this._state.modelMatrixCol2Buf.setData(tempFloat32Vec4, offset, 4); + // } -function getFirstCharacters$1(data, length = 5) { - if (typeof data === 'string') { - return data.slice(0, length); - } else if (ArrayBuffer.isView(data)) { - return getMagicString$2(data.buffer, data.byteOffset, length); - } else if (data instanceof ArrayBuffer) { - const byteOffset = 0; - return getMagicString$2(data, byteOffset, length); - } + _setFlags(portionId, flags, meshTransparent) { - return ''; -} -function getMagicString$2(arrayBuffer, byteOffset, length) { - if (arrayBuffer.byteLength <= byteOffset + length) { - return ''; - } + if (!this._finalized) { + throw "Not finalized"; + } - const dataView = new DataView(arrayBuffer); - let magic = ''; + const visible = !!(flags & ENTITY_FLAGS.VISIBLE); + const xrayed = !!(flags & ENTITY_FLAGS.XRAYED); + const highlighted = !!(flags & ENTITY_FLAGS.HIGHLIGHTED); + const selected = !!(flags & ENTITY_FLAGS.SELECTED); + const edges = !!(flags & ENTITY_FLAGS.EDGES); + const pickable = !!(flags & ENTITY_FLAGS.PICKABLE); + const culled = !!(flags & ENTITY_FLAGS.CULLED); - for (let i = 0; i < length; i++) { - magic += String.fromCharCode(dataView.getUint8(byteOffset + i)); - } + // Normal fill - return magic; -} + let f0; + if (!visible || culled || xrayed + || (highlighted && !this.model.scene.highlightMaterial.glowThrough) + || (selected && !this.model.scene.selectedMaterial.glowThrough) ) { + f0 = RENDER_PASSES.NOT_RENDERED; + } else { + if (meshTransparent) { + f0 = RENDER_PASSES.COLOR_TRANSPARENT; + } else { + f0 = RENDER_PASSES.COLOR_OPAQUE; + } + } -function parseJSON(string) { - try { - return JSON.parse(string); - } catch (_) { - throw new Error("Failed to parse JSON from data starting with \"".concat(getFirstCharacters$1(string), "\"")); - } -} + // Emphasis fill -function isBuffer$1(value) { - return value && typeof value === 'object' && value.isBuffer; -} -function bufferToArrayBuffer(buffer) { - if (isBuffer$1(buffer)) { - const typedArray = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.length); - return typedArray.slice().buffer; - } + let f1; + if (!visible || culled) { + f1 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f1 = RENDER_PASSES.SILHOUETTE_SELECTED; + } else if (highlighted) { + f1 = RENDER_PASSES.SILHOUETTE_HIGHLIGHTED; + } else if (xrayed) { + f1 = RENDER_PASSES.SILHOUETTE_XRAYED; + } else { + f1 = RENDER_PASSES.NOT_RENDERED; + } - return buffer; -} + // Edges -function toArrayBuffer(data) { - if (isBuffer$1(data)) { - return bufferToArrayBuffer(data); - } + let f2 = 0; + if (!visible || culled) { + f2 = RENDER_PASSES.NOT_RENDERED; + } else if (selected) { + f2 = RENDER_PASSES.EDGES_SELECTED; + } else if (highlighted) { + f2 = RENDER_PASSES.EDGES_HIGHLIGHTED; + } else if (xrayed) { + f2 = RENDER_PASSES.EDGES_XRAYED; + } else if (edges) { + if (meshTransparent) { + f2 = RENDER_PASSES.EDGES_COLOR_TRANSPARENT; + } else { + f2 = RENDER_PASSES.EDGES_COLOR_OPAQUE; + } + } else { + f2 = RENDER_PASSES.NOT_RENDERED; + } - if (data instanceof ArrayBuffer) { - return data; - } + // Pick - if (ArrayBuffer.isView(data)) { - if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) { - return data.buffer; - } + let f3 = (visible && !culled && pickable) ? RENDER_PASSES.PICK : RENDER_PASSES.NOT_RENDERED; - return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength); - } + tempUint8Vec4[0] = f0; // x - normal fill + tempUint8Vec4[1] = f1; // y - emphasis fill + tempUint8Vec4[2] = f2; // z - edges + tempUint8Vec4[3] = f3; // w - pick - if (typeof data === 'string') { - const text = data; - const uint8Array = new TextEncoder().encode(text); - return uint8Array.buffer; - } + this._state.flagsBuf.setData(tempUint8Vec4, portionId * 4, 4); + } - if (data && typeof data === 'object' && data._toArrayBuffer) { - return data._toArrayBuffer(); - } + _setFlags2(portionId, flags) { - throw new Error('toArrayBuffer'); -} -function compareArrayBuffers(arrayBuffer1, arrayBuffer2, byteLength) { - byteLength = byteLength || arrayBuffer1.byteLength; + if (!this._finalized) { + throw "Not finalized"; + } - if (arrayBuffer1.byteLength < byteLength || arrayBuffer2.byteLength < byteLength) { - return false; - } + const clippable = !!(flags & ENTITY_FLAGS.CLIPPABLE) ? 255 : 0; + tempUint8Vec4[0] = clippable; - const array1 = new Uint8Array(arrayBuffer1); - const array2 = new Uint8Array(arrayBuffer2); + this._state.flags2Buf.setData(tempUint8Vec4, portionId * 4, 4); + } - for (let i = 0; i < array1.length; ++i) { - if (array1[i] !== array2[i]) { - return false; + setOffset(portionId, offset) { + if (!this._finalized) { + throw "Not finalized"; + } + if (!this.model.scene.entityOffsetsEnabled) { + this.model.error("Entity#offset not enabled for this Viewer"); // See Viewer entityOffsetsEnabled + return; + } + tempVec3fa[0] = offset[0]; + tempVec3fa[1] = offset[1]; + tempVec3fa[2] = offset[2]; + this._state.offsetsBuf.setData(tempVec3fa, portionId * 3, 3); } - } - return true; -} -function concatenateArrayBuffers(...sources) { - const sourceArrays = sources.map(source2 => source2 instanceof ArrayBuffer ? new Uint8Array(source2) : source2); - const byteLength = sourceArrays.reduce((length, typedArray) => length + typedArray.byteLength, 0); - const result = new Uint8Array(byteLength); - let offset = 0; + // ---------------------- NORMAL RENDERING ----------------------------------- - for (const sourceArray of sourceArrays) { - result.set(sourceArray, offset); - offset += sourceArray.byteLength; - } + drawColorOpaque(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === this._numPortions || this._numXRayedLayerPortions === this._numPortions) { + return; + } + if (this._pointsInstancingRenderers.colorRenderer) { + this._pointsInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } - return result.buffer; -} -function sliceArrayBuffer(arrayBuffer, byteOffset, byteLength) { - const subArray = byteLength !== undefined ? new Uint8Array(arrayBuffer).subarray(byteOffset, byteOffset + byteLength) : new Uint8Array(arrayBuffer).subarray(byteOffset); - const arrayCopy = new Uint8Array(subArray); - return arrayCopy.buffer; -} + drawColorTransparent(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numTransparentLayerPortions === 0 || this._numXRayedLayerPortions === this._numPortions) { + return; + } + if (this._pointsInstancingRenderers.colorRenderer) { + this._pointsInstancingRenderers.colorRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_TRANSPARENT); + } + } -function padToNBytes(byteLength, padding) { - assert$5(byteLength >= 0); - assert$5(padding > 0); - return byteLength + (padding - 1) & ~(padding - 1); -} -function copyToArray(source, target, targetOffset) { - let sourceArray; + // -- RENDERING SAO POST EFFECT TARGETS ---------------------------------------------------------------------------- - if (source instanceof ArrayBuffer) { - sourceArray = new Uint8Array(source); - } else { - const srcByteOffset = source.byteOffset; - const srcByteLength = source.byteLength; - sourceArray = new Uint8Array(source.buffer || source.arrayBuffer, srcByteOffset, srcByteLength); - } + drawDepth(renderFlags, frameCtx) { + } - target.set(sourceArray, targetOffset); - return targetOffset + padToNBytes(sourceArray.byteLength, 4); -} + drawNormals(renderFlags, frameCtx) { + } -async function concatenateArrayBuffersAsync(asyncIterator) { - const arrayBuffers = []; + // ---------------------- EMPHASIS RENDERING ----------------------------------- - for await (const chunk of asyncIterator) { - arrayBuffers.push(chunk); - } + drawSilhouetteXRayed(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numXRayedLayerPortions === 0) { + return; + } + if (this._pointsInstancingRenderers.silhouetteRenderer) { + this._pointsInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_XRAYED); + } + } - return concatenateArrayBuffers(...arrayBuffers); -} + drawSilhouetteHighlighted(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numHighlightedLayerPortions === 0) { + return; + } + if (this._pointsInstancingRenderers.silhouetteRenderer) { + this._pointsInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_HIGHLIGHTED); + } + } -let pathPrefix = ''; -const fileAliases = {}; -function resolvePath$1(filename) { - for (const alias in fileAliases) { - if (filename.startsWith(alias)) { - const replacement = fileAliases[alias]; - filename = filename.replace(alias, replacement); + drawSilhouetteSelected(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0 || this._numSelectedLayerPortions === 0) { + return; + } + if (this._pointsInstancingRenderers.silhouetteRenderer) { + this._pointsInstancingRenderers.silhouetteRenderer.drawLayer(frameCtx, this, RENDER_PASSES.SILHOUETTE_SELECTED); + } } - } - if (!filename.startsWith('http://') && !filename.startsWith('https://')) { - filename = "".concat(pathPrefix).concat(filename); - } + //-- EDGES RENDERING ----------------------------------------------------------------------------------------------- - return filename; -} + drawEdgesColorOpaque(renderFlags, frameCtx) { + } -function filename(url) { - const slashIndex = url && url.lastIndexOf('/'); - return slashIndex >= 0 ? url.substr(slashIndex + 1) : ''; -} + drawEdgesColorTransparent(renderFlags, frameCtx) { + } -const isBoolean = x => typeof x === 'boolean'; + drawEdgesHighlighted(renderFlags, frameCtx) { + } -const isFunction = x => typeof x === 'function'; + drawEdgesSelected(renderFlags, frameCtx) { + } -const isObject = x => x !== null && typeof x === 'object'; -const isPureObject = x => isObject(x) && x.constructor === {}.constructor; -const isIterable = x => x && typeof x[Symbol.iterator] === 'function'; -const isAsyncIterable = x => x && typeof x[Symbol.asyncIterator] === 'function'; -const isResponse = x => typeof Response !== 'undefined' && x instanceof Response || x && x.arrayBuffer && x.text && x.json; -const isBlob = x => typeof Blob !== 'undefined' && x instanceof Blob; -const isBuffer = x => x && typeof x === 'object' && x.isBuffer; -const isReadableDOMStream = x => typeof ReadableStream !== 'undefined' && x instanceof ReadableStream || isObject(x) && isFunction(x.tee) && isFunction(x.cancel) && isFunction(x.getReader); -const isReadableNodeStream = x => isObject(x) && isFunction(x.read) && isFunction(x.pipe) && isBoolean(x.readable); -const isReadableStream = x => isReadableDOMStream(x) || isReadableNodeStream(x); + drawEdgesXRayed(renderFlags, frameCtx) { + } -const DATA_URL_PATTERN = /^data:([-\w.]+\/[-\w.+]+)(;|,)/; -const MIME_TYPE_PATTERN = /^([-\w.]+\/[-\w.+]+)/; -function parseMIMEType(mimeString) { - const matches = MIME_TYPE_PATTERN.exec(mimeString); + // ---------------------- OCCLUSION CULL RENDERING ----------------------------------- - if (matches) { - return matches[1]; - } + drawOcclusion(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + if (this._pointsInstancingRenderers.occlusionRenderer) { + // Only opaque, filled objects can be occluders + this._pointsInstancingRenderers.occlusionRenderer.drawLayer(frameCtx, this, RENDER_PASSES.COLOR_OPAQUE); + } + } - return mimeString; -} -function parseMIMETypeFromURL(url) { - const matches = DATA_URL_PATTERN.exec(url); + // ---------------------- SHADOW BUFFER RENDERING ----------------------------------- - if (matches) { - return matches[1]; - } + drawShadow(renderFlags, frameCtx) { + } - return ''; -} + //---- PICKING ---------------------------------------------------------------------------------------------------- -const QUERY_STRING_PATTERN = /\?.*/; -function getResourceUrlAndType(resource) { - if (isResponse(resource)) { - const url = stripQueryString(resource.url || ''); - const contentTypeHeader = resource.headers.get('content-type') || ''; - return { - url, - type: parseMIMEType(contentTypeHeader) || parseMIMETypeFromURL(url) - }; - } + drawPickMesh(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + if (this._pointsInstancingRenderers.pickMeshRenderer) { + this._pointsInstancingRenderers.pickMeshRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } + } - if (isBlob(resource)) { - return { - url: stripQueryString(resource.name || ''), - type: resource.type || '' - }; - } + drawPickDepths(renderFlags, frameCtx) { + if (this._numCulledLayerPortions === this._numPortions || this._numVisibleLayerPortions === 0) { + return; + } + if (this._pointsInstancingRenderers.pickDepthRenderer) { + this._pointsInstancingRenderers.pickDepthRenderer.drawLayer(frameCtx, this, RENDER_PASSES.PICK); + } + } - if (typeof resource === 'string') { - return { - url: stripQueryString(resource), - type: parseMIMETypeFromURL(resource) - }; - } + drawPickNormals(renderFlags, frameCtx) { + } - return { - url: '', - type: '' - }; -} -function getResourceContentLength(resource) { - if (isResponse(resource)) { - return resource.headers['content-length'] || -1; - } - - if (isBlob(resource)) { - return resource.size; - } - - if (typeof resource === 'string') { - return resource.length; - } - - if (resource instanceof ArrayBuffer) { - return resource.byteLength; - } - - if (ArrayBuffer.isView(resource)) { - return resource.byteLength; - } - - return -1; -} - -function stripQueryString(url) { - return url.replace(QUERY_STRING_PATTERN, ''); + destroy() { + const state = this._state; + if (state.colorsBuf) { + state.colorsBuf.destroy(); + state.colorsBuf = null; + } + if (state.flagsBuf) { + state.flagsBuf.destroy(); + state.flagsBuf = null; + } + if (state.flags2Buf) { + state.flags2Buf.destroy(); + state.flags2Buf = null; + } + if (state.offsetsBuf) { + state.offsetsBuf.destroy(); + state.offsetsBuf = null; + } + if (state.modelMatrixCol0Buf) { + state.modelMatrixCol0Buf.destroy(); + state.modelMatrixCol0Buf = null; + } + if (state.modelMatrixCol1Buf) { + state.modelMatrixCol1Buf.destroy(); + state.modelMatrixCol1Buf = null; + } + if (state.modelMatrixCol2Buf) { + state.modelMatrixCol2Buf.destroy(); + state.modelMatrixCol2Buf = null; + } + if (state.pickColorsBuf) { + state.pickColorsBuf.destroy(); + state.pickColorsBuf = null; + } + state.destroy(); + } } -async function makeResponse(resource) { - if (isResponse(resource)) { - return resource; - } +/** + * Instantiated by Model#createTextureSet + * + * @private + */ +class VBOSceneModelTextureSet { - const headers = {}; - const contentLength = getResourceContentLength(resource); + /** + * @param {*} cfg VBOSceneModelTextureSet properties. + * @param {String|Number} cfg.id Mandatory ID for the texture set, to refer to with {@link VBOSceneModel#createMesh}. + * @param {VBOSceneModel} cfg.model VBOSceneModel that owns this texture set. + * @param {VBOSceneModelTexture} [cfg.colorTexture] RGBA texture with base color in RGB and opacity in A. + * @param {VBOSceneModelTexture} [cfg.metallicRoughnessTexture] RGBA texture with metallic in R and roughness in G. + * @param {VBOSceneModelTexture} [cfg.normalsTexture] RGBA texture with surface normals in RGB. + * @param {VBOSceneModelTexture} [cfg.emissiveTexture] RGBA texture with emissive color in RGB. + * @param {VBOSceneModelTexture} [cfg.occlusionTexture] RGBA texture with ambient occlusion factors in RGB. + */ + constructor(cfg) { - if (contentLength >= 0) { - headers['content-length'] = String(contentLength); - } + /** + * ID of this VBOSceneModelTextureSet, unique within the VBOSceneModel. + * + * @property id + * @type {String} + * @final + */ + this.id = cfg.id; - const { - url, - type - } = getResourceUrlAndType(resource); + /** + * RGBA texture containing base color in RGB and opacity in A. + * + * @property colorTexture + * @type {VBOSceneModelTexture} + * @final + */ + this.colorTexture = cfg.colorTexture; - if (type) { - headers['content-type'] = type; - } + /** + * RGBA texture containing metallic and roughness factors in R and G. + * + * @property metallicRoughnessTexture + * @type {VBOSceneModelTexture} + * @final + */ + this.metallicRoughnessTexture = cfg.metallicRoughnessTexture; - const initialDataUrl = await getInitialDataUrl(resource); + /** + * RGBA texture with surface normals in RGB. + * + * @property normalsTexture + * @type {VBOSceneModelTexture} + * @final + */ + this.normalsTexture = cfg.normalsTexture; - if (initialDataUrl) { - headers['x-first-bytes'] = initialDataUrl; - } + /** + * RGBA texture with emissive color in RGB. + * + * @property emissiveTexture + * @type {VBOSceneModelTexture} + * @final + */ + this.emissiveTexture = cfg.emissiveTexture; - if (typeof resource === 'string') { - resource = new TextEncoder().encode(resource); - } + /** + * RGBA texture with ambient occlusion factors in RGB. + * + * @property occlusionTexture + * @type {VBOSceneModelTexture} + * @final + */ + this.occlusionTexture = cfg.occlusionTexture; + } - const response = new Response(resource, { - headers - }); - Object.defineProperty(response, 'url', { - value: url - }); - return response; -} -async function checkResponse(response) { - if (!response.ok) { - const message = await getResponseError(response); - throw new Error(message); - } + /** + * @private + */ + destroy() { + } } -async function getResponseError(response) { - let message = "Failed to fetch resource ".concat(response.url, " (").concat(response.status, "): "); - - try { - const contentType = response.headers.get('Content-Type'); - let text = response.statusText; +/** + * Instantiated by VBOSceneModel#createGeometry + * + * @private + */ +class VBOSceneModelGeometry { - if (contentType.includes('application/json')) { - text += " ".concat(await response.text()); - } + /** + * @param {*} cfg Geometry properties. + * @param {String|Number} id Mandatory ID for the geometry, to refer to with {@link VBOSceneModel#createMesh}. + * @param {VBOSceneModel} model VBOSceneModel that owns this geometry. + * @param {*} cfg.primitive + * @param {*} cfg.positions + * @param {*} cfg.positionsCompressed + * @param {*} cfg.normals + * @param {*} cfg.normalsCompressed + * @param {*} cfg.colors + * @param {*} cfg.colorsCompressed + * @param {*} cfg.uv + * @param {*} cfg.uvCompressed + * @param {*} cfg.uvDecodeMatrix + * @param {*} cfg.indices + * @param {*} cfg.edgeIndices + */ + constructor(id, model, cfg) { - message += text; - message = message.length > 60 ? "".concat(message.slice(60), "...") : message; - } catch (error) {} + /////////////////////////////////////////////////////// + /////////////////////////////////////////////////////// + // TODO: optional origin param, or create from positions automatically if required - then offset from mesh origin in createMesh - return message; -} + /** + * ID of this VBOSceneModelGeometry, unique within the VBOSceneModel. + * + * @property id + * @type {String} + * @final + */ + this.id = cfg.id; -async function getInitialDataUrl(resource) { - const INITIAL_DATA_LENGTH = 5; + /** + * The VBOSceneModel that contains this VBOSceneModelGeometry. + * + * @property model + * @type {VBOSceneModel} + * @final + */ + this.model = cfg.model; - if (typeof resource === 'string') { - return "data:,".concat(resource.slice(0, INITIAL_DATA_LENGTH)); - } + this.primitive = cfg.primitive; + this.positions = null; + this.positionsCompressed = null; + this.quantizedPositions = null; // If pickSurfacePrecisionEnabled is true + this.positionsDecodeMatrix = math.mat4(); + this.normals = null; + this.normalsCompressed = null; + this.colors = null; + this.colorsCompressed = null; + this.uv = null; + this.uvCompressed = null; + this.uvDecodeMatrix = null; + this.indices = null; + this.numIndices = 0; + this.obb = math.OBB3(); + this.positionsBuf = null; + this.normalsBuf = null; + this.edgeIndicesBuf = null; + this.uvBuf = null; + this.colorsBuf = null; - if (resource instanceof Blob) { - const blobSlice = resource.slice(0, 5); - return await new Promise(resolve => { - const reader = new FileReader(); + const pickSurfacePrecisionEnabled = model.scene.pickSurfacePrecisionEnabled; + const gl = model.scene.canvas.gl; - reader.onload = event => { - var _event$target; + if (cfg.positionsCompressed && cfg.positionsCompressed.length > 0) { + const normalized = false; + this.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, cfg.positionsCompressed, cfg.positionsCompressed.length, 3, gl.STATIC_DRAW, normalized); + this.positionsDecodeMatrix.set(cfg.positionsDecodeMatrix); + const localAABB = math.collapseAABB3(); + math.expandAABB3Points3(localAABB, cfg.positionsCompressed); + geometryCompressionUtils.decompressAABB(localAABB, this.positionsDecodeMatrix); + math.AABB3ToOBB3(localAABB, this.obb); + if (pickSurfacePrecisionEnabled) { + this.quantizedPositions = cfg.positionsCompressed; + } - return resolve(event === null || event === void 0 ? void 0 : (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.result); - }; + } else if (cfg.positions && cfg.positions.length > 0) { + const lenPositions = cfg.positions.length; + const localAABB = math.collapseAABB3(); + math.expandAABB3Points3(localAABB, cfg.positions); + math.AABB3ToOBB3(localAABB, this.obb); + const quantizedPositions = quantizePositions(cfg.positions, localAABB, this.positionsDecodeMatrix); + let normalized = false; + this.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, lenPositions, 3, gl.STATIC_DRAW, normalized); + if (pickSurfacePrecisionEnabled) { + this.quantizedPositions = quantizedPositions; + } + } - reader.readAsDataURL(blobSlice); - }); - } + if (cfg.normalsCompressed && cfg.normalsCompressed.length > 0) { + const normalized = true; // For oct-encoded UInt8 + this.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, cfg.normalsCompressed, cfg.normalsCompressed.length, 3, gl.STATIC_DRAW, normalized); - if (resource instanceof ArrayBuffer) { - const slice = resource.slice(0, INITIAL_DATA_LENGTH); - const base64 = arrayBufferToBase64(slice); - return "data:base64,".concat(base64); - } + } else if (cfg.normals && cfg.normals.length > 0) { + const compressedNormals = octEncodeNormals(cfg.normals); + const normalized = true; // For oct-encoded UInt8 + this.normalsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, compressedNormals, compressedNormals.length, 3, gl.STATIC_DRAW, normalized); + } - return null; -} + if (cfg.colorsCompressed && cfg.colorsCompressed.length > 0) { + const colorsCompressed = new Uint8Array(cfg.colorsCompressed); + const notNormalized = false; + this.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colorsCompressed, colorsCompressed.length, 4, gl.STATIC_DRAW, notNormalized); -function arrayBufferToBase64(buffer) { - let binary = ''; - const bytes = new Uint8Array(buffer); + } else if (cfg.colors && cfg.colors.length > 0) { + const colors = cfg.colors; + const colorsCompressed = new Uint8Array(colors.length); + for (let i = 0, len = colors.length; i < len; i++) { + colorsCompressed[i] = colors[i] * 255; + } + const notNormalized = false; + this.colorsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, colorsCompressed, colorsCompressed.length, 4, gl.STATIC_DRAW, notNormalized); + } - for (let i = 0; i < bytes.byteLength; i++) { - binary += String.fromCharCode(bytes[i]); - } + if (cfg.uvCompressed && cfg.uvCompressed.length > 0) { + const uvCompressed = new Uint16Array(cfg.uvCompressed); + this.uvDecodeMatrix = math.mat4(cfg.uvDecodeMatrix); + this.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, cfg.uvCompressed, uvCompressed.length, 2, gl.STATIC_DRAW, false); - return btoa(binary); -} + } else if (cfg.uv && cfg.uv.length > 0) { + const bounds = geometryCompressionUtils.getUVBounds(cfg.uv); + const result = geometryCompressionUtils.compressUVs(cfg.uv, bounds.min, bounds.max); + const uvCompressed = result.quantized; + this.uvDecodeMatrix = result.decodeMatrix; + this.uvBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, uvCompressed, uvCompressed.length, 2, gl.STATIC_DRAW, false); + } -async function fetchFile(url, options) { - if (typeof url === 'string') { - url = resolvePath$1(url); - let fetchOptions = options; + if (cfg.indices && cfg.indices.length > 0) { + this.indicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(cfg.indices), cfg.indices.length, 1, gl.STATIC_DRAW); + if (pickSurfacePrecisionEnabled) { + this.indices = cfg.indices; + } + this.numIndices = cfg.indices.length; + } - if (options !== null && options !== void 0 && options.fetch && typeof (options === null || options === void 0 ? void 0 : options.fetch) !== 'function') { - fetchOptions = options.fetch; + if (cfg.primitive === "triangles" || cfg.primitive === "solid" || cfg.primitive === "surface") { + let edgeIndices = cfg.edgeIndices; + if (!edgeIndices) { + edgeIndices = buildEdgeIndices(cfg.positions, cfg.indices, null, cfg.edgeThreshold || 10); + } + this.edgeIndicesBuf = new ArrayBuf(gl, gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(edgeIndices), edgeIndices.length, 1, gl.STATIC_DRAW); + } } - return await fetch(url, fetchOptions); - } - - return await makeResponse(url); + /** + * @private + */ + destroy() { + } } -function isElectron$1(mockUserAgent) { - if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { - return true; - } +/** + * Instantiated by VBOSceneModel#createTexture + * + * @private + */ +class VBOSceneModelTexture { - if (typeof process !== 'undefined' && typeof process.versions === 'object' && Boolean(process.versions.electron)) { - return true; - } + /** + * @param {*} cfg Texture properties. + * @param {String|Number} cfg.id Mandatory ID for the texture, to refer to with {@link VBOSceneModel#createTexture}. + * @param {String} [cfg.model] VBOSceneModel that owns this texture. + * @param {*} [cfg.image] Texture image data. + * @param {String} [cfg.src] Texture image source. + * @param {Boolean} [cfg.flipY] Whether to flip on Y-axis. + * @param {number[]} [cfg.preloadColor] Texture preload color. + */ + constructor(cfg) { - const realUserAgent = typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent; - const userAgent = mockUserAgent || realUserAgent; + /** + * ID of this VBOSceneModelTexture, unique within the VBOSceneModel. + * + * @property id + * @type {String} + */ + this.id = cfg.id; - if (userAgent && userAgent.indexOf('Electron') >= 0) { - return true; - } + /** + * The texture. + * + * @property texture + * @type {Texture2D} + */ + this.texture = cfg.texture; + } - return false; + /** + * @private + */ + destroy() { + if (this.texture) { + this.texture.destroy(); + this.texture = null; + } + } } -function isBrowser$2() { - const isNode = typeof process === 'object' && String(process) === '[object process]' && !process.browser; - return !isNode || isElectron$1(); -} +const Cache = { -const globals$1 = { - self: typeof self !== 'undefined' && self, - window: typeof window !== 'undefined' && window, - global: typeof global !== 'undefined' && global, - document: typeof document !== 'undefined' && document, - process: typeof process === 'object' && process -}; -const window_$1 = globals$1.window || globals$1.self || globals$1.global; -const process_$1 = globals$1.process || {}; + enabled: false, + files: {}, -const VERSION$7 = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'untranspiled source'; -const isBrowser$1 = isBrowser$2(); + add: function (key, file) { + if (this.enabled === false) { + return; + } + this.files[key] = file; + }, -function getStorage$1(type) { - try { - const storage = window[type]; - const x = '__storage_test__'; - storage.setItem(x, x); - storage.removeItem(x); - return storage; - } catch (e) { - return null; - } -} + get: function (key) { + if (this.enabled === false) { + return; + } + return this.files[key]; + }, -class LocalStorage$1 { - constructor(id, defaultSettings, type = 'sessionStorage') { - this.storage = getStorage$1(type); - this.id = id; - this.config = {}; - Object.assign(this.config, defaultSettings); + remove: function (key) { + delete this.files[key]; + }, - this._loadConfiguration(); - } + clear: function () { + this.files = {}; + } +}; - getConfiguration() { - return this.config; - } +class LoadingManager { - setConfiguration(configuration) { - this.config = {}; - return this.updateConfiguration(configuration); - } + constructor(onLoad, onProgress, onError) { - updateConfiguration(configuration) { - Object.assign(this.config, configuration); + this.isLoading = false; + this.itemsLoaded = 0; + this.itemsTotal = 0; + this.urlModifier = undefined; + this.handlers = []; - if (this.storage) { - const serialized = JSON.stringify(this.config); - this.storage.setItem(this.id, serialized); + this.onStart = undefined; + this.onLoad = onLoad; + this.onProgress = onProgress; + this.onError = onError; } - return this; - } + itemStart(url) { + this.itemsTotal++; + if (this.isLoading === false) { + if (this.onStart !== undefined) { + this.onStart(url, this.itemsLoaded, this.itemsTotal); + } + } + this.isLoading = true; + } - _loadConfiguration() { - let configuration = {}; + itemEnd(url) { + this.itemsLoaded++; + if (this.onProgress !== undefined) { + this.onProgress(url, this.itemsLoaded, this.itemsTotal); + } + if (this.itemsLoaded === this.itemsTotal) { + this.isLoading = false; + if (this.onLoad !== undefined) { + this.onLoad(); + } + } + } - if (this.storage) { - const serializedConfiguration = this.storage.getItem(this.id); - configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {}; + itemError(url) { + if (this.onError !== undefined) { + this.onError(url); + } } - Object.assign(this.config, configuration); - return this; - } + resolveURL(url) { + if (this.urlModifier) { + return this.urlModifier(url); + } + return url; + } -} + setURLModifier(transform) { + this.urlModifier = transform; + return this; + } -function formatTime$1(ms) { - let formatted; + addHandler(regex, loader) { + this.handlers.push(regex, loader); + return this; + } - if (ms < 10) { - formatted = "".concat(ms.toFixed(2), "ms"); - } else if (ms < 100) { - formatted = "".concat(ms.toFixed(1), "ms"); - } else if (ms < 1000) { - formatted = "".concat(ms.toFixed(0), "ms"); - } else { - formatted = "".concat((ms / 1000).toFixed(2), "s"); - } + removeHandler(regex) { + const index = this.handlers.indexOf(regex); + if (index !== -1) { + this.handlers.splice(index, 2); + } + return this; + } - return formatted; -} -function leftPad$1(string, length = 8) { - const padLength = Math.max(length - string.length, 0); - return "".concat(' '.repeat(padLength)).concat(string); + getHandler(file) { + for (let i = 0, l = this.handlers.length; i < l; i += 2) { + const regex = this.handlers[i]; + const loader = this.handlers[i + 1]; + if (regex.global) regex.lastIndex = 0; // see #17920 + if (regex.test(file)) { + return loader; + } + } + return null; + } } -function formatImage$1(image, message, scale, maxWidth = 600) { - const imageUrl = image.src.replace(/\(/g, '%28').replace(/\)/g, '%29'); - - if (image.width > maxWidth) { - scale = Math.min(scale, maxWidth / image.width); - } +const DefaultLoadingManager = new LoadingManager(); - const width = image.width * scale; - const height = image.height * scale; - const style = ['font-size:1px;', "padding:".concat(Math.floor(height / 2), "px ").concat(Math.floor(width / 2), "px;"), "line-height:".concat(height, "px;"), "background:url(".concat(imageUrl, ");"), "background-size:".concat(width, "px ").concat(height, "px;"), 'color:transparent;'].join(''); - return ["".concat(message, " %c+"), style]; -} +class Loader { -const COLOR$1 = { - BLACK: 30, - RED: 31, - GREEN: 32, - YELLOW: 33, - BLUE: 34, - MAGENTA: 35, - CYAN: 36, - WHITE: 37, - BRIGHT_BLACK: 90, - BRIGHT_RED: 91, - BRIGHT_GREEN: 92, - BRIGHT_YELLOW: 93, - BRIGHT_BLUE: 94, - BRIGHT_MAGENTA: 95, - BRIGHT_CYAN: 96, - BRIGHT_WHITE: 97 -}; + constructor(manager) { -function getColor$1(color) { - return typeof color === 'string' ? COLOR$1[color.toUpperCase()] || COLOR$1.WHITE : color; -} + this.manager = (manager !== undefined) ? manager : DefaultLoadingManager; -function addColor$1(string, color, background) { - if (!isBrowser$1 && typeof string === 'string') { - if (color) { - color = getColor$1(color); - string = "\x1B[".concat(color, "m").concat(string, "\x1B[39m"); + this.crossOrigin = 'anonymous'; + this.withCredentials = false; + this.path = ''; + this.resourcePath = ''; + this.requestHeader = {}; } - if (background) { - color = getColor$1(background); - string = "\x1B[".concat(background + 10, "m").concat(string, "\x1B[49m"); + load( /* url, onLoad, onProgress, onError */) { } - } - - return string; -} - -function autobind$1(obj, predefined = ['constructor']) { - const proto = Object.getPrototypeOf(obj); - const propNames = Object.getOwnPropertyNames(proto); - for (const key of propNames) { - if (typeof obj[key] === 'function') { - if (!predefined.find(name => key === name)) { - obj[key] = obj[key].bind(obj); - } + loadAsync(url, onProgress) { + const scope = this; + return new Promise(function (resolve, reject) { + scope.load(url, resolve, onProgress, reject); + }); } - } -} - -function assert$3(condition, message) { - if (!condition) { - throw new Error(message || 'Assertion failed'); - } -} - -function getHiResTimestamp$1() { - let timestamp; - - if (isBrowser$1 && window_$1.performance) { - timestamp = window_$1.performance.now(); - } else if (process_$1.hrtime) { - const timeParts = process_$1.hrtime(); - timestamp = timeParts[0] * 1000 + timeParts[1] / 1e6; - } else { - timestamp = Date.now(); - } - return timestamp; -} + parse( /* data */) { + } -const originalConsole$1 = { - debug: isBrowser$1 ? console.debug || console.log : console.log, - log: console.log, - info: console.info, - warn: console.warn, - error: console.error -}; -const DEFAULT_SETTINGS$1 = { - enabled: true, - level: 0 -}; + setCrossOrigin(crossOrigin) { + this.crossOrigin = crossOrigin; + return this; + } -function noop$1() {} + setWithCredentials(value) { + this.withCredentials = value; + return this; + } -const cache$1 = {}; -const ONCE$1 = { - once: true -}; + setPath(path) { + this.path = path; + return this; + } -function getTableHeader$1(table) { - for (const key in table) { - for (const title in table[key]) { - return title || 'untitled'; + setResourcePath(resourcePath) { + this.resourcePath = resourcePath; + return this; } - } - return 'empty'; + setRequestHeader(requestHeader) { + this.requestHeader = requestHeader; + return this; + } } -class Log$1 { - constructor({ - id - } = { - id: '' - }) { - this.id = id; - this.VERSION = VERSION$7; - this._startTs = getHiResTimestamp$1(); - this._deltaTs = getHiResTimestamp$1(); - this.LOG_THROTTLE_TIMEOUT = 0; - this._storage = new LocalStorage$1("__probe-".concat(this.id, "__"), DEFAULT_SETTINGS$1); - this.userData = {}; - this.timeStamp("".concat(this.id, " started")); - autobind$1(this); - Object.seal(this); - } - - set level(newLevel) { - this.setLevel(newLevel); - } - - get level() { - return this.getLevel(); - } - - isEnabled() { - return this._storage.config.enabled; - } - - getLevel() { - return this._storage.config.level; - } +const loading = {}; - getTotal() { - return Number((getHiResTimestamp$1() - this._startTs).toPrecision(10)); - } +class FileLoader extends Loader { - getDelta() { - return Number((getHiResTimestamp$1() - this._deltaTs).toPrecision(10)); - } + constructor(manager) { + super(manager); + } - set priority(newPriority) { - this.level = newPriority; - } + load(url, onLoad, onProgress, onError) { + if (url === undefined) { + url = ''; + } + if (this.path !== undefined) { + url = this.path + url; + } + url = this.manager.resolveURL(url); + const cached = Cache.get(url); + if (cached !== undefined) { + this.manager.itemStart(url); + setTimeout(() => { + if (onLoad) { + onLoad(cached); + } + this.manager.itemEnd(url); + }, 0); + return cached; + } + if (loading[url] !== undefined) { + loading[url].push({onLoad, onProgress, onError}); + return; + } + loading[url] = []; + loading[url].push({onLoad, onProgress, onError}); + const req = new Request(url, { + headers: new Headers(this.requestHeader), + credentials: this.withCredentials ? 'include' : 'same-origin' + }); + const mimeType = this.mimeType; + const responseType = this.responseType; + fetch(req).then(response => { + if (response.status === 200 || response.status === 0) { + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. + if (response.status === 0) { + console.warn('FileLoader: HTTP Status 0 received.'); + } + if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) { + return response; + } + const callbacks = loading[url]; + const reader = response.body.getReader(); + const contentLength = response.headers.get('Content-Length'); + const total = contentLength ? parseInt(contentLength) : 0; + const lengthComputable = total !== 0; + let loaded = 0; + const stream = new ReadableStream({ + start(controller) { + readData(); - get priority() { - return this.level; - } + function readData() { + reader.read().then(({done, value}) => { + if (done) { + controller.close(); + } else { + loaded += value.byteLength; + const event = new ProgressEvent('progress', {lengthComputable, loaded, total}); + for (let i = 0, il = callbacks.length; i < il; i++) { + const callback = callbacks[i]; + if (callback.onProgress) { + callback.onProgress(event); + } + } + controller.enqueue(value); + readData(); + } + }); + } + } + }); + return new Response(stream); + } else { + throw Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`); + } + }).then(response => { + switch (responseType) { + case 'arraybuffer': + return response.arrayBuffer(); + case 'blob': + return response.blob(); + case 'document': + return response.text() + .then(text => { + const parser = new DOMParser(); + return parser.parseFromString(text, mimeType); + }); + case 'json': + return response.json(); + default: + if (mimeType === undefined) { + return response.text(); + } else { + // sniff encoding + const re = /charset="?([^;"\s]*)"?/i; + const exec = re.exec(mimeType); + const label = exec && exec[1] ? exec[1].toLowerCase() : undefined; + const decoder = new TextDecoder(label); + return response.arrayBuffer().then(ab => decoder.decode(ab)); + } + } + }).then(data => { + // Add to cache only on HTTP success, so that we do not cache + // error response bodies as proper responses to requests. + Cache.add(url, data); + const callbacks = loading[url]; + delete loading[url]; + for (let i = 0, il = callbacks.length; i < il; i++) { + const callback = callbacks[i]; + if (callback.onLoad) { + callback.onLoad(data); + } + } + }).catch(err => { + // Abort errors and other errors are handled the same + const callbacks = loading[url]; + if (callbacks === undefined) { + // When onLoad was called and url was deleted in `loading` + this.manager.itemError(url); + throw err; - getPriority() { - return this.level; - } + } + delete loading[url]; + for (let i = 0, il = callbacks.length; i < il; i++) { + const callback = callbacks[i]; + if (callback.onError) { + callback.onError(err); + } + } + this.manager.itemError(url); + }).finally(() => { + this.manager.itemEnd(url); + }); + this.manager.itemStart(url); + } - enable(enabled = true) { - this._storage.updateConfiguration({ - enabled - }); + setResponseType(value) { + this.responseType = value; + return this; + } - return this; - } + setMimeType(value) { + this.mimeType = value; + return this; + } +} - setLevel(level) { - this._storage.updateConfiguration({ - level - }); +/** + * @author Deepkolos / https://github.com/deepkolos + */ - return this; - } +class WorkerPool$1 { - assert(condition, message) { - assert$3(condition, message); - } + constructor(pool = 4) { + this.pool = pool; + this.queue = []; + this.workers = []; + this.workersResolve = []; + this.workerStatus = 0; + } - warn(message) { - return this._getLogFunction(0, message, originalConsole$1.warn, arguments, ONCE$1); - } + _initWorker(workerId) { + if (!this.workers[workerId]) { + const worker = this.workerCreator(); + worker.addEventListener('message', this._onMessage.bind(this, workerId)); + this.workers[workerId] = worker; + } + } - error(message) { - return this._getLogFunction(0, message, originalConsole$1.error, arguments); - } + _getIdleWorker() { + for (let i = 0; i < this.pool; i++) + if (!(this.workerStatus & (1 << i))) return i; + return -1; + } - deprecated(oldUsage, newUsage) { - return this.warn("`".concat(oldUsage, "` is deprecated and will be removed in a later version. Use `").concat(newUsage, "` instead")); - } + _onMessage(workerId, msg) { + const resolve = this.workersResolve[workerId]; + resolve && resolve(msg); + if (this.queue.length) { + const {resolve, msg, transfer} = this.queue.shift(); + this.workersResolve[workerId] = resolve; + this.workers[workerId].postMessage(msg, transfer); + } else { + this.workerStatus ^= 1 << workerId; + } + } - removed(oldUsage, newUsage) { - return this.error("`".concat(oldUsage, "` has been removed. Use `").concat(newUsage, "` instead")); - } + setWorkerCreator(workerCreator) { + this.workerCreator = workerCreator; + } - probe(logLevel, message) { - return this._getLogFunction(logLevel, message, originalConsole$1.log, arguments, { - time: true, - once: true - }); - } + setWorkerLimit(pool) { + this.pool = pool; + } - log(logLevel, message) { - return this._getLogFunction(logLevel, message, originalConsole$1.debug, arguments); - } + postMessage(msg, transfer) { + return new Promise((resolve) => { + const workerId = this._getIdleWorker(); + if (workerId !== -1) { + this._initWorker(workerId); + this.workerStatus |= 1 << workerId; + this.workersResolve[workerId] = resolve; + this.workers[workerId].postMessage(msg, transfer); + } else { + this.queue.push({resolve, msg, transfer}); + } + }); + } - info(logLevel, message) { - return this._getLogFunction(logLevel, message, console.info, arguments); - } + destroy() { - once(logLevel, message) { - return this._getLogFunction(logLevel, message, originalConsole$1.debug || originalConsole$1.info, arguments, ONCE$1); - } + this.workers.forEach((worker) => worker.terminate()); + this.workersResolve.length = 0; + this.workers.length = 0; + this.queue.length = 0; + this.workerStatus = 0; - table(logLevel, table, columns) { - if (table) { - return this._getLogFunction(logLevel, table, console.table || noop$1, columns && [columns], { - tag: getTableHeader$1(table) - }); } - return noop$1; - } +} - image({ - logLevel, - priority, - image, - message = '', - scale = 1 - }) { - if (!this._shouldLog(logLevel || priority)) { - return noop$1; - } +const KTX2TransferSRGB = 2; +const KTX2_ALPHA_PREMULTIPLIED = 1; - return isBrowser$1 ? logImageInBrowser$1({ - image, - message, - scale - }) : logImageInNode$1({ - image, - message, - scale - }); - } - - settings() { - if (console.table) { - console.table(this._storage.config); - } else { - console.log(this._storage.config); - } - } - - get(setting) { - return this._storage.config[setting]; - } - - set(setting, value) { - this._storage.updateConfiguration({ - [setting]: value - }); - } - - time(logLevel, message) { - return this._getLogFunction(logLevel, message, console.time ? console.time : console.info); - } - - timeEnd(logLevel, message) { - return this._getLogFunction(logLevel, message, console.timeEnd ? console.timeEnd : console.info); - } +let activeTranscoders = 0; - timeStamp(logLevel, message) { - return this._getLogFunction(logLevel, message, console.timeStamp || noop$1); - } +/** + * Transcodes texture data from KTX2. + * + * ## Overview + * + * * Uses the [Basis Universal GPU Texture Codec](https://github.com/BinomialLLC/basis_universal) to + * transcode [KTX2](https://github.khronos.org/KTX-Specification/) textures. + * * {@link XKTLoaderPlugin} uses a KTX2TextureTranscoder to load textures in XKT files. + * * {@link VBOSceneModel} uses a KTX2TextureTranscoder to enable us to add KTX2-encoded textures. + * * Loads the Basis Codec from [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/) by default, but can + * also be configured to load the Codec from local files. + * * We also bundle the Basis Codec with the xeokit-sdk npm package, and in the [repository](https://github.com/xeokit/xeokit-sdk/tree/master/dist/basis). + * + * ## What is KTX2? + * + * A [KTX2](https://github.khronos.org/KTX-Specification/) file stores GPU texture data in the Khronos Texture 2.0 (KTX2) container format. It contains image data for + * a texture asset compressed with Basis Universal (BasisU) supercompression that can be transcoded to different formats + * depending on the support provided by the target devices. KTX2 provides a lightweight format for distributing texture + * assets to GPUs. Due to BasisU compression, KTX2 files can store any image format supported by GPUs. + * + * ## Loading XKT files containing KTX2 textures + * + * {@link XKTLoaderPlugin} uses a KTX2TextureTranscoder to load textures in XKT files. An XKTLoaderPlugin has its own + * default KTX2TextureTranscoder, configured to load the Basis Codec from the [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/). If we wish, we can override that with our own + * KTX2TextureTranscoder, configured to load the Codec locally. + * + * In the example below, we'll create a {@link Viewer} and add an {@link XKTLoaderPlugin} + * configured with a KTX2TextureTranscoder. Then we'll use the XKTLoaderPlugin to load an + * XKT file that contains KTX2 textures, which the plugin will transcode using + * its KTX2TextureTranscoder. + * + * We'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. If we were happy with loading the + * Codec from our [CDN](https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/) (ie. our app will always have an Internet connection) then we could just leave out the + * KTX2TextureTranscoder altogether, and let the XKTLoaderPlugin use its internal default KTX2TextureTranscoder, which is configured to + * load the Codec from the CDN. We'll stick with loading our own Codec, in case we want to run our app without an Internet connection. + * + * + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan)] + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [-2.56, 8.38, 8.27]; + * viewer.camera.look = [13.44, 3.31, -14.83]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * const textureTranscoder = new KTX2TextureTranscoder({ + * viewer, + * transcoderPath: "./../dist/basis/" // <------ Path to Basis Universal transcoder + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer, { + * textureTranscoder // <<------------- Transcodes KTX2 textures in XKT files + * }); + * + * const sceneModel = xktLoader.load({ + * id: "myModel", + * src: "./HousePlan.xkt" // <<------ XKT file with KTX2 textures + * }); + * ```` + * + * ## Loading KTX2 files into a VBOSceneModel + * + * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will + * allow us to load textures into it from KTX2-transcoded buffers or files. + * + * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a + * KTX2TextureTranscoder. + * + * We'll then programmatically create a simple object within the VBOSceneModel, consisting of + * a single box mesh with a texture loaded from a KTX2 file, which our VBOSceneModel internally transcodes, using + * its KTX2TextureTranscoder. + * + * As in the previous example, we'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. + * + * * [Run a similar example](http://localhost:8080/examples/sceneRepresentation_VBOSceneModel_batching_textures_ktx2.html) + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; + * + * const textureTranscoder = new KTX2TextureTranscoder({ + * viewer, + * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module + * }); + * + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "myModel", + * textureTranscoder // <<-------------------- Configure model with our transcoder + * }); + * + * vboSceneModel.createTexture({ + * id: "myColorTexture", + * src: "../assets/textures/compressed/sample_uastc_zstd.ktx2" // <<----- KTX2 texture asset + * }); + * + * vboSceneModel.createTexture({ + * id: "myMetallicRoughnessTexture", + * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset + * }); + * + * vboSceneModel.createTextureSet({ + * id: "myTextureSet", + * colorTextureId: "myColorTexture", + * metallicRoughnessTextureId: "myMetallicRoughnessTexture" + * }); + * + * vboSceneModel.createMesh({ + * id: "myMesh", + * textureSetId: "myTextureSet", + * primitive: "triangles", + * positions: [1, 1, 1, ...], + * normals: [0, 0, 1, 0, ...], + * uv: [1, 0, 0, ...], + * indices: [0, 1, 2, ...], + * }); + * + * vboSceneModel.createEntity({ + * id: "myEntity", + * meshIds: ["myMesh"] + * }); + * + * vboSceneModel.finalize(); + * ```` + * + * ## Loading KTX2 ArrayBuffers into a VBOSceneModel + * + * A {@link SceneModel} that is configured with a KTX2TextureTranscoder will also allow us to load textures into + * it from KTX2 ArrayBuffers. + * + * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a + * KTX2TextureTranscoder. + * + * We'll then programmatically create a simple object within the VBOSceneModel, consisting of + * a single mesh with a texture loaded from a KTX2 ArrayBuffer, which our VBOSceneModel internally transcodes, using + * its KTX2TextureTranscoder. + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; + * + * const textureTranscoder = new KTX2TextureTranscoder({ + * viewer, + * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module + * }); + * + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "myModel", + * textureTranscoder // <<-------------------- Configure model with our transcoder + * }); + * + * utils.loadArraybuffer("../assets/textures/compressed/sample_uastc_zstd.ktx2",(arrayBuffer) => { + * + * vboSceneModel.createTexture({ + * id: "myColorTexture", + * buffers: [arrayBuffer] // <<----- KTX2 texture asset + * }); + * + * vboSceneModel.createTexture({ + * id: "myMetallicRoughnessTexture", + * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset + * }); + * + * vboSceneModel.createTextureSet({ + * id: "myTextureSet", + * colorTextureId: "myColorTexture", + * metallicRoughnessTextureId: "myMetallicRoughnessTexture" + * }); + * + * vboSceneModel.createMesh({ + * id: "myMesh", + * textureSetId: "myTextureSet", + * primitive: "triangles", + * positions: [1, 1, 1, ...], + * normals: [0, 0, 1, 0, ...], + * uv: [1, 0, 0, ...], + * indices: [0, 1, 2, ...], + * }); + * + * vboSceneModel.createEntity({ + * id: "myEntity", + * meshIds: ["myMesh"] + * }); + * + * vboSceneModel.finalize(); + * }); + * ```` + * + * @implements {TextureTranscoder} + */ +class KTX2TextureTranscoder { - group(logLevel, message, opts = { - collapsed: false - }) { - opts = normalizeArguments$1({ - logLevel, - message, - opts - }); - const { - collapsed - } = opts; - opts.method = (collapsed ? console.groupCollapsed : console.group) || console.info; - return this._getLogFunction(opts); - } + /** + * Creates a new KTX2TextureTranscoder. + * + * @param {Viewer} viewer The Viewer that our KTX2TextureTranscoder will be used with. This KTX2TextureTranscoder + * must only be used to transcode textures for this Viewer. This is because the Viewer's capabilities will decide + * what target GPU formats this KTX2TextureTranscoder will transcode to. + * @param {String} [transcoderPath="https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/"] Path to the Basis + * transcoder module that internally does the heavy lifting for our KTX2TextureTranscoder. If we omit this configuration, + * then our KTX2TextureTranscoder will load it from ````https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/```` by + * default. Therefore, make sure your application is connected to the internet if you wish to use the default transcoder path. + * @param {Number} [workerLimit] The maximum number of Workers to use for transcoding. + */ + constructor({viewer, transcoderPath, workerLimit}) { - groupCollapsed(logLevel, message, opts = {}) { - return this.group(logLevel, message, Object.assign({}, opts, { - collapsed: true - })); - } + this._transcoderPath = transcoderPath || "https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/"; + this._transcoderBinary = null; + this._transcoderPending = null; + this._workerPool = new WorkerPool$1(); + this._workerSourceURL = ''; - groupEnd(logLevel) { - return this._getLogFunction(logLevel, '', console.groupEnd || noop$1); - } + if (workerLimit) { + this._workerPool.setWorkerLimit(workerLimit); + } - withGroup(logLevel, message, func) { - this.group(logLevel, message)(); + const viewerCapabilities = viewer.capabilities; - try { - func(); - } finally { - this.groupEnd(logLevel)(); - } - } + this._workerConfig = { + astcSupported: viewerCapabilities.astcSupported, + etc1Supported: viewerCapabilities.etc1Supported, + etc2Supported: viewerCapabilities.etc2Supported, + dxtSupported: viewerCapabilities.dxtSupported, + bptcSupported: viewerCapabilities.bptcSupported, + pvrtcSupported: viewerCapabilities.pvrtcSupported + }; - trace() { - if (console.trace) { - console.trace(); + this._supportedFileTypes = ["xkt2"]; } - } - - _shouldLog(logLevel) { - return this.isEnabled() && this.getLevel() >= normalizeLogLevel$1(logLevel); - } - - _getLogFunction(logLevel, message, method, args = [], opts) { - if (this._shouldLog(logLevel)) { - opts = normalizeArguments$1({ - logLevel, - message, - args, - opts - }); - method = method || opts.method; - assert$3(method); - opts.total = this.getTotal(); - opts.delta = this.getDelta(); - this._deltaTs = getHiResTimestamp$1(); - const tag = opts.tag || opts.message; - if (opts.once) { - if (!cache$1[tag]) { - cache$1[tag] = getHiResTimestamp$1(); - } else { - return noop$1; + _init() { + if (!this._transcoderPending) { + const jsLoader = new FileLoader(); + jsLoader.setPath(this._transcoderPath); + jsLoader.setWithCredentials(this.withCredentials); + const jsContent = jsLoader.loadAsync('basis_transcoder.js'); + const binaryLoader = new FileLoader(); + binaryLoader.setPath(this._transcoderPath); + binaryLoader.setResponseType('arraybuffer'); + binaryLoader.setWithCredentials(this.withCredentials); + const binaryContent = binaryLoader.loadAsync('basis_transcoder.wasm'); + this._transcoderPending = Promise.all([jsContent, binaryContent]) + .then(([jsContent, binaryContent]) => { + const fn = KTX2TextureTranscoder.BasisWorker.toString(); + const body = [ + '/* constants */', + 'let _EngineFormat = ' + JSON.stringify(KTX2TextureTranscoder.EngineFormat), + 'let _TranscoderFormat = ' + JSON.stringify(KTX2TextureTranscoder.TranscoderFormat), + 'let _BasisFormat = ' + JSON.stringify(KTX2TextureTranscoder.BasisFormat), + '/* basis_transcoder.js */', + jsContent, + '/* worker */', + fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')) + ].join('\n'); + this._workerSourceURL = URL.createObjectURL(new Blob([body])); + this._transcoderBinary = binaryContent; + this._workerPool.setWorkerCreator(() => { + const worker = new Worker(this._workerSourceURL); + const transcoderBinary = this._transcoderBinary.slice(0); + worker.postMessage({ + type: 'init', + config: this._workerConfig, + transcoderBinary + }, [transcoderBinary]); + return worker; + }); + }); + if (activeTranscoders > 0) { + console.warn('KTX2TextureTranscoder: Multiple active KTX2TextureTranscoder may cause performance issues.' + ' Use a single KTX2TextureTranscoder instance, or call .dispose() on old instances.'); + } + activeTranscoders++; } - } - - message = decorateMessage$1(this.id, opts.message, opts); - return method.bind(console, message, ...opts.args); + return this._transcoderPending; } - return noop$1; - } - -} -Log$1.VERSION = VERSION$7; - -function normalizeLogLevel$1(logLevel) { - if (!logLevel) { - return 0; - } - - let resolvedLevel; - - switch (typeof logLevel) { - case 'number': - resolvedLevel = logLevel; - break; - - case 'object': - resolvedLevel = logLevel.logLevel || logLevel.priority || 0; - break; - - default: - return 0; - } - - assert$3(Number.isFinite(resolvedLevel) && resolvedLevel >= 0); - return resolvedLevel; -} - -function normalizeArguments$1(opts) { - const { - logLevel, - message - } = opts; - opts.logLevel = normalizeLogLevel$1(logLevel); - const args = opts.args ? Array.from(opts.args) : []; - - while (args.length && args.shift() !== message) {} - - opts.args = args; - - switch (typeof logLevel) { - case 'string': - case 'function': - if (message !== undefined) { - args.unshift(message); - } - - opts.message = logLevel; - break; - - case 'object': - Object.assign(opts, logLevel); - break; - } - - if (typeof opts.message === 'function') { - opts.message = opts.message(); - } - - const messageType = typeof opts.message; - assert$3(messageType === 'string' || messageType === 'object'); - return Object.assign(opts, opts.opts); -} - -function decorateMessage$1(id, message, opts) { - if (typeof message === 'string') { - const time = opts.time ? leftPad$1(formatTime$1(opts.total)) : ''; - message = opts.time ? "".concat(id, ": ").concat(time, " ").concat(message) : "".concat(id, ": ").concat(message); - message = addColor$1(message, opts.color, opts.background); - } - - return message; -} - -function logImageInNode$1({ - image, - message = '', - scale = 1 -}) { - let asciify = null; - - try { - asciify = module.require('asciify-image'); - } catch (error) {} - - if (asciify) { - return () => asciify(image, { - fit: 'box', - width: "".concat(Math.round(80 * scale), "%") - }).then(data => console.log(data)); - } - - return noop$1; -} - -function logImageInBrowser$1({ - image, - message = '', - scale = 1 -}) { - if (typeof image === 'string') { - const img = new Image(); - - img.onload = () => { - const args = formatImage$1(img, message, scale); - console.log(...args); - }; - - img.src = image; - return noop$1; - } - - const element = image.nodeName || ''; - - if (element.toLowerCase() === 'img') { - console.log(...formatImage$1(image, message, scale)); - return noop$1; - } - - if (element.toLowerCase() === 'canvas') { - const img = new Image(); - - img.onload = () => console.log(...formatImage$1(img, message, scale)); - - img.src = image.toDataURL(); - return noop$1; - } - - return noop$1; -} - -const probeLog = new Log$1({ - id: 'loaders.gl' -}); -class NullLog { - log() { - return () => {}; - } - - info() { - return () => {}; - } - - warn() { - return () => {}; - } - - error() { - return () => {}; - } - -} -class ConsoleLog { - constructor() { - _defineProperty(this, "console", void 0); - - this.console = console; - } - - log(...args) { - return this.console.log.bind(this.console, ...args); - } - - info(...args) { - return this.console.info.bind(this.console, ...args); - } - - warn(...args) { - return this.console.warn.bind(this.console, ...args); - } - - error(...args) { - return this.console.error.bind(this.console, ...args); - } + /** + * Transcodes texture data from transcoded buffers into a {@link Texture2D}. + * + * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support multi-image textures, such as cube maps. + * @param {*} config Transcoding options. + * @param {Texture2D} texture The texture to load. + * @returns {Promise} Resolves when the texture has loaded. + */ + transcode(buffers, texture, config = {}) { + return new Promise((resolve, reject) => { + const taskConfig = config; + this._init().then(() => { + return this._workerPool.postMessage({ + type: 'transcode', + buffers, + taskConfig: taskConfig + }, buffers); + }).then((e) => { + const transcodeResult = e.data; + const {mipmaps, width, height, format, type, error, dfdTransferFn, dfdFlags} = transcodeResult; + if (type === 'error') { + return reject(error); + } + texture.setCompressedData({ + mipmaps, + props: { + format: format, + minFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter, + magFilter: mipmaps.length === 1 ? LinearFilter : LinearMipmapLinearFilter, + encoding: dfdTransferFn === KTX2TransferSRGB ? sRGBEncoding : LinearEncoding, + premultiplyAlpha: !!(dfdFlags & KTX2_ALPHA_PREMULTIPLIED) + } + }); + resolve(); + }); + }); + } + /** + * Destroys this KTX2TextureTranscoder + */ + destroy() { + URL.revokeObjectURL(this._workerSourceURL); + this._workerPool.destroy(); + activeTranscoders--; + } } -const DEFAULT_LOADER_OPTIONS = { - fetch: null, - mimeType: undefined, - nothrow: false, - log: new ConsoleLog(), - CDN: 'https://unpkg.com/@loaders.gl', - worker: true, - maxConcurrency: 3, - maxMobileConcurrency: 1, - reuseWorkers: true, - _workerType: '', - limit: 0, - _limitMB: 0, - batchSize: 'auto', - batchDebounceMs: 0, - metadata: false, - transforms: [] -}; -const REMOVED_LOADER_OPTIONS = { - throws: 'nothrow', - dataType: '(no longer used)', - uri: 'baseUri', - method: 'fetch.method', - headers: 'fetch.headers', - body: 'fetch.body', - mode: 'fetch.mode', - credentials: 'fetch.credentials', - cache: 'fetch.cache', - redirect: 'fetch.redirect', - referrer: 'fetch.referrer', - referrerPolicy: 'fetch.referrerPolicy', - integrity: 'fetch.integrity', - keepalive: 'fetch.keepalive', - signal: 'fetch.signal' +/** + * @private + */ +KTX2TextureTranscoder.BasisFormat = { + ETC1S: 0, + UASTC_4x4: 1 }; -function getGlobalLoaderState() { - globalThis.loaders = globalThis.loaders || {}; - const { - loaders - } = globalThis; - loaders._state = loaders._state || {}; - return loaders._state; -} - -const getGlobalLoaderOptions = () => { - const state = getGlobalLoaderState(); - state.globalOptions = state.globalOptions || { ...DEFAULT_LOADER_OPTIONS - }; - return state.globalOptions; +/** + * @private + */ +KTX2TextureTranscoder.TranscoderFormat = { + ETC1: 0, + ETC2: 1, + BC1: 2, + BC3: 3, + BC4: 4, + BC5: 5, + BC7_M6_OPAQUE_ONLY: 6, + BC7_M5: 7, + PVRTC1_4_RGB: 8, + PVRTC1_4_RGBA: 9, + ASTC_4x4: 10, + ATC_RGB: 11, + ATC_RGBA_INTERPOLATED_ALPHA: 12, + RGBA32: 13, + RGB565: 14, + BGR565: 15, + RGBA4444: 16 }; -function normalizeOptions(options, loader, loaders, url) { - loaders = loaders || []; - loaders = Array.isArray(loaders) ? loaders : [loaders]; - validateOptions(options, loaders); - return normalizeOptionsInternal(loader, options, url); -} -function getFetchFunction(options, context) { - const globalOptions = getGlobalLoaderOptions(); - const fetchOptions = options || globalOptions; - - if (typeof fetchOptions.fetch === 'function') { - return fetchOptions.fetch; - } - - if (isObject(fetchOptions.fetch)) { - return url => fetchFile(url, fetchOptions); - } - if (context !== null && context !== void 0 && context.fetch) { - return context === null || context === void 0 ? void 0 : context.fetch; - } +/** + * @private + */ +KTX2TextureTranscoder.EngineFormat = { + RGBAFormat: RGBAFormat, + RGBA_ASTC_4x4_Format: RGBA_ASTC_4x4_Format, + RGBA_BPTC_Format: RGBA_BPTC_Format, + RGBA_ETC2_EAC_Format: RGBA_ETC2_EAC_Format, + RGBA_PVRTC_4BPPV1_Format: RGBA_PVRTC_4BPPV1_Format, + RGBA_S3TC_DXT5_Format: RGBA_S3TC_DXT5_Format, + RGB_ETC1_Format: RGB_ETC1_Format, + RGB_ETC2_Format: RGB_ETC2_Format, + RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format, + RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format +}; - return fetchFile; -} +/* WEB WORKER */ -function validateOptions(options, loaders) { - validateOptionsObject(options, null, DEFAULT_LOADER_OPTIONS, REMOVED_LOADER_OPTIONS, loaders); +/** + * @private + * @constructor + */ +KTX2TextureTranscoder.BasisWorker = function () { - for (const loader of loaders) { - const idOptions = options && options[loader.id] || {}; - const loaderOptions = loader.options && loader.options[loader.id] || {}; - const deprecatedOptions = loader.deprecatedOptions && loader.deprecatedOptions[loader.id] || {}; - validateOptionsObject(idOptions, loader.id, loaderOptions, deprecatedOptions, loaders); - } -} + let config; + let transcoderPending; + let BasisModule; -function validateOptionsObject(options, id, defaultOptions, deprecatedOptions, loaders) { - const loaderName = id || 'Top level'; - const prefix = id ? "".concat(id, ".") : ''; + const EngineFormat = _EngineFormat; // eslint-disable-line no-undef + const TranscoderFormat = _TranscoderFormat; // eslint-disable-line no-undef + const BasisFormat = _BasisFormat; // eslint-disable-line no-undef - for (const key in options) { - const isSubOptions = !id && isObject(options[key]); - const isBaseUriOption = key === 'baseUri' && !id; - const isWorkerUrlOption = key === 'workerUrl' && id; + self.addEventListener('message', function (e) { + const message = e.data; + switch (message.type) { + case 'init': + config = message.config; + init(message.transcoderBinary); + break; + case 'transcode': + transcoderPending.then(() => { + try { + const { + width, + height, + hasAlpha, + mipmaps, + format, + dfdTransferFn, + dfdFlags + } = transcode(message.buffers[0]); + const buffers = []; + for (let i = 0; i < mipmaps.length; ++i) { + buffers.push(mipmaps[i].data.buffer); + } + self.postMessage({ + type: 'transcode', + id: message.id, + width, + height, + hasAlpha, + mipmaps, + format, + dfdTransferFn, + dfdFlags + }, buffers); + } catch (error) { + console.error(`[KTX2TextureTranscoder.BasisWorker]: ${error}`); + self.postMessage({type: 'error', id: message.id, error: error.message}); + } + }); + break; + } + }); - if (!(key in defaultOptions) && !isBaseUriOption && !isWorkerUrlOption) { - if (key in deprecatedOptions) { - probeLog.warn("".concat(loaderName, " loader option '").concat(prefix).concat(key, "' no longer supported, use '").concat(deprecatedOptions[key], "'"))(); - } else if (!isSubOptions) { - const suggestion = findSimilarOption(key, loaders); - probeLog.warn("".concat(loaderName, " loader option '").concat(prefix).concat(key, "' not recognized. ").concat(suggestion))(); - } + function init(wasmBinary) { + transcoderPending = new Promise(resolve => { + BasisModule = { + wasmBinary, + onRuntimeInitialized: resolve + }; + BASIS(BasisModule); // eslint-disable-line no-undef + }).then(() => { + BasisModule.initializeBasis(); + if (BasisModule.KTX2File === undefined) { + console.warn('KTX2TextureTranscoder: Please update Basis Universal transcoder.'); + } + }); } - } -} - -function findSimilarOption(optionKey, loaders) { - const lowerCaseOptionKey = optionKey.toLowerCase(); - let bestSuggestion = ''; - for (const loader of loaders) { - for (const key in loader.options) { - if (optionKey === key) { - return "Did you mean '".concat(loader.id, ".").concat(key, "'?"); - } + function transcode(buffer) { + const ktx2File = new BasisModule.KTX2File(new Uint8Array(buffer)); - const lowerCaseKey = key.toLowerCase(); - const isPartialMatch = lowerCaseOptionKey.startsWith(lowerCaseKey) || lowerCaseKey.startsWith(lowerCaseOptionKey); + function cleanup() { + ktx2File.close(); + ktx2File.delete(); + } - if (isPartialMatch) { - bestSuggestion = bestSuggestion || "Did you mean '".concat(loader.id, ".").concat(key, "'?"); - } + if (!ktx2File.isValid()) { + cleanup(); + throw new Error('KTX2TextureTranscoder: Invalid or unsupported .ktx2 file'); + } + const basisFormat = ktx2File.isUASTC() ? BasisFormat.UASTC_4x4 : BasisFormat.ETC1S; + const width = ktx2File.getWidth(); + const height = ktx2File.getHeight(); + const levels = ktx2File.getLevels(); + const hasAlpha = ktx2File.getHasAlpha(); + const dfdTransferFn = ktx2File.getDFDTransferFunc(); + const dfdFlags = ktx2File.getDFDFlags(); + const {transcoderFormat, engineFormat} = getTranscoderFormat(basisFormat, width, height, hasAlpha); + if (!width || !height || !levels) { + cleanup(); + throw new Error('KTX2TextureTranscoder: Invalid texture'); + } + if (!ktx2File.startTranscoding()) { + cleanup(); + throw new Error('KTX2TextureTranscoder: .startTranscoding failed'); + } + const mipmaps = []; + for (let mip = 0; mip < levels; mip++) { + const levelInfo = ktx2File.getImageLevelInfo(mip, 0, 0); + const mipWidth = levelInfo.origWidth; + const mipHeight = levelInfo.origHeight; + const dst = new Uint8Array(ktx2File.getImageTranscodedSizeInBytes(mip, 0, 0, transcoderFormat)); + const status = ktx2File.transcodeImage(dst, mip, 0, 0, transcoderFormat, 0, -1, -1); + if (!status) { + cleanup(); + throw new Error('KTX2TextureTranscoder: .transcodeImage failed.'); + } + mipmaps.push({data: dst, width: mipWidth, height: mipHeight}); + } + cleanup(); + return {width, height, hasAlpha, mipmaps, format: engineFormat, dfdTransferFn, dfdFlags}; } - } - return bestSuggestion; -} + // Optimal choice of a transcoder target format depends on the Basis format (ETC1S or UASTC), + // device capabilities, and texture dimensions. The list below ranks the formats separately + // for ETC1S and UASTC. + // + // In some cases, transcoding UASTC to RGBA32 might be preferred for higher quality (at + // significant memory cost) compared to ETC1/2, BC1/3, and PVRTC. The transcoder currently + // chooses RGBA32 only as a last resort and does not expose that option to the caller. -function normalizeOptionsInternal(loader, options, url) { - const loaderDefaultOptions = loader.options || {}; - const mergedOptions = { ...loaderDefaultOptions - }; - addUrlOptions(mergedOptions, url); + const FORMAT_OPTIONS = [{ + if: 'astcSupported', + basisFormat: [BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ASTC_4x4, TranscoderFormat.ASTC_4x4], + engineFormat: [EngineFormat.RGBA_ASTC_4x4_Format, EngineFormat.RGBA_ASTC_4x4_Format], + priorityETC1S: Infinity, + priorityUASTC: 1, + needsPowerOfTwo: false + }, { + if: 'bptcSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.BC7_M5, TranscoderFormat.BC7_M5], + engineFormat: [EngineFormat.RGBA_BPTC_Format, EngineFormat.RGBA_BPTC_Format], + priorityETC1S: 3, + priorityUASTC: 2, + needsPowerOfTwo: false + }, { + if: 'dxtSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.BC1, TranscoderFormat.BC3], + engineFormat: [EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format], + priorityETC1S: 4, + priorityUASTC: 5, + needsPowerOfTwo: false + }, { + if: 'etc2Supported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ETC1, TranscoderFormat.ETC2], + engineFormat: [EngineFormat.RGB_ETC2_Format, EngineFormat.RGBA_ETC2_EAC_Format], + priorityETC1S: 1, + priorityUASTC: 3, + needsPowerOfTwo: false + }, { + if: 'etc1Supported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.ETC1], + engineFormat: [EngineFormat.RGB_ETC1_Format], + priorityETC1S: 2, + priorityUASTC: 4, + needsPowerOfTwo: false + }, { + if: 'pvrtcSupported', + basisFormat: [BasisFormat.ETC1S, BasisFormat.UASTC_4x4], + transcoderFormat: [TranscoderFormat.PVRTC1_4_RGB, TranscoderFormat.PVRTC1_4_RGBA], + engineFormat: [EngineFormat.RGB_PVRTC_4BPPV1_Format, EngineFormat.RGBA_PVRTC_4BPPV1_Format], + priorityETC1S: 5, + priorityUASTC: 6, + needsPowerOfTwo: true + }]; + const ETC1S_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { + return a.priorityETC1S - b.priorityETC1S; + }); + const UASTC_OPTIONS = FORMAT_OPTIONS.sort(function (a, b) { + return a.priorityUASTC - b.priorityUASTC; + }); - if (mergedOptions.log === null) { - mergedOptions.log = new NullLog(); - } + function getTranscoderFormat(basisFormat, width, height, hasAlpha) { + let transcoderFormat; + let engineFormat; + const options = basisFormat === BasisFormat.ETC1S ? ETC1S_OPTIONS : UASTC_OPTIONS; + for (let i = 0; i < options.length; i++) { + const opt = options[i]; + if (!config[opt.if]) continue; + if (!opt.basisFormat.includes(basisFormat)) continue; + if (hasAlpha && opt.transcoderFormat.length < 2) continue; + if (opt.needsPowerOfTwo && !(isPowerOfTwo(width) && isPowerOfTwo(height))) continue; + transcoderFormat = opt.transcoderFormat[hasAlpha ? 1 : 0]; + engineFormat = opt.engineFormat[hasAlpha ? 1 : 0]; + return { + transcoderFormat, + engineFormat + }; + } + console.warn('KTX2TextureTranscoder: No suitable compressed texture format found. Decoding to RGBA32.'); + transcoderFormat = TranscoderFormat.RGBA32; + engineFormat = EngineFormat.RGBAFormat; + return { + transcoderFormat, + engineFormat + }; + } - mergeNestedFields(mergedOptions, getGlobalLoaderOptions()); - mergeNestedFields(mergedOptions, options); - return mergedOptions; -} + function isPowerOfTwo(value) { + if (value <= 2) return true; + return (value & value - 1) === 0 && value !== 0; + } +}; -function mergeNestedFields(mergedOptions, options) { - for (const key in options) { - if (key in options) { - const value = options[key]; +const cachedTranscoders = {}; - if (isPureObject(value) && isPureObject(mergedOptions[key])) { - mergedOptions[key] = { ...mergedOptions[key], - ...options[key] - }; - } else { - mergedOptions[key] = options[key]; - } +/** + * Returns a new {@link KTX2TextureTranscoder}. + * + * The ````transcoderPath```` config will be set to: "https://cdn.jsdelivr.net/npm/@xeokit/xeokit-sdk/dist/basis/" + * + * @private + */ +function getKTX2TextureTranscoder(viewer) { + const sceneId = viewer.scene.id; + let transcoder = cachedTranscoders[sceneId]; + if (!transcoder) { + transcoder = new KTX2TextureTranscoder({viewer}); + cachedTranscoders[sceneId] = transcoder; + viewer.scene.on("destroyed", () => { + delete cachedTranscoders[sceneId]; + transcoder.destroy(); + }); } - } + return transcoder; } -function addUrlOptions(options, url) { - if (url && !('baseUri' in options)) { - options.baseUri = url; - } -} +const tempVec3a$8 = math.vec3(); +const tempMat4$1 = math.mat4(); -function isLoaderObject(loader) { - var _loader; +const defaultScale = math.vec3([1, 1, 1]); +const defaultPosition = math.vec3([0, 0, 0]); +const defaultRotation = math.vec3([0, 0, 0]); +const defaultQuaternion = math.identityQuaternion(); - if (!loader) { - return false; - } +const defaultColorTextureId = "defaultColorTexture"; +const defaultMetalRoughTextureId = "defaultMetalRoughTexture"; +const defaultNormalsTextureId = "defaultNormalsTexture"; +const defaultEmissiveTextureId = "defaultEmissiveTexture"; +const defaultOcclusionTextureId = "defaultOcclusionTexture"; +const defaultTextureSetId = "defaultTextureSet"; - if (Array.isArray(loader)) { - loader = loader[0]; - } - - const hasExtensions = Array.isArray((_loader = loader) === null || _loader === void 0 ? void 0 : _loader.extensions); - return hasExtensions; -} -function normalizeLoader(loader) { - var _loader2, _loader3; +/** + * @desc A high-performance model representation for efficient rendering and low memory usage. + * + * # Examples + * + * * [VBOSceneModel using geometry batching](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) + * * [VBOSceneModel using geometry batching and RTC coordinates](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching_origin) + * * [VBOSceneModel using geometry instancing](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing) + * * [VBOSceneModel using geometry instancing and RTC coordinates](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing_origin) + * + * # Overview + * + * While xeokit's standard [scene graph](https://github.com/xeokit/xeokit-sdk/wiki/Scene-Graphs) is great for gizmos and medium-sized models, it doesn't scale up to millions of objects in terms of memory and rendering efficiency. + * + * For huge models, we have the ````VBOSceneModel```` representation, which is optimized to pack large amounts of geometry into memory and render it efficiently using WebGL. + * + * ````VBOSceneModel```` is the default model representation loaded by (at least) {@link GLTFLoaderPlugin}, {@link XKTLoaderPlugin} and {@link WebIFCLoaderPlugin}. + * + * In this tutorial you'll learn how to use ````VBOSceneModel```` to create high-detail content programmatically. Ordinarily you'd be learning about ````VBOSceneModel```` if you were writing your own model loader plugins. + * + * # Contents + * + * - [VBOSceneModel](#performancemodel) + * - [GPU-Resident Geometry](#gpu-resident-geometry) + * - [Picking](#picking) + * - [Example 1: Geometry Instancing](#example-1--geometry-instancing) + * - [Finalizing a VBOSceneModel](#finalizing-a-performancemodel) + * - [Finding Entities](#finding-entities) + * - [Example 2: Geometry Batching](#example-2--geometry-batching) + * - [Classifying with Metadata](#classifying-with-metadata) + * - [Querying Metadata](#querying-metadata) + * - [Metadata Structure](#metadata-structure) + * - [RTC Coordinates](#rtc-coordinates-for-double-precision) + * - [Example 3: RTC Coordinates with Geometry Instancing](#example-2--rtc-coordinates-with-geometry-instancing) + * - [Example 4: RTC Coordinates with Geometry Batching](#example-2--rtc-coordinates-with-geometry-batching) + * + * ## VBOSceneModel + * + * ````VBOSceneModel```` uses two rendering techniques internally: + * + * 1. ***Geometry batching*** for unique geometries, combining those into a single WebGL geometry buffer, to render in one draw call, and + * 2. ***geometry instancing*** for geometries that are shared by multiple meshes, rendering all instances of each shared geometry in one draw call. + * + *
+ * These techniques come with certain limitations: + * + * * Non-realistic rendering - while scene graphs can use xeokit's full set of material workflows, ````VBOSceneModel```` uses simple Lambertian shading without textures. + * * Static transforms - transforms within a ````VBOSceneModel```` are static and cannot be dynamically translated, rotated and scaled the way {@link Node}s and {@link Mesh}es in scene graphs can. + * * Immutable model representation - while scene graph {@link Node}s and + * {@link Mesh}es can be dynamically plugged together, ````VBOSceneModel```` is immutable, + * since it packs its geometries into buffers and instanced arrays. + * + * ````VBOSceneModel````'s API allows us to exploit batching and instancing, while exposing its elements as + * abstract {@link Entity} types. + * + * {@link Entity} is the abstract base class for + * the various xeokit components that represent models, objects, or anonymous visible elements. An Entity has a unique ID and can be + * individually shown, hidden, selected, highlighted, ghosted, culled, picked and clipped, and has its own World-space boundary. + * + * * A ````VBOSceneModel```` is an {@link Entity} that represents a model. + * * A ````VBOSceneModel```` represents each of its objects with an {@link Entity}. + * * Each {@link Entity} has one or more meshes that define its shape. + * * Each mesh has either its own unique geometry, or shares a geometry with other meshes. + * + * ## GPU-Resident Geometry + * + * For a low memory footprint, ````VBOSceneModel```` stores its geometries in GPU memory only, compressed (quantized) as integers. Unfortunately, GPU-resident geometry is + * not readable by JavaScript. + * + * + * ## Example 1: Geometry Instancing + * + * In the example below, we'll use a ````VBOSceneModel```` + * to build a simple table model using geometry instancing. + * + * We'll start by adding a reusable box-shaped geometry to our ````VBOSceneModel````. + * + * Then, for each object in our model we'll add an {@link Entity} + * that has a mesh that instances our box geometry, transforming and coloring the instance. + * + * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing) + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing)] + * + * ````javascript + * import {Viewer, VBOSceneModel} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; + * + * // Build a VBOSceneModel representing a table + * // with four legs, using geometry instancing + * + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "table", + * isModel: true, // <--- Registers VBOSceneModel in viewer.scene.models + * position: [0, 0, 0], + * scale: [1, 1, 1], + * rotation: [0, 0, 0] + * }); + * + * // Create a reusable geometry within the VBOSceneModel + * // We'll instance this geometry by five meshes + * + * vboSceneModel.createGeometry({ + * + * id: "myBoxGeometry", + * + * // The primitive type - allowed values are "points", "lines" and "triangles". + * // See the OpenGL/WebGL specification docs + * // for how the coordinate arrays are supposed to be laid out. + * primitive: "triangles", + * + * // The vertices - eight for our cube, each + * // one spanning three array elements for X,Y and Z + * positions: [ + * 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // v0-v1-v2-v3 front + * 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // v0-v3-v4-v1 right + * 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // v0-v1-v6-v1 top + * -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // v1-v6-v7-v2 left + * -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, // v7-v4-v3-v2 bottom + * 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 // v4-v7-v6-v1 back + * ], + * + * // Normal vectors, one for each vertex + * normals: [ + * 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // v0-v1-v2-v3 front + * 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right + * 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // v0-v5-v6-v1 top + * -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, // v1-v6-v7-v2 left + * 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, // v7-v4-v3-v2 bottom + * 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1 // v4-v7-v6-v5 back + * ], + * + * // Indices - these organise the positions and and normals + * // into geometric primitives in accordance with the "primitive" parameter, + * // in this case a set of three indices for each triangle. + * // + * // Note that each triangle is specified in counter-clockwise winding order. + * // + * indices: [ + * 0, 1, 2, 0, 2, 3, // front + * 4, 5, 6, 4, 6, 7, // right + * 8, 9, 10, 8, 10, 11, // top + * 12, 13, 14, 12, 14, 15, // left + * 16, 17, 18, 16, 18, 19, // bottom + * 20, 21, 22, 20, 22, 23 + * ] + * }); + * + * // Red table leg + * + * vboSceneModel.createMesh({ + * id: "redLegMesh", + * geometryId: "myBoxGeometry", + * position: [-4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1, 0.3, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * id: "redLeg", + * meshIds: ["redLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Green table leg + * + * vboSceneModel.createMesh({ + * id: "greenLegMesh", + * geometryId: "myBoxGeometry", + * position: [4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 1.0, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * id: "greenLeg", + * meshIds: ["greenLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Blue table leg + * + * vboSceneModel.createMesh({ + * id: "blueLegMesh", + * geometryId: "myBoxGeometry", + * position: [4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * id: "blueLeg", + * meshIds: ["blueLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Yellow table leg + * + * vboSceneModel.createMesh({ + * id: "yellowLegMesh", + * geometryId: "myBoxGeometry", + * position: [-4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1.0, 1.0, 0.0] + * }); + * + * vboSceneModel.createEntity({ + * id: "yellowLeg", + * meshIds: ["yellowLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Purple table top + * + * vboSceneModel.createMesh({ + * id: "purpleTableTopMesh", + * geometryId: "myBoxGeometry", + * position: [0, -3, 0], + * scale: [6, 0.5, 6], + * rotation: [0, 0, 0], + * color: [1.0, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * id: "purpleTableTop", + * meshIds: ["purpleTableTopMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * ```` + * + * ## Finalizing a VBOSceneModel + * + * Before we can view and interact with our ````VBOSceneModel````, we need to **finalize** it. Internally, this causes the ````VBOSceneModel```` to build the + * vertex buffer objects (VBOs) that support our geometry instances. When using geometry batching (see next example), + * this causes ````VBOSceneModel```` to build the VBOs that combine the batched geometries. Note that you can do both instancing and + * batching within the same ````VBOSceneModel````. + * + * Once finalized, we can't add anything more to our ````VBOSceneModel````. + * + * ```` javascript + * vboSceneModel.finalize(); + * ```` + * + * ## Finding Entities + * + * As mentioned earlier, {@link Entity} is + * the abstract base class for components that represent models, objects, or just + * anonymous visible elements. + * + * Since we created configured our ````VBOSceneModel```` with ````isModel: true````, + * we're able to find it as an Entity by ID in ````viewer.scene.models````. Likewise, since + * we configured each of its Entities with ````isObject: true````, we're able to + * find them in ````viewer.scene.objects````. + * + * + * ````javascript + * // Get the whole table model Entity + * const table = viewer.scene.models["table"]; + * + * // Get some leg object Entities + * const redLeg = viewer.scene.objects["redLeg"]; + * const greenLeg = viewer.scene.objects["greenLeg"]; + * const blueLeg = viewer.scene.objects["blueLeg"]; + * ```` + * + * ## Example 2: Geometry Batching + * + * Let's once more use a ````VBOSceneModel```` + * to build the simple table model, this time exploiting geometry batching. + * + * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching)] + * + * ````javascript + * import {Viewer, VBOSceneModel} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; + * + * // Create a VBOSceneModel representing a table with four legs, using geometry batching + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "table", + * isModel: true, // <--- Registers VBOSceneModel in viewer.scene.models + * position: [0, 0, 0], + * scale: [1, 1, 1], + * rotation: [0, 0, 0] + * }); + * + * // Red table leg + * + * vboSceneModel.createMesh({ + * id: "redLegMesh", + * + * // Geometry arrays are same as for the earlier batching example + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [-4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1, 0.3, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * id: "redLeg", + * meshIds: ["redLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Green table leg + * + * vboSceneModel.createMesh({ + * id: "greenLegMesh", + * primitive: "triangles", + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 1.0, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * id: "greenLeg", + * meshIds: ["greenLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Blue table leg + * + * vboSceneModel.createMesh({ + * id: "blueLegMesh", + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * id: "blueLeg", + * meshIds: ["blueLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Yellow table leg object + * + * vboSceneModel.createMesh({ + * id: "yellowLegMesh", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [-4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1.0, 1.0, 0.0] + * }); + * + * vboSceneModel.createEntity({ + * id: "yellowLeg", + * meshIds: ["yellowLegMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Purple table top + * + * vboSceneModel.createMesh({ + * id: "purpleTableTopMesh", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [0, -3, 0], + * scale: [6, 0.5, 6], + * rotation: [0, 0, 0], + * color: [1.0, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * id: "purpleTableTop", + * meshIds: ["purpleTableTopMesh"], + * isObject: true // <---- Registers Entity by ID on viewer.scene.objects + * }); + * + * // Finalize the VBOSceneModel. + * + * vboSceneModel.finalize(); + * + * // Find BigModelNodes by their model and object IDs + * + * // Get the whole table model + * const table = viewer.scene.models["table"]; + * + * // Get some leg objects + * const redLeg = viewer.scene.objects["redLeg"]; + * const greenLeg = viewer.scene.objects["greenLeg"]; + * const blueLeg = viewer.scene.objects["blueLeg"]; + * ```` + * + * ## Classifying with Metadata + * + * In the previous examples, we used ````VBOSceneModel```` to build + * two versions of the same table model, to demonstrate geometry batching and geometry instancing. + * + * We'll now classify our {@link Entity}s with metadata. This metadata + * will work the same for both our examples, since they create the exact same structure of {@link Entity}s + * to represent their models and objects. The abstract Entity type is, after all, intended to provide an abstract interface through which differently-implemented scene content can be accessed uniformly. + * + * To create the metadata, we'll create a {@link MetaModel} for our model, + * with a {@link MetaObject} for each of it's objects. The MetaModel and MetaObjects + * get the same IDs as the {@link Entity}s that represent their model and objects within our scene. + * + * ```` javascript + * const furnitureMetaModel = viewer.metaScene.createMetaModel("furniture", { // Creates a MetaModel in the MetaScene + * + * "projectId": "myTableProject", + * "revisionId": "V1.0", + * + * "metaObjects": [ + * { // Creates a MetaObject in the MetaModel + * "id": "table", + * "name": "Table", // Same ID as an object Entity + * "type": "furniture", // Arbitrary type, could be IFC type + * "properties": { // Arbitrary properties, could be IfcPropertySet + * "cost": "200" + * } + * }, + * { + * "id": "redLeg", + * "name": "Red table Leg", + * "type": "leg", + * "parent": "table", // References first MetaObject as parent + * "properties": { + * "material": "wood" + * } + * }, + * { + * "id": "greenLeg", // Node with corresponding id does not need to exist + * "name": "Green table leg", // and MetaObject does not need to exist for Node with an id + * "type": "leg", + * "parent": "table", + * "properties": { + * "material": "wood" + * } + * }, + * { + * "id": "blueLeg", + * "name": "Blue table leg", + * "type": "leg", + * "parent": "table", + * "properties": { + * "material": "wood" + * } + * }, + * { + * "id": "yellowLeg", + * "name": "Yellow table leg", + * "type": "leg", + * "parent": "table", + * "properties": { + * "material": "wood" + * } + * }, + * { + * "id": "tableTop", + * "name": "Purple table top", + * "type": "surface", + * "parent": "table", + * "properties": { + * "material": "formica", + * "width": "60", + * "depth": "60", + * "thickness": "5" + * } + * } + * ] + * }); + * ```` + * + * ## Querying Metadata + * + * Having created and classified our model (either the instancing or batching example), we can now find the {@link MetaModel} + * and {@link MetaObject}s using the IDs of their + * corresponding {@link Entity}s. + * + * ````JavaScript + * const furnitureMetaModel = scene.metaScene.metaModels["furniture"]; + * + * const redLegMetaObject = scene.metaScene.metaObjects["redLeg"]; + * ```` + * + * In the snippet below, we'll log metadata on each {@link Entity} we click on: + * + * ````JavaScript + * viewer.scene.input.on("mouseclicked", function (coords) { + * + * const hit = viewer.scene.pick({ + * canvasPos: coords + * }); + * + * if (hit) { + * const entity = hit.entity; + * const metaObject = viewer.metaScene.metaObjects[entity.id]; + * if (metaObject) { + * console.log(JSON.stringify(metaObject.getJSON(), null, "\t")); + * } + * } + * }); + * ```` + * + * ## Metadata Structure + * + * The {@link MetaModel} + * organizes its {@link MetaObject}s in + * a tree that describes their structural composition: + * + * ````JavaScript + * // Get metadata on the root object + * const tableMetaObject = furnitureMetaModel.rootMetaObject; + * + * // Get metadata on the leg objects + * const redLegMetaObject = tableMetaObject.children[0]; + * const greenLegMetaObject = tableMetaObject.children[1]; + * const blueLegMetaObject = tableMetaObject.children[2]; + * const yellowLegMetaObject = tableMetaObject.children[3]; + * ```` + * + * Given an {@link Entity}, we can find the object or model of which it is a part, or the objects that comprise it. We can also generate UI + * components from the metadata, such as the tree view demonstrated in [this demo](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_glTF_OTCConferenceCenter). + * + * This hierarchy allows us to express the hierarchical structure of a model while representing it in + * various ways in the 3D scene (such as with ````VBOSceneModel````, which + * has a non-hierarchical scene representation). + * + * Note also that a {@link MetaObject} does not need to have a corresponding + * {@link Entity} and vice-versa. + * + * # RTC Coordinates for Double Precision + * + * ````VBOSceneModel```` can emulate 64-bit precision on GPUs using relative-to-center (RTC) coordinates. + * + * Consider a model that contains many small objects, but with such large spatial extents that 32 bits of GPU precision (accurate to ~7 digits) will not be sufficient to render all of the the objects without jittering. + * + * To prevent jittering, we could spatially subdivide the objects into "tiles". Each tile would have a center position, and the positions of the objects within the tile would be relative to that center ("RTC coordinates"). + * + * While the center positions of the tiles would be 64-bit values, the object positions only need to be 32-bit. + * + * Internally, when rendering an object with RTC coordinates, xeokit first temporarily translates the camera viewing matrix by the object's tile's RTC center, on the CPU, using 64-bit math. + * + * Then xeokit loads the viewing matrix into its WebGL shaders, where math happens at 32-bit precision. Within the shaders, the matrix is effectively down-cast to 32-bit precision, and the object's 32-bit vertex positions are transformed by the matrix. + * + * We see no jittering, because with RTC a detectable loss of GPU accuracy only starts happening to objects as they become very distant from the camera viewpoint, at which point they are too small to be discernible anyway. + * + * ## RTC Coordinates with Geometry Instancing + * + * To use RTC with ````VBOSceneModel```` geometry instancing, we specify an RTC center for the geometry via its ````origin```` parameter. Then ````VBOSceneModel```` assumes that all meshes that instance that geometry are within the same RTC coordinate system, ie. the meshes ````position```` and ````rotation```` properties are assumed to be relative to the geometry's ````origin````. + * + * For simplicity, our example's meshes all instance the same geometry. Therefore, our example model has only one RTC center. + * + * Note that the axis-aligned World-space boundary (AABB) of our model is ````[ -6, -9, -6, 1000000006, -2.5, 1000000006]````. + * + * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_instancing_origin)] + * + * ````javascript + * const origin = [100000000, 0, 100000000]; + * + * vboSceneModel.createGeometry({ + * id: "box", + * origin: origin, // This geometry's positions, and the transforms of all meshes that instance the geometry, are relative to the RTC center + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * }); + * + * vboSceneModel.createMesh({ + * id: "leg1", + * geometryId: "box", + * position: [-4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1, 0.3, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg1"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg2", + * geometryId: "box", + * position: [4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 1.0, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg2"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg3", + * geometryId: "box", + * position: [4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg3"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg4", + * geometryId: "box", + * position: [-4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1.0, 1.0, 0.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg4"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "top", + * geometryId: "box", + * position: [0, -3, 0], + * scale: [6, 0.5, 6], + * rotation: [0, 0, 0], + * color: [1.0, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["top"], + * isObject: true + * }); + * ```` + * + * ## RTC Coordinates with Geometry Batching + * + * To use RTC with ````VBOSceneModel```` geometry batching, we specify an RTC center (````origin````) for each mesh. For performance, we try to have as many meshes share the same value for ````origin```` as possible. Each mesh's ````positions````, ````position```` and ````rotation```` properties are assumed to be relative to ````origin````. + * + * For simplicity, the meshes in our example all share the same RTC center. + * + * The axis-aligned World-space boundary (AABB) of our model is ````[ -6, -9, -6, 1000000006, -2.5, 1000000006]````. + * + * [![](http://xeokit.io/img/docs/sceneGraph.png)](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching) + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_VBOSceneModel_batching_origin)] + * + * ````javascript + * const origin = [100000000, 0, 100000000]; + * + * vboSceneModel.createMesh({ + * id: "leg1", + * origin: origin, // This mesh's positions and transforms are relative to the RTC center + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [-4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1, 0.3, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg1"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg2", + * origin: origin, // This mesh's positions and transforms are relative to the RTC center + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 1.0, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg2"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg3", + * origin: origin, // This mesh's positions and transforms are relative to the RTC center + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg3"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg4", + * origin: origin, // This mesh's positions and transforms are relative to the RTC center + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [-4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1.0, 1.0, 0.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg4"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "top", + * origin: origin, // This mesh's positions and transforms are relative to the RTC center + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * position: [0, -3, 0], + * scale: [6, 0.5, 6], + * rotation: [0, 0, 0], + * color: [1.0, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["top"], + * isObject: true + * }); + * ```` + * + * ## Positioning at World-space coordinates + * + * To position a VBOSceneModel at given double-precision World coordinates, we can + * configure the ````origin```` of the VBOSceneModel itself. The ````origin```` is a double-precision + * 3D World-space position at which the VBOSceneModel will be located. + * + * Note that ````position```` is a single-precision offset relative to ````origin````. + * + * ````javascript + * const origin = [100000000, 0, 100000000]; + * + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "table", + * isModel: true, + * origin: origin, // Everything in this VBOSceneModel is relative to this RTC center + * position: [0, 0, 0], + * scale: [1, 1, 1], + * rotation: [0, 0, 0] + * }); + * + * vboSceneModel.createGeometry({ + * id: "box", + * primitive: "triangles", + * positions: [ 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1 ... ], + * normals: [ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, ... ], + * indices: [ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, ... ], + * }); + * + * vboSceneModel.createMesh({ + * id: "leg1", + * geometryId: "box", + * position: [-4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1, 0.3, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg1"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg2", + * geometryId: "box", + * position: [4, -6, -4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 1.0, 0.3] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg2"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg3", + * geometryId: "box", + * position: [4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [0.3, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg3"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "leg4", + * geometryId: "box", + * position: [-4, -6, 4], + * scale: [1, 3, 1], + * rotation: [0, 0, 0], + * color: [1.0, 1.0, 0.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["leg4"], + * isObject: true + * }); + * + * vboSceneModel.createMesh({ + * id: "top", + * geometryId: "box", + * position: [0, -3, 0], + * scale: [6, 0.5, 6], + * rotation: [0, 0, 0], + * color: [1.0, 0.3, 1.0] + * }); + * + * vboSceneModel.createEntity({ + * meshIds: ["top"], + * isObject: true + * }); + * ```` + * + * # Textures + * + * ## Loading KTX2 Texture Files into a VBOSceneModel + * + * A {@link VBOSceneModel} that is configured with a {@link KTX2TextureTranscoder} will + * allow us to load textures into it from KTX2 buffers or files. + * + * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a + * {@link KTX2TextureTranscoder}. We'll then programmatically create a simple object within the VBOSceneModel, consisting of + * a single mesh with a texture loaded from a KTX2 file, which our VBOSceneModel internally transcodes, using + * its {@link KTX2TextureTranscoder}. Note how we configure our {@link KTX2TextureTranscoder} with a path to the Basis Universal + * transcoder WASM module. + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; + * + * const textureTranscoder = new KTX2TextureTranscoder({ + * viewer, + * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module + * }); + * + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "myModel", + * textureTranscoder // <<-------------------- Configure model with our transcoder + * }); + * + * vboSceneModel.createTexture({ + * id: "myColorTexture", + * src: "../assets/textures/compressed/sample_uastc_zstd.ktx2" // <<----- KTX2 texture asset + * }); + * + * vboSceneModel.createTexture({ + * id: "myMetallicRoughnessTexture", + * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset + * }); + * + * vboSceneModel.createTextureSet({ + * id: "myTextureSet", + * colorTextureId: "myColorTexture", + * metallicRoughnessTextureId: "myMetallicRoughnessTexture" + * }); + * + * vboSceneModel.createMesh({ + * id: "myMesh", + * textureSetId: "myTextureSet", + * primitive: "triangles", + * positions: [1, 1, 1, ...], + * normals: [0, 0, 1, 0, ...], + * uv: [1, 0, 0, ...], + * indices: [0, 1, 2, ...], + * }); + * + * vboSceneModel.createEntity({ + * id: "myEntity", + * meshIds: ["myMesh"] + * }); + * + * vboSceneModel.finalize(); + * ```` + * + * ## Loading KTX2 Textures from ArrayBuffers into a VBOSceneModel + * + * A VBOSceneModel that is configured with a {@link KTX2TextureTranscoder} will allow us to load textures into + * it from KTX2 ArrayBuffers. + * + * In the example below, we'll create a {@link Viewer}, containing a {@link VBOSceneModel} configured with a + * {@link KTX2TextureTranscoder}. We'll then programmatically create a simple object within the VBOSceneModel, consisting of + * a single mesh with a texture loaded from a KTX2 ArrayBuffer, which our VBOSceneModel internally transcodes, using + * its {@link KTX2TextureTranscoder}. + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-21.80, 4.01, 6.56]; + * viewer.scene.camera.look = [0, -5.75, 0]; + * viewer.scene.camera.up = [0.37, 0.91, -0.11]; + * + * const textureTranscoder = new KTX2TextureTranscoder({ + * viewer, + * transcoderPath: "./../dist/basis/" // <------ Path to BasisU transcoder module + * }); + * + * const vboSceneModel = new VBOSceneModel(viewer.scene, { + * id: "myModel", + * textureTranscoder // <<-------------------- Configure model with our transcoder + * }); + * + * utils.loadArraybuffer("../assets/textures/compressed/sample_uastc_zstd.ktx2",(arrayBuffer) => { + * + * vboSceneModel.createTexture({ + * id: "myColorTexture", + * buffers: [arrayBuffer] // <<----- KTX2 texture asset + * }); + * + * vboSceneModel.createTexture({ + * id: "myMetallicRoughnessTexture", + * src: "../assets/textures/alpha/crosshatchAlphaMap.jpg" // <<----- JPEG texture asset + * }); + * + * vboSceneModel.createTextureSet({ + * id: "myTextureSet", + * colorTextureId: "myColorTexture", + * metallicRoughnessTextureId: "myMetallicRoughnessTexture" + * }); + * + * vboSceneModel.createMesh({ + * id: "myMesh", + * textureSetId: "myTextureSet", + * primitive: "triangles", + * positions: [1, 1, 1, ...], + * normals: [0, 0, 1, 0, ...], + * uv: [1, 0, 0, ...], + * indices: [0, 1, 2, ...], + * }); + * + * vboSceneModel.createEntity({ + * id: "myEntity", + * meshIds: ["myMesh"] + * }); + * + * vboSceneModel.finalize(); + * }); + * ```` + * + * @implements {Drawable} + * @implements {Entity} + * @implements {SceneModel} + */ +class VBOSceneModel extends Component { - assert$5(loader, 'null loader'); - assert$5(isLoaderObject(loader), 'invalid loader'); - let options; - - if (Array.isArray(loader)) { - options = loader[1]; - loader = loader[0]; - loader = { ...loader, - options: { ...loader.options, - ...options - } - }; - } - - if ((_loader2 = loader) !== null && _loader2 !== void 0 && _loader2.parseTextSync || (_loader3 = loader) !== null && _loader3 !== void 0 && _loader3.parseText) { - loader.text = true; - } - - if (!loader.text) { - loader.binary = true; - } - - return loader; -} + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. + * @param {*} [cfg] Configs + * @param {String} [cfg.id] Optional ID, unique among all components in the parent scene, generated automatically when omitted. + * @param {Boolean} [cfg.isModel] Specify ````true```` if this VBOSceneModel represents a model, in which case the VBOSceneModel will be registered by {@link VBOSceneModel#id} in {@link Scene#models} and may also have a corresponding {@link MetaModel} with matching {@link MetaModel#id}, registered by that ID in {@link MetaScene#metaModels}. + * @param {Number[]} [cfg.origin=[0,0,0]] World-space double-precision 3D origin. + * @param {Number[]} [cfg.position=[0,0,0]] Local, single-precision 3D position, relative to the origin parameter. + * @param {Number[]} [cfg.scale=[1,1,1]] Local scale. + * @param {Number[]} [cfg.rotation=[0,0,0]] Local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1] Local modelling transform matrix. Overrides the position, scale and rotation parameters. + * @param {Boolean} [cfg.visible=true] Indicates if the VBOSceneModel is initially visible. + * @param {Boolean} [cfg.culled=false] Indicates if the VBOSceneModel is initially culled from view. + * @param {Boolean} [cfg.pickable=true] Indicates if the VBOSceneModel is initially pickable. + * @param {Boolean} [cfg.clippable=true] Indicates if the VBOSceneModel is initially clippable. + * @param {Boolean} [cfg.collidable=true] Indicates if the VBOSceneModel is initially included in boundary calculations. + * @param {Boolean} [cfg.xrayed=false] Indicates if the VBOSceneModel is initially xrayed. + * @param {Boolean} [cfg.highlighted=false] Indicates if the VBOSceneModel is initially highlighted. + * @param {Boolean} [cfg.selected=false] Indicates if the VBOSceneModel is initially selected. + * @param {Boolean} [cfg.edges=false] Indicates if the VBOSceneModel's edges are initially emphasized. + * @param {Number[]} [cfg.colorize=[1.0,1.0,1.0]] VBOSceneModel's initial RGB colorize color, multiplies by the rendered fragment colors. + * @param {Number} [cfg.opacity=1.0] VBOSceneModel's initial opacity factor, multiplies by the rendered fragment alpha. + * @param {Number} [cfg.backfaces=false] When we set this ````true````, then we force rendering of backfaces for this VBOSceneModel. When + * we leave this ````false````, then we allow the Viewer to decide when to render backfaces. In that case, the + * Viewer will hide backfaces on watertight meshes, show backfaces on open meshes, and always show backfaces on meshes when we slice them open with {@link SectionPlane}s. + * @param {Boolean} [cfg.saoEnabled=true] Indicates if Scalable Ambient Obscurance (SAO) will apply to this VBOSceneModel. SAO is configured by the Scene's {@link SAO} component. + * @param {Boolean} [cfg.pbrEnabled=true] Indicates if physically-based rendering (PBR) will apply to the VBOSceneModel when {@link Scene#pbrEnabled} is ````true````. + * @param {Boolean} [cfg.colorTextureEnabled=true] Indicates if base color textures will be rendered for the VBOSceneModel when {@link Scene#colorTextureEnabled} is ````true````. + * @param {Number} [cfg.edgeThreshold=10] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. + * @param {Number} [cfg.maxGeometryBatchSize=50000000] Maximum geometry batch size, as number of vertices. This is optionally supplied + * to limit the size of the batched geometry arrays that VBOSceneModel internally creates for batched geometries. + * A lower value means less heap allocation/de-allocation while creating/loading batched geometries, but more draw calls and + * slower rendering speed. A high value means larger heap allocation/de-allocation while creating/loading, but less draw calls + * and faster rendering speed. It's recommended to keep this somewhere roughly between ````50000```` and ````50000000```. + * @param {TextureTranscoder} [cfg.textureTranscoder] Transcoder that will be used internally by {@link VBOSceneModel#createTexture} + * to convert transcoded texture data. Only required when we'll be providing transcoded data + * to {@link VBOSceneModel#createTexture}. We assume that all transcoded texture data added to a ````VBOSceneModel```` + * will then in a format supported by this transcoder. + */ + constructor(owner, cfg = {}) { -const getGlobalLoaderRegistry = () => { - const state = getGlobalLoaderState(); - state.loaderRegistry = state.loaderRegistry || []; - return state.loaderRegistry; -}; -function getRegisteredLoaders() { - return getGlobalLoaderRegistry(); -} + super(owner, cfg); -function isElectron(mockUserAgent) { - if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { - return true; - } + this._textureTranscoder = cfg.textureTranscoder || getKTX2TextureTranscoder(this.scene.viewer); - if (typeof process !== 'undefined' && typeof process.versions === 'object' && Boolean(process.versions.electron)) { - return true; - } + this._maxGeometryBatchSize = cfg.maxGeometryBatchSize; - const realUserAgent = typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent; - const userAgent = mockUserAgent || realUserAgent; + this._aabb = math.collapseAABB3(); + this._aabbDirty = false; + this._layerList = []; // For GL state efficiency when drawing, InstancingLayers are in first part, BatchingLayers are in second + this._nodeList = []; - if (userAgent && userAgent.indexOf('Electron') >= 0) { - return true; - } + this._lastOrigin = null; + this._lastPositionsDecodeMatrix = null; + this._lastNormals = null; - return false; -} + this._instancingLayers = {}; + this._currentBatchingLayers = {}; -function isBrowser() { - const isNode = typeof process === 'object' && String(process) === '[object process]' && !process.browser; - return !isNode || isElectron(); -} + this._scratchMemory = getScratchMemory(); -const globals = { - self: typeof self !== 'undefined' && self, - window: typeof window !== 'undefined' && window, - global: typeof global !== 'undefined' && global, - document: typeof document !== 'undefined' && document, - process: typeof process === 'object' && process -}; -const window_ = globals.window || globals.self || globals.global; -const process_ = globals.process || {}; + this._geometries = {}; + this._textures = {}; + this._textureSets = {}; + this._meshes = {}; + this._nodes = {}; -const VERSION$6 = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'untranspiled source'; -isBrowser(); + /** @private **/ + this.renderFlags = new RenderFlags(); -function getStorage(type) { - try { - const storage = window[type]; - const x = '__storage_test__'; - storage.setItem(x, x); - storage.removeItem(x); - return storage; - } catch (e) { - return null; - } -} + /** + * @private + */ + this.numGeometries = 0; // Number of geometries created with createGeometry() -class LocalStorage { - constructor(id) { - let defaultSettings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - let type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'sessionStorage'; + // These counts are used to avoid unnecessary render passes + // They are incremented or decremented exclusively by BatchingLayer and InstancingLayer - _defineProperty(this, "storage", void 0); + /** + * @private + */ + this.numPortions = 0; - _defineProperty(this, "id", void 0); + /** + * @private + */ + this.numVisibleLayerPortions = 0; - _defineProperty(this, "config", {}); + /** + * @private + */ + this.numTransparentLayerPortions = 0; - this.storage = getStorage(type); - this.id = id; - this.config = {}; - Object.assign(this.config, defaultSettings); + /** + * @private + */ + this.numXRayedLayerPortions = 0; - this._loadConfiguration(); - } + /** + * @private + */ + this.numHighlightedLayerPortions = 0; - getConfiguration() { - return this.config; - } + /** + * @private + */ + this.numSelectedLayerPortions = 0; - setConfiguration(configuration) { - this.config = {}; - return this.updateConfiguration(configuration); - } + /** + * @private + */ + this.numEdgesLayerPortions = 0; - updateConfiguration(configuration) { - Object.assign(this.config, configuration); + /** + * @private + */ + this.numPickableLayerPortions = 0; - if (this.storage) { - const serialized = JSON.stringify(this.config); - this.storage.setItem(this.id, serialized); - } + /** + * @private + */ + this.numClippableLayerPortions = 0; - return this; - } + /** + * @private + */ + this.numCulledLayerPortions = 0; - _loadConfiguration() { - let configuration = {}; + /** @private */ + this.numEntities = 0; - if (this.storage) { - const serializedConfiguration = this.storage.getItem(this.id); - configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {}; - } + /** @private */ + this._numTriangles = 0; - Object.assign(this.config, configuration); - return this; - } + /** @private */ + this._numLines = 0; -} + /** @private */ + this._numPoints = 0; -function formatTime(ms) { - let formatted; + this._edgeThreshold = cfg.edgeThreshold || 10; - if (ms < 10) { - formatted = "".concat(ms.toFixed(2), "ms"); - } else if (ms < 100) { - formatted = "".concat(ms.toFixed(1), "ms"); - } else if (ms < 1000) { - formatted = "".concat(ms.toFixed(0), "ms"); - } else { - formatted = "".concat((ms / 1000).toFixed(2), "s"); - } + // Build static matrix - return formatted; -} -function leftPad(string) { - let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 8; - const padLength = Math.max(length - string.length, 0); - return "".concat(' '.repeat(padLength)).concat(string); -} + this._origin = math.vec3(cfg.origin || [0, 0, 0]); + this._position = math.vec3(cfg.position || [0, 0, 0]); + this._rotation = math.vec3(cfg.rotation || [0, 0, 0]); + this._quaternion = math.vec4(cfg.quaternion || [0, 0, 0, 1]); + if (cfg.rotation) { + math.eulerToQuaternion(this._rotation, "XYZ", this._quaternion); + } + this._scale = math.vec3(cfg.scale || [1, 1, 1]); + this._worldMatrix = math.mat4(); + math.composeMat4(this._position, this._quaternion, this._scale, this._worldMatrix); + this._worldNormalMatrix = math.mat4(); + math.inverseMat4(this._worldMatrix, this._worldNormalMatrix); + math.transposeMat4(this._worldNormalMatrix); -function formatImage(image, message, scale) { - let maxWidth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 600; - const imageUrl = image.src.replace(/\(/g, '%28').replace(/\)/g, '%29'); + if (cfg.matrix || cfg.position || cfg.rotation || cfg.scale || cfg.quaternion) { + this._viewMatrix = math.mat4(); + this._viewNormalMatrix = math.mat4(); + this._viewMatrixDirty = true; + this._worldMatrixNonIdentity = true; + } - if (image.width > maxWidth) { - scale = Math.min(scale, maxWidth / image.width); - } + this._opacity = 1.0; + this._colorize = [1, 1, 1]; - const width = image.width * scale; - const height = image.height * scale; - const style = ['font-size:1px;', "padding:".concat(Math.floor(height / 2), "px ").concat(Math.floor(width / 2), "px;"), "line-height:".concat(height, "px;"), "background:url(".concat(imageUrl, ");"), "background-size:".concat(width, "px ").concat(height, "px;"), 'color:transparent;'].join(''); - return ["".concat(message, " %c+"), style]; -} + this._saoEnabled = (cfg.saoEnabled !== false); + this._pbrEnabled = (cfg.pbrEnabled !== false); + this._colorTextureEnabled = (cfg.colorTextureEnabled !== false); -let COLOR; + this._isModel = cfg.isModel; + if (this._isModel) { + this.scene._registerModel(this); + } -(function (COLOR) { - COLOR[COLOR["BLACK"] = 30] = "BLACK"; - COLOR[COLOR["RED"] = 31] = "RED"; - COLOR[COLOR["GREEN"] = 32] = "GREEN"; - COLOR[COLOR["YELLOW"] = 33] = "YELLOW"; - COLOR[COLOR["BLUE"] = 34] = "BLUE"; - COLOR[COLOR["MAGENTA"] = 35] = "MAGENTA"; - COLOR[COLOR["CYAN"] = 36] = "CYAN"; - COLOR[COLOR["WHITE"] = 37] = "WHITE"; - COLOR[COLOR["BRIGHT_BLACK"] = 90] = "BRIGHT_BLACK"; - COLOR[COLOR["BRIGHT_RED"] = 91] = "BRIGHT_RED"; - COLOR[COLOR["BRIGHT_GREEN"] = 92] = "BRIGHT_GREEN"; - COLOR[COLOR["BRIGHT_YELLOW"] = 93] = "BRIGHT_YELLOW"; - COLOR[COLOR["BRIGHT_BLUE"] = 94] = "BRIGHT_BLUE"; - COLOR[COLOR["BRIGHT_MAGENTA"] = 95] = "BRIGHT_MAGENTA"; - COLOR[COLOR["BRIGHT_CYAN"] = 96] = "BRIGHT_CYAN"; - COLOR[COLOR["BRIGHT_WHITE"] = 97] = "BRIGHT_WHITE"; -})(COLOR || (COLOR = {})); + this._onCameraViewMatrix = this.scene.camera.on("matrix", () => { + this._viewMatrixDirty = true; + }); -function getColor(color) { - return typeof color === 'string' ? COLOR[color.toUpperCase()] || COLOR.WHITE : color; -} + this._createDefaultTextureSet(); -function addColor(string, color, background) { - if (!isBrowser && typeof string === 'string') { - if (color) { - color = getColor(color); - string = "\x1B[".concat(color, "m").concat(string, "\x1B[39m"); + this.visible = cfg.visible; + this.culled = cfg.culled; + this.pickable = cfg.pickable; + this.clippable = cfg.clippable; + this.collidable = cfg.collidable; + this.castsShadow = cfg.castsShadow; + this.receivesShadow = cfg.receivesShadow; + this.xrayed = cfg.xrayed; + this.highlighted = cfg.highlighted; + this.selected = cfg.selected; + this.edges = cfg.edges; + this.colorize = cfg.colorize; + this.opacity = cfg.opacity; + this.backfaces = cfg.backfaces; } - if (background) { - color = getColor(background); - string = "\x1B[".concat(background + 10, "m").concat(string, "\x1B[49m"); + _createDefaultTextureSet() { + // Every VBOSceneModelMesh gets at least the default TextureSet, + // which contains empty default textures filled with color + const defaultColorTexture = new VBOSceneModelTexture({ + id: defaultColorTextureId, + texture: new Texture2D({ + gl: this.scene.canvas.gl, + preloadColor: [1, 1, 1, 1] // [r, g, b, a]}) + }) + }); + const defaultMetalRoughTexture = new VBOSceneModelTexture({ + id: defaultMetalRoughTextureId, + texture: new Texture2D({ + gl: this.scene.canvas.gl, + preloadColor: [0, 1, 1, 1] // [unused, roughness, metalness, unused] + }) + }); + const defaultNormalsTexture = new VBOSceneModelTexture({ + id: defaultNormalsTextureId, + texture: new Texture2D({ + gl: this.scene.canvas.gl, + preloadColor: [0, 0, 0, 0] // [x, y, z, unused] - these must be zeros + }) + }); + const defaultEmissiveTexture = new VBOSceneModelTexture({ + id: defaultEmissiveTextureId, + texture: new Texture2D({ + gl: this.scene.canvas.gl, + preloadColor: [0, 0, 0, 1] // [x, y, z, unused] + }) + }); + const defaultOcclusionTexture = new VBOSceneModelTexture({ + id: defaultOcclusionTextureId, + texture: new Texture2D({ + gl: this.scene.canvas.gl, + preloadColor: [1, 1, 1, 1] // [x, y, z, unused] + }) + }); + this._textures[defaultColorTextureId] = defaultColorTexture; + this._textures[defaultMetalRoughTextureId] = defaultMetalRoughTexture; + this._textures[defaultNormalsTextureId] = defaultNormalsTexture; + this._textures[defaultEmissiveTextureId] = defaultEmissiveTexture; + this._textures[defaultOcclusionTextureId] = defaultOcclusionTexture; + this._textureSets[defaultTextureSetId] = new VBOSceneModelTextureSet({ + id: defaultTextureSetId, + model: this, + colorTexture: defaultColorTexture, + metallicRoughnessTexture: defaultMetalRoughTexture, + normalsTexture: defaultNormalsTexture, + emissiveTexture: defaultEmissiveTexture, + occlusionTexture: defaultOcclusionTexture + }); } - } - - return string; -} -function autobind(obj) { - let predefined = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ['constructor']; - const proto = Object.getPrototypeOf(obj); - const propNames = Object.getOwnPropertyNames(proto); + //------------------------------------------------------------------------------------------------------------------ + // VBOSceneModel members + //------------------------------------------------------------------------------------------------------------------ - for (const key of propNames) { - if (typeof obj[key] === 'function') { - if (!predefined.find(name => key === name)) { - obj[key] = obj[key].bind(obj); - } + /** + * Returns true to indicate that this Component is a VBOSceneModel. + * @type {Boolean} + */ + get isPerformanceModel() { + return true; } - } -} - -function assert$2(condition, message) { - if (!condition) { - throw new Error(message || 'Assertion failed'); - } -} -function getHiResTimestamp() { - let timestamp; - - if (isBrowser && 'performance' in window_) { - var _window$performance, _window$performance$n; + /** + * Returns the {@link Entity}s in this VBOSceneModel. + * @returns {*|{}} + */ + get objects() { + return this._nodes; + } - timestamp = window_ === null || window_ === void 0 ? void 0 : (_window$performance = window_.performance) === null || _window$performance === void 0 ? void 0 : (_window$performance$n = _window$performance.now) === null || _window$performance$n === void 0 ? void 0 : _window$performance$n.call(_window$performance); - } else if ('hrtime' in process_) { - var _process$hrtime; + /** + * Gets the 3D World-space origin for this VBOSceneModel. + * + * Each geometry or mesh origin, if supplied, is relative to this origin. + * + * Default value is ````[0,0,0]````. + * + * @type {Float64Array} + * @abstract + */ + get origin() { + return this._origin; + } - const timeParts = process_ === null || process_ === void 0 ? void 0 : (_process$hrtime = process_.hrtime) === null || _process$hrtime === void 0 ? void 0 : _process$hrtime.call(process_); - timestamp = timeParts[0] * 1000 + timeParts[1] / 1e6; - } else { - timestamp = Date.now(); - } + /** + * Gets the VBOSceneModel's local translation. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + */ + get position() { + return this._position; + } - return timestamp; -} + /** + * Gets the VBOSceneModel's local rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * + * Default value is ````[0,0,0]````. + * + * @type {Number[]} + */ + get rotation() { + return this._rotation; + } -const originalConsole = { - debug: isBrowser ? console.debug || console.log : console.log, - log: console.log, - info: console.info, - warn: console.warn, - error: console.error -}; -const DEFAULT_SETTINGS = { - enabled: true, - level: 0 -}; + /** + * Gets the PerformanceModels's local rotation quaternion. + * + * Default value is ````[0,0,0,1]````. + * + * @type {Number[]} + */ + get quaternion() { + return this._quaternion; + } -function noop() {} + /** + * Gets the VBOSceneModel's local scale. + * + * Default value is ````[1,1,1]````. + * + * @type {Number[]} + */ + get scale() { + return this._scale; + } -const cache = {}; -const ONCE = { - once: true -}; -class Log { - constructor() { - let { - id - } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { - id: '' - }; + /** + * Gets the VBOSceneModel's local modeling transform matrix. + * + * Default value is ````[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]````. + * + * @type {Number[]} + */ + get matrix() { + return this._worldMatrix; + } - _defineProperty(this, "id", void 0); + /** + * Gets the VBOSceneModel's World matrix. + * + * @property worldMatrix + * @type {Number[]} + */ + get worldMatrix() { + return this._worldMatrix; + } - _defineProperty(this, "VERSION", VERSION$6); + /** + * Gets the VBOSceneModel's World normal matrix. + * + * @type {Number[]} + */ + get worldNormalMatrix() { + return this._worldNormalMatrix; + } - _defineProperty(this, "_startTs", getHiResTimestamp()); + /** + * Called by private renderers in ./lib, returns the view matrix with which to + * render this VBOSceneModel. The view matrix is the concatenation of the + * Camera view matrix with the Performance model's world (modeling) matrix. + * + * @private + */ + get viewMatrix() { + if (!this._viewMatrix) { + return this.scene.camera.viewMatrix; + } + if (this._viewMatrixDirty) { + math.mulMat4(this.scene.camera.viewMatrix, this._worldMatrix, this._viewMatrix); + math.inverseMat4(this._viewMatrix, this._viewNormalMatrix); + math.transposeMat4(this._viewNormalMatrix); + this._viewMatrixDirty = false; + } + return this._viewMatrix; + } - _defineProperty(this, "_deltaTs", getHiResTimestamp()); + /** + * Called by private renderers in ./lib, returns the view normal matrix with which to render this VBOSceneModel. + * + * @private + */ + get viewNormalMatrix() { + if (!this._viewNormalMatrix) { + return this.scene.camera.viewNormalMatrix; + } + if (this._viewMatrixDirty) { + math.mulMat4(this.scene.camera.viewMatrix, this._worldMatrix, this._viewMatrix); + math.inverseMat4(this._viewMatrix, this._viewNormalMatrix); + math.transposeMat4(this._viewNormalMatrix); + this._viewMatrixDirty = false; + } + return this._viewNormalMatrix; + } - _defineProperty(this, "_storage", void 0); + /** + * Sets if backfaces are rendered for this VBOSceneModel. + * + * Default is ````false````. + * + * @type {Boolean} + */ + get backfaces() { + return this._backfaces; + } - _defineProperty(this, "userData", {}); + /** + * Sets if backfaces are rendered for this VBOSceneModel. + * + * Default is ````false````. + * + * When we set this ````true````, then backfaces are always rendered for this VBOSceneModel. + * + * When we set this ````false````, then we allow the Viewer to decide whether to render backfaces. In this case, + * the Viewer will: + * + * * hide backfaces on watertight meshes, + * * show backfaces on open meshes, and + * * always show backfaces on meshes when we slice them open with {@link SectionPlane}s. + * + * @type {Boolean} + */ + set backfaces(backfaces) { + backfaces = !!backfaces; + this._backfaces = backfaces; + this.glRedraw(); + } - _defineProperty(this, "LOG_THROTTLE_TIMEOUT", 0); + /** + * Gets the list of {@link Entity}s within this VBOSceneModel. + * + * @returns {Entity[]} + */ + get entityList() { + return this._nodeList; + } - this.id = id; - this._storage = new LocalStorage("__probe-".concat(this.id, "__"), DEFAULT_SETTINGS); - this.userData = {}; - this.timeStamp("".concat(this.id, " started")); - autobind(this); - Object.seal(this); - } + /** + * Returns true to indicate that VBOSceneModel is an {@link Entity}. + * @type {Boolean} + */ + get isEntity() { + return true; + } - set level(newLevel) { - this.setLevel(newLevel); - } + /** + * Returns ````true```` if this VBOSceneModel represents a model. + * + * When ````true```` the VBOSceneModel will be registered by {@link VBOSceneModel#id} in + * {@link Scene#models} and may also have a {@link MetaObject} with matching {@link MetaObject#id}. + * + * @type {Boolean} + */ + get isModel() { + return this._isModel; + } - get level() { - return this.getLevel(); - } + //------------------------------------------------------------------------------------------------------------------ + // VBOSceneModel members + //------------------------------------------------------------------------------------------------------------------ - isEnabled() { - return this._storage.config.enabled; - } + /** + * Returns ````false```` to indicate that VBOSceneModel never represents an object. + * + * @type {Boolean} + */ + get isObject() { + return false; + } - getLevel() { - return this._storage.config.level; - } + /** + * Gets the VBOSceneModel's World-space 3D axis-aligned bounding box. + * + * Represented by a six-element Float64Array containing the min/max extents of the + * axis-aligned volume, ie. ````[xmin, ymin,zmin,xmax,ymax, zmax]````. + * + * @type {Number[]} + */ + get aabb() { + if (this._aabbDirty) { + this._rebuildAABB(); + } + return this._aabb; + } - getTotal() { - return Number((getHiResTimestamp() - this._startTs).toPrecision(10)); - } + /** + * The approximate number of triangle primitives in this VBOSceneModel. + * + * @type {Number} + */ + get numTriangles() { + return this._numTriangles; + } - getDelta() { - return Number((getHiResTimestamp() - this._deltaTs).toPrecision(10)); - } + //------------------------------------------------------------------------------------------------------------------ + // Entity members + //------------------------------------------------------------------------------------------------------------------ - set priority(newPriority) { - this.level = newPriority; - } + /** + * The approximate number of line primitives in this VBOSceneModel. + * + * @type {Number} + */ + get numLines() { + return this._numLines; + } - get priority() { - return this.level; - } + /** + * The approximate number of point primitives in this VBOSceneModel. + * + * @type {Number} + */ + get numPoints() { + return this._numPoints; + } - getPriority() { - return this.level; - } + /** + * Gets if any {@link Entity}s in this VBOSceneModel are visible. + * + * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is ````true```` and {@link VBOSceneModel#culled} is ````false````. + * + * @type {Boolean} + */ + get visible() { + return (this.numVisibleLayerPortions > 0); + } - enable() { - let enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + /** + * Sets if this VBOSceneModel is visible. + * + * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is ````true```` and {@link VBOSceneModel#culled} is ````false````. + ** + * @type {Boolean} + */ + set visible(visible) { + visible = visible !== false; + this._visible = visible; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].visible = visible; + } + this.glRedraw(); + } - this._storage.updateConfiguration({ - enabled - }); + /** + * Gets if any {@link Entity}s in this VBOSceneModel are xrayed. + * + * @type {Boolean} + */ + get xrayed() { + return (this.numXRayedLayerPortions > 0); + } - return this; - } + /** + * Sets if all {@link Entity}s in this VBOSceneModel are xrayed. + * + * @type {Boolean} + */ + set xrayed(xrayed) { + xrayed = !!xrayed; + this._xrayed = xrayed; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].xrayed = xrayed; + } + this.glRedraw(); + } - setLevel(level) { - this._storage.updateConfiguration({ - level - }); + /** + * Gets if any {@link Entity}s in this VBOSceneModel are highlighted. + * + * @type {Boolean} + */ + get highlighted() { + return (this.numHighlightedLayerPortions > 0); + } - return this; - } + /** + * Sets if all {@link Entity}s in this VBOSceneModel are highlighted. + * + * @type {Boolean} + */ + set highlighted(highlighted) { + highlighted = !!highlighted; + this._highlighted = highlighted; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].highlighted = highlighted; + } + this.glRedraw(); + } - get(setting) { - return this._storage.config[setting]; - } + /** + * Gets if any {@link Entity}s in this VBOSceneModel are selected. + * + * @type {Boolean} + */ + get selected() { + return (this.numSelectedLayerPortions > 0); + } - set(setting, value) { - this._storage.updateConfiguration({ - [setting]: value - }); - } + /** + * Sets if all {@link Entity}s in this VBOSceneModel are selected. + * + * @type {Boolean} + */ + set selected(selected) { + selected = !!selected; + this._selected = selected; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].selected = selected; + } + this.glRedraw(); + } - settings() { - if (console.table) { - console.table(this._storage.config); - } else { - console.log(this._storage.config); + /** + * Gets if any {@link Entity}s in this VBOSceneModel have edges emphasised. + * + * @type {Boolean} + */ + get edges() { + return (this.numEdgesLayerPortions > 0); } - } - assert(condition, message) { - assert$2(condition, message); - } + /** + * Sets if all {@link Entity}s in this VBOSceneModel have edges emphasised. + * + * @type {Boolean} + */ + set edges(edges) { + edges = !!edges; + this._edges = edges; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].edges = edges; + } + this.glRedraw(); + } - warn(message) { - return this._getLogFunction(0, message, originalConsole.warn, arguments, ONCE); - } + /** + * Gets if this VBOSceneModel is culled from view. + * + * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is true and {@link VBOSceneModel#culled} is false. + * + * @type {Boolean} + */ + get culled() { + return this._culled; + } - error(message) { - return this._getLogFunction(0, message, originalConsole.error, arguments); - } + /** + * Sets if this VBOSceneModel is culled from view. + * + * The VBOSceneModel is only rendered when {@link VBOSceneModel#visible} is true and {@link VBOSceneModel#culled} is false. + * + * @type {Boolean} + */ + set culled(culled) { + culled = !!culled; + this._culled = culled; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].culled = culled; + } + this.glRedraw(); + } - deprecated(oldUsage, newUsage) { - return this.warn("`".concat(oldUsage, "` is deprecated and will be removed in a later version. Use `").concat(newUsage, "` instead")); - } + /** + * Gets if {@link Entity}s in this VBOSceneModel are clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * @type {Boolean} + */ + get clippable() { + return this._clippable; + } - removed(oldUsage, newUsage) { - return this.error("`".concat(oldUsage, "` has been removed. Use `").concat(newUsage, "` instead")); - } + /** + * Sets if {@link Entity}s in this VBOSceneModel are clippable. + * + * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. + * + * @type {Boolean} + */ + set clippable(clippable) { + clippable = clippable !== false; + this._clippable = clippable; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].clippable = clippable; + } + this.glRedraw(); + } - probe(logLevel, message) { - return this._getLogFunction(logLevel, message, originalConsole.log, arguments, { - time: true, - once: true - }); - } + /** + * Gets if this VBOSceneModel is collidable. + * + * @type {Boolean} + */ + get collidable() { + return this._collidable; + } - log(logLevel, message) { - return this._getLogFunction(logLevel, message, originalConsole.debug, arguments); - } + /** + * Sets if {@link Entity}s in this VBOSceneModel are collidable. + * + * @type {Boolean} + */ + set collidable(collidable) { + collidable = collidable !== false; + this._collidable = collidable; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].collidable = collidable; + } + } - info(logLevel, message) { - return this._getLogFunction(logLevel, message, console.info, arguments); - } + /** + * Gets if this VBOSceneModel is pickable. + * + * Picking is done via calls to {@link Scene#pick}. + * + * @type {Boolean} + */ + get pickable() { + return (this.numPickableLayerPortions > 0); + } - once(logLevel, message) { - for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { - args[_key - 2] = arguments[_key]; + /** + * Sets if {@link Entity}s in this VBOSceneModel are pickable. + * + * Picking is done via calls to {@link Scene#pick}. + * + * @type {Boolean} + */ + set pickable(pickable) { + pickable = pickable !== false; + this._pickable = pickable; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].pickable = pickable; + } } - return this._getLogFunction(logLevel, message, originalConsole.debug || originalConsole.info, arguments, ONCE); - } + /** + * Gets the RGB colorize color for this VBOSceneModel. + * + * Each element of the color is in range ````[0..1]````. + * + * @type {Number[]} + */ + get colorize() { + return this._colorize; + } - table(logLevel, table, columns) { - if (table) { - return this._getLogFunction(logLevel, table, console.table || noop, columns && [columns], { - tag: getTableHeader(table) - }); + /** + * Sets the RGB colorize color for this VBOSceneModel. + * + * Multiplies by rendered fragment colors. + * + * Each element of the color is in range ````[0..1]````. + * + * @type {Number[]} + */ + set colorize(colorize) { + this._colorize = colorize; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].colorize = colorize; + } } - return noop; - } + /** + * Gets this VBOSceneModel's opacity factor. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + get opacity() { + return this._opacity; + } - image(_ref) { - let { - logLevel, - priority, - image, - message = '', - scale = 1 - } = _ref; + /** + * Sets the opacity factor for this VBOSceneModel. + * + * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. + * + * @type {Number} + */ + set opacity(opacity) { + this._opacity = opacity; + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i].opacity = opacity; + } + } - if (!this._shouldLog(logLevel || priority)) { - return noop; + /** + * Gets if this VBOSceneModel casts a shadow. + * + * @type {Boolean} + */ + get castsShadow() { + return this._castsShadow; } - return isBrowser ? logImageInBrowser({ - image, - message, - scale - }) : logImageInNode({ - image, - message, - scale - }); - } + /** + * Sets if this VBOSceneModel casts a shadow. + * + * @type {Boolean} + */ + set castsShadow(castsShadow) { + castsShadow = (castsShadow !== false); + if (castsShadow !== this._castsShadow) { + this._castsShadow = castsShadow; + this.glRedraw(); + } + } - time(logLevel, message) { - return this._getLogFunction(logLevel, message, console.time ? console.time : console.info); - } + /** + * Sets if this VBOSceneModel can have shadow cast upon it. + * + * @type {Boolean} + */ + get receivesShadow() { + return this._receivesShadow; + } - timeEnd(logLevel, message) { - return this._getLogFunction(logLevel, message, console.timeEnd ? console.timeEnd : console.info); - } + /** + * Sets if this VBOSceneModel can have shadow cast upon it. + * + * @type {Boolean} + */ + set receivesShadow(receivesShadow) { + receivesShadow = (receivesShadow !== false); + if (receivesShadow !== this._receivesShadow) { + this._receivesShadow = receivesShadow; + this.glRedraw(); + } + } - timeStamp(logLevel, message) { - return this._getLogFunction(logLevel, message, console.timeStamp || noop); - } + /** + * Gets if Scalable Ambient Obscurance (SAO) will apply to this VBOSceneModel. + * + * SAO is configured by the Scene's {@link SAO} component. + * + * Only works when {@link SAO#enabled} is also true. + * + * @type {Boolean} + */ + get saoEnabled() { + return this._saoEnabled; + } - group(logLevel, message) { - let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { - collapsed: false - }; - const options = normalizeArguments({ - logLevel, - message, - opts - }); - const { - collapsed - } = opts; - options.method = (collapsed ? console.groupCollapsed : console.group) || console.info; - return this._getLogFunction(options); - } + /** + * Gets if physically-based rendering (PBR) is enabled for this VBOSceneModel. + * + * Only works when {@link Scene#pbrEnabled} is also true. + * + * @type {Boolean} + */ + get pbrEnabled() { + return this._pbrEnabled; + } - groupCollapsed(logLevel, message) { - let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - return this.group(logLevel, message, Object.assign({}, opts, { - collapsed: true - })); - } + /** + * Gets if color textures are enabled for this VBOSceneModel. + * + * Only works when {@link Scene#colorTextureEnabled} is also true. + * + * @type {Boolean} + */ + get colorTextureEnabled() { + return this._colorTextureEnabled; + } - groupEnd(logLevel) { - return this._getLogFunction(logLevel, '', console.groupEnd || noop); - } + /** + * Returns true to indicate that VBOSceneModel is implements {@link Drawable}. + * + * @type {Boolean} + */ + get isDrawable() { + return true; + } - withGroup(logLevel, message, func) { - this.group(logLevel, message)(); + /** @private */ + get isStateSortable() { + return false + } - try { - func(); - } finally { - this.groupEnd(logLevel)(); + /** + * Configures the appearance of xrayed {@link Entity}s within this VBOSceneModel. + * + * This is the {@link Scene#xrayMaterial}. + * + * @type {EmphasisMaterial} + */ + get xrayMaterial() { + return this.scene.xrayMaterial; } - } - trace() { - if (console.trace) { - console.trace(); + /** + * Configures the appearance of highlighted {@link Entity}s within this VBOSceneModel. + * + * This is the {@link Scene#highlightMaterial}. + * + * @type {EmphasisMaterial} + */ + get highlightMaterial() { + return this.scene.highlightMaterial; } - } - _shouldLog(logLevel) { - return this.isEnabled() && this.getLevel() >= normalizeLogLevel(logLevel); - } + /** + * Configures the appearance of selected {@link Entity}s within this VBOSceneModel. + * + * This is the {@link Scene#selectedMaterial}. + * + * @type {EmphasisMaterial} + */ + get selectedMaterial() { + return this.scene.selectedMaterial; + } - _getLogFunction(logLevel, message, method, args, opts) { - if (this._shouldLog(logLevel)) { - opts = normalizeArguments({ - logLevel, - message, - args, - opts - }); - method = method || opts.method; - assert$2(method); - opts.total = this.getTotal(); - opts.delta = this.getDelta(); - this._deltaTs = getHiResTimestamp(); - const tag = opts.tag || opts.message; + /** + * Configures the appearance of edges of {@link Entity}s within this VBOSceneModel. + * + * This is the {@link Scene#edgeMaterial}. + * + * @type {EdgeMaterial} + */ + get edgeMaterial() { + return this.scene.edgeMaterial; + } - if (opts.once) { - if (!cache[tag]) { - cache[tag] = getHiResTimestamp(); - } else { - return noop; - } - } + //------------------------------------------------------------------------------------------------------------------ + // Drawable members + //------------------------------------------------------------------------------------------------------------------ - message = decorateMessage(this.id, opts.message, opts); - return method.bind(console, message, ...opts.args); + /** + * Called by private renderers in ./lib, returns the picking view matrix with which to + * ray-pick on this VBOSceneModel. + * + * @private + */ + getPickViewMatrix(pickViewMatrix) { + if (!this._viewMatrix) { + return pickViewMatrix; + } + return this._viewMatrix; } - return noop; - } + /** + * Creates a reusable geometry within this VBOSceneModel. + * + * We can then supply the geometry ID to {@link VBOSceneModel#createMesh} when we want to create meshes that instance the geometry. + * + * @param {*} cfg Geometry properties. + * @param {String|Number} cfg.id Mandatory ID for the geometry, to refer to with {@link VBOSceneModel#createMesh}. + * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. + * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. + * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. + * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. + * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. + * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. + * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. + * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. + * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````VBOSceneModel```` constructor. + */ + createGeometry(cfg) { + const geometryId = cfg.id; + if (geometryId === undefined || geometryId === null) { + this.error("Config missing: id"); + return; + } + if (this._geometries[geometryId]) { + this.error("Geometry already created: " + geometryId); + return; + } + const primitive = cfg.primitive; + if (primitive === undefined || primitive === null) { + this.error("Param expected: primitive"); + return; + } + if (primitive !== "points" && primitive !== "lines" && primitive !== "triangles" && primitive !== "solid" && primitive !== "surface") { + this.error(`Unsupported value for 'primitive': '${primitive}' - supported values are 'points', 'lines', 'triangles', 'solid' and 'surface'. Defaulting to 'triangles'.`); + return; + } + if (!cfg.positions && !cfg.positionsCompressed) { + this.error("Param expected: `positions` or `positionsCompressed'"); + return null; + } + if (cfg.positionsCompressed && !cfg.positionsDecodeMatrix) { + this.error("Param expected: `positionsDecodeMatrix` (required for `positionsCompressed')"); + return null; + } + if (cfg.uvCompressed && !cfg.uvDecodeMatrix) { + this.error("Param expected: `uvDecodeMatrix` (required for `uvCompressed')"); + return null; + } + if (!cfg.indices && primitive !== "points") { + this.error(`Param expected: indices (required for '${primitive}' primitive type)`); + return null; + } + const geometry = new VBOSceneModelGeometry(geometryId, this, cfg); + this._geometries[geometryId] = geometry; + this._numTriangles += (cfg.indices ? Math.round(cfg.indices.length / 3) : 0); + this.numGeometries++; + } -} + /** + * Creates a texture within this VBOSceneModel. + * + * We can then supply the texture ID to {@link VBOSceneModel#createTextureSet} when we want to create texture sets that use the texture. + * + * @param {*} cfg Texture properties. + * @param {String|Number} cfg.id Mandatory ID for the texture, to refer to with {@link VBOSceneModel#createTextureSet}. + * @param {String} [cfg.src] Image file for the texture. Assumed to be transcoded if not having a recognized image file + * extension (jpg, jpeg, png etc.). If transcoded, then assumes ````VBOSceneModel```` is configured with a {@link TextureTranscoder}. + * @param {ArrayBuffer[]} [cfg.buffers] Transcoded texture data. Assumes ````VBOSceneModel```` is + * configured with a {@link TextureTranscoder}. This parameter is given as an array of buffers so we can potentially support multi-image textures, such as cube maps. + * @param {HTMLImageElement} [cfg.image] HTML Image object to load into this texture. Overrides ````src```` and ````buffers````. Never transcoded. + * @param {Number} [cfg.minFilter=LinearMipmapLinearFilter] How the texture is sampled when a texel covers less than one pixel. + * Supported values are {@link LinearMipmapLinearFilter}, {@link LinearMipMapNearestFilter}, {@link NearestMipMapNearestFilter}, {@link NearestMipMapLinearFilter} and {@link LinearMipMapLinearFilter}. + * @param {Number} [cfg.magFilter=LinearFilter] How the texture is sampled when a texel covers more than one pixel. Supported values are {@link LinearFilter} and {@link NearestFilter}. + * @param {Number} [cfg.wrapS=RepeatWrapping] Wrap parameter for texture coordinate *S*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. + * @param {Number} [cfg.wrapT=RepeatWrapping] Wrap parameter for texture coordinate *T*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}.. + * @param {Number} [cfg.wrapR=RepeatWrapping] Wrap parameter for texture coordinate *R*. Supported values are {@link ClampToEdgeWrapping}, {@link MirroredRepeatWrapping} and {@link RepeatWrapping}. + * @param {Boolean} [cfg.flipY=false] Flips this Texture's source data along its vertical axis when ````true````. + * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. + */ + createTexture(cfg) { + const textureId = cfg.id; + if (textureId === undefined || textureId === null) { + this.error("Config missing: id"); + return; + } + if (this._textures[textureId]) { + this.error("Texture already created: " + textureId); + return; + } + if (!cfg.src && !cfg.image && !cfg.buffers) { + this.error("Param expected: `src`, `image' or 'buffers'"); + return null; + } + let minFilter = cfg.minFilter || LinearMipmapLinearFilter; + if (minFilter !== LinearFilter && + minFilter !== LinearMipMapNearestFilter && + minFilter !== LinearMipmapLinearFilter && + minFilter !== NearestMipMapLinearFilter && + minFilter !== NearestMipMapNearestFilter) { + this.error(`[createTexture] Unsupported value for 'minFilter' - + supported values are LinearFilter, LinearMipMapNearestFilter, NearestMipMapNearestFilter, + NearestMipMapLinearFilter and LinearMipmapLinearFilter. Defaulting to LinearMipmapLinearFilter.`); + minFilter = LinearMipmapLinearFilter; + } + let magFilter = cfg.magFilter || LinearFilter; + if (magFilter !== LinearFilter && magFilter !== NearestFilter) { + this.error(`[createTexture] Unsupported value for 'magFilter' - supported values are LinearFilter and NearestFilter. Defaulting to LinearFilter.`); + magFilter = LinearFilter; + } + let wrapS = cfg.wrapS || RepeatWrapping; + if (wrapS !== ClampToEdgeWrapping && wrapS !== MirroredRepeatWrapping && wrapS !== RepeatWrapping) { + this.error(`[createTexture] Unsupported value for 'wrapS' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping.`); + wrapS = RepeatWrapping; + } + let wrapT = cfg.wrapT || RepeatWrapping; + if (wrapT !== ClampToEdgeWrapping && wrapT !== MirroredRepeatWrapping && wrapT !== RepeatWrapping) { + this.error(`[createTexture] Unsupported value for 'wrapT' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping.`); + wrapT = RepeatWrapping; + } + let wrapR = cfg.wrapR || RepeatWrapping; + if (wrapR !== ClampToEdgeWrapping && wrapR !== MirroredRepeatWrapping && wrapR !== RepeatWrapping) { + this.error(`[createTexture] Unsupported value for 'wrapR' - supported values are ClampToEdgeWrapping, MirroredRepeatWrapping and RepeatWrapping. Defaulting to RepeatWrapping.`); + wrapR = RepeatWrapping; + } + let encoding = cfg.encoding || LinearEncoding; + if (encoding !== LinearEncoding && encoding !== sRGBEncoding) { + this.error("[createTexture] Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); + encoding = LinearEncoding; + } + const texture = new Texture2D({ + gl: this.scene.canvas.gl, + minFilter, + magFilter, + wrapS, + wrapT, + wrapR, + // flipY: cfg.flipY, + encoding + }); + if (cfg.preloadColor) { + texture.setPreloadColor(cfg.preloadColor); + } + if (cfg.image) { // Ignore transcoder for Images + const image = cfg.image; + image.crossOrigin = "Anonymous"; + texture.setImage(image, {minFilter, magFilter, wrapS, wrapT, wrapR, flipY: cfg.flipY, encoding}); -_defineProperty(Log, "VERSION", VERSION$6); + } else if (cfg.src) { + const ext = cfg.src.split('.').pop(); + switch (ext) { // Don't transcode recognized image file types + case "jpeg": + case "jpg": + case "png": + case "gif": + const image = new Image(); + image.onload = () => { + texture.setImage(image, { + minFilter, + magFilter, + wrapS, + wrapT, + wrapR, + flipY: cfg.flipY, + encoding + }); + this.glRedraw(); + }; + image.src = cfg.src; // URL or Base64 string + break; + default: // Assume other file types need transcoding + if (!this._textureTranscoder) { + this.error(`Can't create texture from 'src' - VBOSceneModel needs to be configured with a TextureTranscoder for this file type ('${ext}')`); + } else { + utils.loadArraybuffer(cfg.src, (arrayBuffer) => { + if (!arrayBuffer.byteLength) { + this.error(`Can't create texture from 'src': file data is zero length`); + return; + } + this._textureTranscoder.transcode([arrayBuffer], texture).then(() => { + this.glRedraw(); + }); + }, + function (errMsg) { + this.error(`Can't create texture from 'src': ${errMsg}`); + }); + } + break; + } + } else if (cfg.buffers) { // Buffers implicitly require transcoding + if (!this._textureTranscoder) { + this.error(`Can't create texture from 'buffers' - VBOSceneModel needs to be configured with a TextureTranscoder for this option`); + } else { + this._textureTranscoder.transcode(cfg.buffers, texture).then(() => { + this.glRedraw(); + }); + } + } -function normalizeLogLevel(logLevel) { - if (!logLevel) { - return 0; - } + this._textures[textureId] = new VBOSceneModelTexture({id: textureId, texture}); + } - let resolvedLevel; + /** + * Creates a texture set within this VBOSceneModel. + * + * A texture set is a collection of textures that can be shared among meshes. We can then supply the texture set + * ID to {@link VBOSceneModel#createMesh} when we want to create meshes that use the texture set. + * + * The textures can work as a texture atlas, where each mesh can have geometry UVs that index + * a different part of the textures. This allows us to minimize the number of textures in our models, which + * means faster rendering. + * + * @param {*} cfg Texture set properties. + * @param {String|Number} cfg.id Mandatory ID for the texture set, to refer to with {@link VBOSceneModel#createMesh}. + * @param {*} [cfg.colorTextureId] ID of *RGBA* base color texture, with color in *RGB* and alpha in *A*. + * @param {*} [cfg.metallicRoughnessTextureId] ID of *RGBA* metal-roughness texture, with the metallic factor in *R*, and roughness factor in *G*. + * @param {*} [cfg.normalsTextureId] ID of *RGBA* normal map texture, with normal map vectors in *RGB*. + * @param {*} [cfg.emissiveTextureId] ID of *RGBA* emissive map texture, with emissive color in *RGB*. + * @param {*} [cfg.occlusionTextureId] ID of *RGBA* occlusion map texture, with occlusion factor in *R*. + */ + createTextureSet(cfg) { + const textureSetId = cfg.id; + if (textureSetId === undefined || textureSetId === null) { + this.error("Config missing: id"); + return; + } + if (this._textureSets[textureSetId]) { + this.error(`Texture set already created: ${textureSetId}`); + return; + } + let colorTexture; + if (cfg.colorTextureId !== undefined && cfg.colorTextureId !== null) { + colorTexture = this._textures[cfg.colorTextureId]; + if (!colorTexture) { + this.error(`Texture not found: ${cfg.colorTextureId} - ensure that you create it first with createTexture()`); + return; + } + } else { + colorTexture = this._textures[defaultColorTextureId]; + } + let metallicRoughnessTexture; + if (cfg.metallicRoughnessTextureId !== undefined && cfg.metallicRoughnessTextureId !== null) { + metallicRoughnessTexture = this._textures[cfg.metallicRoughnessTextureId]; + if (!metallicRoughnessTexture) { + this.error(`Texture not found: ${cfg.metallicRoughnessTextureId} - ensure that you create it first with createTexture()`); + return; + } + } else { + metallicRoughnessTexture = this._textures[defaultMetalRoughTextureId]; + } + let normalsTexture; + if (cfg.normalsTextureId !== undefined && cfg.normalsTextureId !== null) { + normalsTexture = this._textures[cfg.normalsTextureId]; + if (!normalsTexture) { + this.error(`Texture not found: ${cfg.normalsTextureId} - ensure that you create it first with createTexture()`); + return; + } + } else { + normalsTexture = this._textures[defaultNormalsTextureId]; + } + let emissiveTexture; + if (cfg.emissiveTextureId !== undefined && cfg.emissiveTextureId !== null) { + emissiveTexture = this._textures[cfg.emissiveTextureId]; + if (!emissiveTexture) { + this.error(`Texture not found: ${cfg.emissiveTextureId} - ensure that you create it first with createTexture()`); + return; + } + } else { + emissiveTexture = this._textures[defaultEmissiveTextureId]; + } + let occlusionTexture; + if (cfg.occlusionTextureId !== undefined && cfg.occlusionTextureId !== null) { + occlusionTexture = this._textures[cfg.occlusionTextureId]; + if (!occlusionTexture) { + this.error(`Texture not found: ${cfg.occlusionTextureId} - ensure that you create it first with createTexture()`); + return; + } + } else { + occlusionTexture = this._textures[defaultOcclusionTextureId]; + } + const textureSet = new VBOSceneModelTextureSet({ + id: textureSetId, + model: this, + colorTexture, + metallicRoughnessTexture, + normalsTexture, + emissiveTexture, + occlusionTexture + }); + this._textureSets[textureSetId] = textureSet; + } - switch (typeof logLevel) { - case 'number': - resolvedLevel = logLevel; - break; + /** + * Creates a mesh within this VBOSceneModel. + * + * A mesh can either define its own geometry or share it with other meshes. To define own geometry, provide the + * various geometry arrays to this method. To share a geometry, provide the ID of a geometry created earlier + * with {@link VBOSceneModel#createGeometry}. + * + * Internally, VBOSceneModel will batch all unique mesh geometries into the same arrays, which improves + * rendering performance. + * + * If you accompany the arrays with an ````origin````, then ````createMesh()```` will assume + * that the ````positions```` are in relative-to-center (RTC) coordinates, with ````origin```` being the origin of their + * RTC coordinate system. + * + * @param {object} cfg Object properties. + * @param {String} cfg.id Mandatory ID for the new mesh. Must not clash with any existing components within the {@link Scene}. + * @param {String|Number} [cfg.textureSetId] ID of a texture set previously created with {@link VBOSceneModel#createTextureSet"}. + * @param {String|Number} [cfg.geometryId] ID of a geometry to instance, previously created with {@link VBOSceneModel#createGeometry"}. Overrides all other geometry parameters given to this method. + * @param {String} cfg.primitive The primitive type. Accepted values are 'points', 'lines', 'triangles', 'solid' and 'surface'. + * @param {Number[]} [cfg.positions] Flat array of uncompressed 3D vertex positions positions. Required for all primitive types. Overridden by ````positionsCompressed````. + * @param {Number[]} [cfg.positionsCompressed] Flat array of quantized 3D vertex positions. Overrides ````positions````, and must be accompanied by ````positionsDecodeMatrix````. + * @param {Number[]} [cfg.positionsDecodeMatrix] A 4x4 matrix for decompressing ````positionsCompressed````. Must be accompanied by ````positionsCompressed````. + * @param {Number[]} [cfg.normals] Flat array of normal vectors. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.normalsCompressed] Flat array of oct-encoded normal vectors. Overrides ````normals````. Only used with "triangles", "solid" and "surface" primitives. When no normals are given, the geometry will be flat shaded using auto-generated face-aligned normals. + * @param {Number[]} [cfg.colors] Flat array of uncompressed RGBA vertex colors, as float values in range ````[0..1]````. Ignored when ````geometryId```` is given. Overridden by ````color```` and ````colorsCompressed````. + * @param {Number[]} [cfg.colorsCompressed] Flat array of compressed RGBA vertex colors, as unsigned short integers in range ````[0..255]````. Ignored when ````geometryId```` is given. Overrides ````colors```` and is overridden by ````color````. + * @param {Number[]} [cfg.uv] Flat array of uncompressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvCompressed] Flat array of compressed vertex UV coordinates. Only used with "triangles", "solid" and "surface" primitives. Overrides ````uv````. Must be accompanied by ````uvDecodeMatrix````. Only used with "triangles", "solid" and "surface" primitives. Required for textured rendering. + * @param {Number[]} [cfg.uvDecodeMatrix] A 3x3 matrix for decompressing ````uvCompressed````. + * @param {Number[]} [cfg.indices] Array of primitive connectivity indices. Not required for `points` primitives. + * @param {Number[]} [cfg.edgeIndices] Array of edge line indices. Used only with 'triangles', 'solid' and 'surface' primitives. Automatically generated internally if not supplied, using the optional ````edgeThreshold```` given to the ````VBOSceneModel```` constructor. + * @param {Number[]} [cfg.origin] Optional geometry origin, relative to {@link VBOSceneModel#origin}. When this is given, then ````positions```` are assumed to be relative to this. + * @param {Number[]} [cfg.position=[0,0,0]] Local 3D position of the mesh. + * @param {Number[]} [cfg.scale=[1,1,1]] Scale of the mesh. + * @param {Number[]} [cfg.rotation=[0,0,0]] Rotation of the mesh as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Mesh modelling transform matrix. Overrides the ````position````, ````scale```` and ````rotation```` parameters. + * @param {Number[]} [cfg.color=[1,1,1]] RGB color in range ````[0..1, 0..1, 0..1]````. Overridden by texture set ````colorTexture````. Overrides ````colors```` and ````colorsCompressed````. + * @param {Number} [cfg.opacity=1] Opacity in range ````[0..1]````. Overridden by texture set ````colorTexture````. + * @param {Number} [cfg.metallic=0] Metallic factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. + * @param {Number} [cfg.roughness=1] Roughness factor in range ````[0..1]````. Overridden by texture set ````metallicRoughnessTexture````. + */ + createMesh(cfg) { - case 'object': - resolvedLevel = logLevel.logLevel || logLevel.priority || 0; - break; + let id = cfg.id; + if (id === undefined || id === null) { + this.error("Config missing: id"); + return; + } - default: - return 0; - } + if (this._meshes[id]) { + this.error(`VBOSceneModel already has a mesh with this ID: ${id}`); + return; + } - assert$2(Number.isFinite(resolvedLevel) && resolvedLevel >= 0); - return resolvedLevel; -} + const geometryId = cfg.geometryId; + const sharingGeometry = (cfg.geometryId !== undefined); + if (sharingGeometry && !this._geometries[cfg.geometryId]) { + this.error(`Geometry not found: ${cfg.geometryId} - ensure that you create it first with createGeometry()`); + return; + } -function normalizeArguments(opts) { - const { - logLevel, - message - } = opts; - opts.logLevel = normalizeLogLevel(logLevel); - const args = opts.args ? Array.from(opts.args) : []; + const textureSetId = cfg.textureSetId || defaultTextureSetId; + if (textureSetId) { + if (!this._textureSets[textureSetId]) { + this.error(`Texture set not found: ${textureSetId} - ensure that you create it first with createTextureSet()`); + return; + } + } - while (args.length && args.shift() !== message) {} + let portionId; - switch (typeof logLevel) { - case 'string': - case 'function': - if (message !== undefined) { - args.unshift(message); - } + const color = (cfg.color) ? new Uint8Array([Math.floor(cfg.color[0] * 255), Math.floor(cfg.color[1] * 255), Math.floor(cfg.color[2] * 255)]) : [255, 255, 255]; + const opacity = (cfg.opacity !== undefined && cfg.opacity !== null) ? Math.floor(cfg.opacity * 255) : 255; + const metallic = (cfg.metallic !== undefined && cfg.metallic !== null) ? Math.floor(cfg.metallic * 255) : 0; + const roughness = (cfg.roughness !== undefined && cfg.roughness !== null) ? Math.floor(cfg.roughness * 255) : 255; - opts.message = logLevel; - break; + const mesh = new VBOSceneModelMesh(this, id, color, opacity); - case 'object': - Object.assign(opts, logLevel); - break; - } + const pickId = mesh.pickId; - if (typeof opts.message === 'function') { - opts.message = opts.message(); - } + const a = pickId >> 24 & 0xFF; + const b = pickId >> 16 & 0xFF; + const g = pickId >> 8 & 0xFF; + const r = pickId & 0xFF; - const messageType = typeof opts.message; - assert$2(messageType === 'string' || messageType === 'object'); - return Object.assign(opts, { - args - }, opts.opts); -} + const pickColor = new Uint8Array([r, g, b, a]); // Quantized pick color -function decorateMessage(id, message, opts) { - if (typeof message === 'string') { - const time = opts.time ? leftPad(formatTime(opts.total)) : ''; - message = opts.time ? "".concat(id, ": ").concat(time, " ").concat(message) : "".concat(id, ": ").concat(message); - message = addColor(message, opts.color, opts.background); - } + const aabb = math.collapseAABB3(); - return message; -} + let layer; -function logImageInNode(_ref2) { - let { - image, - message = '', - scale = 1 - } = _ref2; - let asciify = null; + if (sharingGeometry) { - try { - asciify = module.require('asciify-image'); - } catch (error) {} + let meshMatrix; + let worldMatrix = this._worldMatrixNonIdentity ? this._worldMatrix : null; - if (asciify) { - return () => asciify(image, { - fit: 'box', - width: "".concat(Math.round(80 * scale), "%") - }).then(data => console.log(data)); - } + if (cfg.matrix) { + meshMatrix = cfg.matrix; + } else { + const scale = cfg.scale || defaultScale; + const position = cfg.position || defaultPosition; + const rotation = cfg.rotation || defaultRotation; + math.eulerToQuaternion(rotation, "XYZ", defaultQuaternion); + meshMatrix = math.composeMat4(position, defaultQuaternion, scale, tempMat4$1); + } - return noop; -} + const cfgOrigin = cfg.origin || cfg.rtcCenter; + const origin = (cfgOrigin) ? math.addVec3(this._origin, cfgOrigin, tempVec3a$8) : this._origin; -function logImageInBrowser(_ref3) { - let { - image, - message = '', - scale = 1 - } = _ref3; + const instancingLayer = this._getInstancingLayer(origin, textureSetId, geometryId); - if (typeof image === 'string') { - const img = new Image(); + layer = instancingLayer; - img.onload = () => { - const args = formatImage(img, message, scale); - console.log(...args); - }; + portionId = instancingLayer.createPortion({ + color: color, + metallic: metallic, + roughness: roughness, + opacity: opacity, + meshMatrix: meshMatrix, + worldMatrix: worldMatrix, + aabb: aabb, + pickColor: pickColor + }); - img.src = image; - return noop; - } + math.expandAABB3(this._aabb, aabb); - const element = image.nodeName || ''; + const numTriangles = Math.round(instancingLayer.numIndices / 3); + this._numTriangles += numTriangles; + mesh.numTriangles = numTriangles; - if (element.toLowerCase() === 'img') { - console.log(...formatImage(image, message, scale)); - return noop; - } + mesh.origin = origin; - if (element.toLowerCase() === 'canvas') { - const img = new Image(); + } else { // Batching - img.onload = () => console.log(...formatImage(img, message, scale)); + let primitive = cfg.primitive; + if (primitive === undefined || primitive === null) { + primitive = "triangles"; + } + if (primitive !== "points" && primitive !== "lines" && primitive !== "triangles" && primitive !== "solid" && primitive !== "surface") { + this.error(`Unsupported value for 'primitive': '${primitive}' ('geometryId' is absent) - supported values are 'points', 'lines', 'triangles', 'solid' and 'surface'.`); + return; + } + if (!cfg.positions && !cfg.positionsCompressed) { + this.error("Param expected: 'positions' or 'positionsCompressed' ('geometryId' is absent)"); + return null; + } + if (cfg.positions && cfg.positionsCompressed) { + this.error("Only one param expected, not both: 'positions' or 'positionsCompressed' ('geometryId' is absent)"); + return null; + } + if (cfg.positionsCompressed && !cfg.positionsDecodeMatrix) { + this.error("Param expected: 'positionsDecodeMatrix' (required for 'positionsCompressed'; 'geometryId' is absent)"); + return null; + } + if (cfg.uvCompressed && !cfg.uvDecodeMatrix) { + this.error("Param expected: `uvDecodeMatrix` (required for `uvCompressed'; 'geometryId' is absent)"); + return null; + } + if (!cfg.indices && primitive !== "points") { + this.error(`Param expected: indices (required for '${primitive}' primitive type)`); + return null; + } + if (!cfg.indices && primitive !== "points") { + this.error("Config expected: indices (no meshIds provided, so expecting geometry arrays instead)"); + return null; + } - img.src = image.toDataURL(); - return noop; - } + let indices = cfg.indices; + let edgeIndices = cfg.edgeIndices; + let origin = (cfg.origin || cfg.rtcCenter) ? math.addVec3(this._origin, cfg.origin || cfg.rtcCenter, tempVec3a$8) : this._origin; + let positions = cfg.positions; - return noop; -} + if (positions) { + const rtcCenter = math.vec3(); + const rtcPositions = []; + const rtcNeeded = worldToRTCPositions(positions, rtcPositions, rtcCenter); + if (rtcNeeded) { + positions = rtcPositions; + origin = math.addVec3(origin, rtcCenter, rtcCenter); + } + } -function getTableHeader(table) { - for (const key in table) { - for (const title in table[key]) { - return title || 'untitled'; - } - } + let needNewBatchingLayers = false; - return 'empty'; -} + if (!this._lastOrigin) { + needNewBatchingLayers = true; + this._lastOrigin = math.vec3(origin); + } else { + if (!math.compareVec3(this._lastOrigin, origin)) { + needNewBatchingLayers = true; + this._lastOrigin.set(origin); + } + } + if (cfg.positionsDecodeMatrix) { + if (!this._lastPositionsDecodeMatrix) { + needNewBatchingLayers = true; + this._lastPositionsDecodeMatrix = math.mat4(cfg.positionsDecodeMatrix); -const log = new Log({ - id: 'loaders.gl' -}); + } else { + if (!math.compareMat4(this._lastPositionsDecodeMatrix, cfg.positionsDecodeMatrix)) { + needNewBatchingLayers = true; + this._lastPositionsDecodeMatrix.set(cfg.positionsDecodeMatrix); + } + } + } + if (cfg.uvDecodeMatrix) { + if (!this._lastUVDecodeMatrix) { + needNewBatchingLayers = true; + this._lastUVDecodeMatrix = math.mat4(cfg.uvDecodeMatrix); -const EXT_PATTERN = /\.([^.]+)$/; -async function selectLoader(data, loaders = [], options, context) { - if (!validHTTPResponse(data)) { - return null; - } + } else { + if (!math.compareMat4(this._lastUVDecodeMatrix, cfg.uvDecodeMatrix)) { + needNewBatchingLayers = true; + this._lastUVDecodeMatrix.set(cfg.uvDecodeMatrix); + } + } + } + if (cfg.textureSetId) { + if (this._lastTextureSetId !== cfg.textureSetId) { + needNewBatchingLayers = true; + this._lastTextureSetId = cfg.textureSetId; + } + } + if (needNewBatchingLayers) { + for (let primitiveId in this._currentBatchingLayers) { + if (this._currentBatchingLayers.hasOwnProperty(primitiveId)) { + this._currentBatchingLayers[primitiveId].finalize(); + } + } + this._currentBatchingLayers = {}; + } - let loader = selectLoaderSync(data, loaders, { ...options, - nothrow: true - }, context); + const normalsProvided = (!!cfg.normals && cfg.normals.length > 0); + if (primitive === "triangles" || primitive === "solid" || primitive === "surface") { + if (this._lastNormals !== null && normalsProvided !== this._lastNormals) { + for (let primitiveId in this._currentBatchingLayers) { + if (this._currentBatchingLayers[primitiveId]) { + this._currentBatchingLayers[primitiveId].finalize(); + delete this._currentBatchingLayers[primitiveId]; + } + } + } + this._lastNormals = normalsProvided; + } - if (loader) { - return loader; - } + const worldMatrix = this._worldMatrixNonIdentity ? this._worldMatrix : null; + let meshMatrix; - if (isBlob(data)) { - data = await data.slice(0, 10).arrayBuffer(); - loader = selectLoaderSync(data, loaders, options, context); - } + if (!cfg.positionsDecodeMatrix) { + if (cfg.matrix) { + meshMatrix = cfg.matrix; + } else { + const scale = cfg.scale || defaultScale; + const position = cfg.position || defaultPosition; + const rotation = cfg.rotation || defaultRotation; + math.eulerToQuaternion(rotation, "XYZ", defaultQuaternion); + meshMatrix = math.composeMat4(position, defaultQuaternion, scale, tempMat4$1); + } + } - if (!loader && !(options !== null && options !== void 0 && options.nothrow)) { - throw new Error(getNoValidLoaderMessage(data)); - } + const textureSet = textureSetId ? this._textureSets[textureSetId] : null; - return loader; -} -function selectLoaderSync(data, loaders = [], options, context) { - if (!validHTTPResponse(data)) { - return null; - } + const primitiveId = `${primitive}-\ +${cfg.normals && cfg.normals.length > 0 ? 1 : 0}-${cfg.normalsCompressed && cfg.normalsCompressed.length > 0 ? 1 : 0}-\ +${cfg.colors && cfg.colors.length > 0 ? 1 : 0}-${cfg.colorsCompressed && cfg.colorsCompressed.length > 0 ? 1 : 0}-\ +${cfg.uv && cfg.uv.length > 0 ? 1 : 0}-${cfg.uvCompressed && cfg.uvCompressed.length > 0 ? 1 : 0}`; - if (loaders && !Array.isArray(loaders)) { - return normalizeLoader(loaders); - } + layer = this._currentBatchingLayers[primitiveId]; - let candidateLoaders = []; + const lenPositions = (positions || cfg.positionsCompressed).length; - if (loaders) { - candidateLoaders = candidateLoaders.concat(loaders); - } + switch (primitive) { + case "triangles": + case "solid": + case "surface": + if (layer) { + if (!layer.canCreatePortion(lenPositions, indices.length)) { + layer.finalize(); + delete this._currentBatchingLayers[primitiveId]; + layer = null; + } + } + if (!layer) { + layer = new TrianglesBatchingLayer({ + model: this, + textureSet: textureSet, + layerIndex: 0, // This is set in #finalize() + scratchMemory: this._scratchMemory, + positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined + uvDecodeMatrix: cfg.uvDecodeMatrix, // Can be undefined + origin, + maxGeometryBatchSize: this._maxGeometryBatchSize, + solid: (primitive === "solid"), + autoNormals: (!normalsProvided) + }); + this._layerList.push(layer); + this._currentBatchingLayers[primitiveId] = layer; + } + if (!edgeIndices) { + edgeIndices = buildEdgeIndices(positions || cfg.positionsCompressed, indices, null, this._edgeThreshold); + } + portionId = layer.createPortion({ + positions: positions, + positionsCompressed: cfg.positionsCompressed, + normals: cfg.normals, + normalsCompressed: cfg.normalsCompressed, + colors: cfg.colors, + colorsCompressed: cfg.colorsCompressed, + uv: cfg.uv, + uvCompressed: cfg.uvCompressed, + indices: indices, + edgeIndices: edgeIndices, + color: color, + opacity: opacity, + metallic: metallic, + roughness: roughness, + meshMatrix: meshMatrix, + worldMatrix: worldMatrix, + worldAABB: aabb, + pickColor: pickColor + }); + const numTriangles = Math.round(indices.length / 3); + this._numTriangles += numTriangles; + mesh.numTriangles = numTriangles; + break; - if (!(options !== null && options !== void 0 && options.ignoreRegisteredLoaders)) { - candidateLoaders.push(...getRegisteredLoaders()); - } + case "lines": + if (layer) { + if (!layer.canCreatePortion(lenPositions, indices.length)) { + layer.finalize(); + delete this._currentBatchingLayers[primitiveId]; + layer = null; + } + } + if (!layer) { + layer = new LinesBatchingLayer({ + model: this, + layerIndex: 0, // This is set in #finalize() + scratchMemory: this._scratchMemory, + positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined + origin, + maxGeometryBatchSize: this._maxGeometryBatchSize + }); + this._layerList.push(layer); + this._currentBatchingLayers[primitiveId] = layer; + } + portionId = layer.createPortion({ + positions: positions, + positionsCompressed: cfg.positionsCompressed, + indices: indices, + colors: cfg.colors, + colorsCompressed: cfg.colorsCompressed, + color: color, + opacity: opacity, + meshMatrix: meshMatrix, + worldMatrix: worldMatrix, + worldAABB: aabb, + pickColor: pickColor + }); + this._numLines += Math.round(indices.length / 2); + break; - normalizeLoaders(candidateLoaders); - const loader = selectLoaderInternal(data, candidateLoaders, options, context); + case "points": + if (layer) { + if (!layer.canCreatePortion(lenPositions)) { + layer.finalize(); + delete this._currentBatchingLayers[primitiveId]; + layer = null; + } + } + if (!layer) { + layer = new PointsBatchingLayer({ + model: this, + layerIndex: 0, // This is set in #finalize() + scratchMemory: this._scratchMemory, + positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined + origin, + maxGeometryBatchSize: this._maxGeometryBatchSize + }); + this._layerList.push(layer); + this._currentBatchingLayers[primitiveId] = layer; + } + portionId = layer.createPortion({ + positions: positions, + positionsCompressed: cfg.positionsCompressed, + colors: cfg.colors, + colorsCompressed: cfg.colorsCompressed, + color: color, + opacity: opacity, + meshMatrix: meshMatrix, + worldMatrix: worldMatrix, + worldAABB: aabb, + pickColor: pickColor + }); + this._numPoints += Math.round(lenPositions / 3); + break; + } - if (!loader && !(options !== null && options !== void 0 && options.nothrow)) { - throw new Error(getNoValidLoaderMessage(data)); - } + math.expandAABB3(this._aabb, aabb); + this.numGeometries++; + mesh.origin = origin; + } - return loader; -} + mesh.parent = null; // Will be set within PerformanceModelNode constructor + mesh._layer = layer; + mesh._portionId = portionId; + mesh.aabb = aabb; -function selectLoaderInternal(data, loaders, options, context) { - const { - url, - type - } = getResourceUrlAndType(data); - const testUrl = url || (context === null || context === void 0 ? void 0 : context.url); - let loader = null; - let reason = ''; + this._meshes[id] = mesh; + } - if (options !== null && options !== void 0 && options.mimeType) { - loader = findLoaderByMIMEType(loaders, options === null || options === void 0 ? void 0 : options.mimeType); - reason = "match forced by supplied MIME type ".concat(options === null || options === void 0 ? void 0 : options.mimeType); - } + _getInstancingLayer(origin, textureSetId, geometryId) { + const layerId = `${origin[0]}.${origin[1]}.${origin[2]}.${textureSetId}.${geometryId}`; + let instancingLayer = this._instancingLayers[layerId]; + if (instancingLayer) { + return instancingLayer; + } + let textureSet; + if (textureSetId !== undefined) { + textureSet = this._textureSets[textureSetId]; + if (!textureSet) { + this.error(`TextureSet not found: ${textureSetId} - ensure that you create it first with createTextureSet()`); + return; + } + } + const geometry = this._geometries[geometryId]; + if (!this._geometries[geometryId]) { + this.error(`Geometry not found: ${geometryId} - ensure that you create it first with createGeometry()`); + return; + } + switch (geometry.primitive) { + case "triangles": + instancingLayer = new TrianglesInstancingLayer({ + model: this, + textureSet, + geometry, + origin, + layerIndex: 0, + solid: false + }); + break; + case "solid": + instancingLayer = new TrianglesInstancingLayer({ + model: this, + textureSet, + geometry, + origin, + layerIndex: 0, + solid: true + }); + break; + case "surface": + instancingLayer = new TrianglesInstancingLayer({ + model: this, + textureSet, + geometry, + origin, + layerIndex: 0, + solid: false + }); + break; + case "lines": + instancingLayer = new LinesInstancingLayer({ + model: this, + textureSet, + geometry, + origin, + layerIndex: 0 + }); + break; + case "points": + instancingLayer = new PointsInstancingLayer({ + model: this, + textureSet, + geometry, + origin, + layerIndex: 0 + }); + break; + } + this._instancingLayers[layerId] = instancingLayer; + this._layerList.push(instancingLayer); + return instancingLayer; + } - loader = loader || findLoaderByUrl(loaders, testUrl); - reason = reason || (loader ? "matched url ".concat(testUrl) : ''); - loader = loader || findLoaderByMIMEType(loaders, type); - reason = reason || (loader ? "matched MIME type ".concat(type) : ''); - loader = loader || findLoaderByInitialBytes(loaders, data); - reason = reason || (loader ? "matched initial data ".concat(getFirstCharacters(data)) : ''); - loader = loader || findLoaderByMIMEType(loaders, options === null || options === void 0 ? void 0 : options.fallbackMimeType); - reason = reason || (loader ? "matched fallback MIME type ".concat(type) : ''); + /** + * Creates an {@link Entity} within this VBOSceneModel, giving it one or more meshes previously created with {@link VBOSceneModel#createMesh}. + * + * A mesh can only belong to one {@link Entity}, so you'll get an error if you try to reuse a mesh among multiple {@link Entity}s. + * + * @param {Object} cfg Entity configuration. + * @param {String} cfg.id Optional ID for the new Entity. Must not clash with any existing components within the {@link Scene}. + * @param {String[]} cfg.meshIds IDs of one or more meshes created previously with {@link VBOSceneModel@createMesh}. - if (reason) { - var _loader; + * @param {Boolean} [cfg.isObject] Set ````true```` if the {@link Entity} represents an object, in which case it will be registered by {@link Entity#id} in {@link Scene#objects} and can also have a corresponding {@link MetaObject} with matching {@link MetaObject#id}, registered by that ID in {@link MetaScene#metaObjects}. + * @param {Boolean} [cfg.visible=true] Indicates if the Entity is initially visible. + * @param {Boolean} [cfg.culled=false] Indicates if the Entity is initially culled from view. + * @param {Boolean} [cfg.pickable=true] Indicates if the Entity is initially pickable. + * @param {Boolean} [cfg.clippable=true] Indicates if the Entity is initially clippable. + * @param {Boolean} [cfg.collidable=true] Indicates if the Entity is initially included in boundary calculations. + * @param {Boolean} [cfg.castsShadow=true] Indicates if the Entity initially casts shadows. + * @param {Boolean} [cfg.receivesShadow=true] Indicates if the Entity initially receives shadows. + * @param {Boolean} [cfg.xrayed=false] Indicates if the Entity is initially xrayed. XRayed appearance is configured by {@link VBOSceneModel#xrayMaterial}. + * @param {Boolean} [cfg.highlighted=false] Indicates if the Entity is initially highlighted. Highlighted appearance is configured by {@link VBOSceneModel#highlightMaterial}. + * @param {Boolean} [cfg.selected=false] Indicates if the Entity is initially selected. Selected appearance is configured by {@link VBOSceneModel#selectedMaterial}. + * @param {Boolean} [cfg.edges=false] Indicates if the Entity's edges are initially emphasized. Edges appearance is configured by {@link VBOSceneModel#edgeMaterial}. + * @returns {Entity} + */ + createEntity(cfg) { + // Validate or generate Entity ID + let id = cfg.id; + if (id === undefined) { + id = math.createUUID(); + } else if (this.scene.components[id]) { + this.error("Scene already has a Component with this ID: " + id + " - will assign random ID"); + id = math.createUUID(); + } + // Collect PerformanceModelNode's PerformanceModelMeshes + const meshIds = cfg.meshIds; + if (meshIds === undefined) { + this.error("Config missing: meshIds"); + return; + } + let meshes = []; + for (let i = 0, len = meshIds.length; i < len; i++) { + const meshId = meshIds[i]; + const mesh = this._meshes[meshId]; + if (!mesh) { + this.error("Mesh with this ID not found: " + meshId + " - ignoring this mesh"); + continue; + } + if (mesh.parent) { + this.error("Mesh with ID " + meshId + " already belongs to object with ID " + mesh.parent.id + " - ignoring this mesh"); + continue; + } + meshes.push(mesh); + } + // Create PerformanceModelNode flags + let flags = 0; + if (this._visible && cfg.visible !== false) { + flags = flags | ENTITY_FLAGS.VISIBLE; + } + if (this._pickable && cfg.pickable !== false) { + flags = flags | ENTITY_FLAGS.PICKABLE; + } + if (this._culled && cfg.culled !== false) { + flags = flags | ENTITY_FLAGS.CULLED; + } + if (this._clippable && cfg.clippable !== false) { + flags = flags | ENTITY_FLAGS.CLIPPABLE; + } + if (this._collidable && cfg.collidable !== false) { + flags = flags | ENTITY_FLAGS.COLLIDABLE; + } + if (this._edges && cfg.edges !== false) { + flags = flags | ENTITY_FLAGS.EDGES; + } + if (this._xrayed && cfg.xrayed !== false) { + flags = flags | ENTITY_FLAGS.XRAYED; + } + if (this._highlighted && cfg.highlighted !== false) { + flags = flags | ENTITY_FLAGS.HIGHLIGHTED; + } + if (this._selected && cfg.selected !== false) { + flags = flags | ENTITY_FLAGS.SELECTED; + } + // Create PerformanceModelNode AABB + let aabb; + if (meshes.length === 1) { + aabb = meshes[0].aabb; + } else { + aabb = math.collapseAABB3(); + for (let i = 0, len = meshes.length; i < len; i++) { + math.expandAABB3(aabb, meshes[i].aabb); + } + } + const node = new VBOSceneModelNode(this, cfg.isObject, id, meshes, flags, aabb); // Internally sets PerformanceModelMesh#parent to this PerformanceModelNode + this._nodeList.push(node); + this._nodes[id] = node; + this.numEntities++; + return node; + } - log.log(1, "selectLoader selected ".concat((_loader = loader) === null || _loader === void 0 ? void 0 : _loader.name, ": ").concat(reason, ".")); - } + /** + * Finalizes this VBOSceneModel. + * + * Immediately creates the VBOSceneModel's {@link Entity}s within the {@link Scene}. + * + * Once finalized, you can't add anything more to this VBOSceneModel. + */ + finalize() { - return loader; -} + if (this.destroyed) { + return; + } -function validHTTPResponse(data) { - if (data instanceof Response) { - if (data.status === 204) { - return false; - } - } + for (const layerId in this._instancingLayers) { + if (this._instancingLayers.hasOwnProperty(layerId)) { + this._instancingLayers[layerId].finalize(); + } + } - return true; -} + for (let layerId in this._currentBatchingLayers) { + if (this._currentBatchingLayers.hasOwnProperty(layerId)) { + this._currentBatchingLayers[layerId].finalize(); + } + } + this._currentBatchingLayers = {}; -function getNoValidLoaderMessage(data) { - const { - url, - type - } = getResourceUrlAndType(data); - let message = 'No valid loader found ('; - message += url ? "".concat(filename(url), ", ") : 'no url provided, '; - message += "MIME type: ".concat(type ? "\"".concat(type, "\"") : 'not provided', ", "); - const firstCharacters = data ? getFirstCharacters(data) : ''; - message += firstCharacters ? " first bytes: \"".concat(firstCharacters, "\"") : 'first bytes: not available'; - message += ')'; - return message; -} + for (let i = 0, len = this._nodeList.length; i < len; i++) { + const node = this._nodeList[i]; + node._finalize(); + } -function normalizeLoaders(loaders) { - for (const loader of loaders) { - normalizeLoader(loader); - } -} + for (let i = 0, len = this._nodeList.length; i < len; i++) { + const node = this._nodeList[i]; + node._finalize2(); + } -function findLoaderByUrl(loaders, url) { - const match = url && EXT_PATTERN.exec(url); - const extension = match && match[1]; - return extension ? findLoaderByExtension(loaders, extension) : null; -} + // Sort layers to reduce WebGL shader switching when rendering them -function findLoaderByExtension(loaders, extension) { - extension = extension.toLowerCase(); + this._layerList.sort((a, b) => { + if (a.sortId < b.sortId) { + return -1; + } + if (a.sortId > b.sortId) { + return 1; + } + return 0; + }); - for (const loader of loaders) { - for (const loaderExtension of loader.extensions) { - if (loaderExtension.toLowerCase() === extension) { - return loader; - } - } - } + for (let i = 0, len = this._layerList.length; i < len; i++) { + const layer = this._layerList[i]; + layer.layerIndex = i; + } - return null; -} + this.glRedraw(); -function findLoaderByMIMEType(loaders, mimeType) { - for (const loader of loaders) { - if (loader.mimeTypes && loader.mimeTypes.includes(mimeType)) { - return loader; + this.scene._aabbDirty = true; } - if (mimeType === "application/x.".concat(loader.id)) { - return loader; + _rebuildAABB() { + math.collapseAABB3(this._aabb); + for (let i = 0, len = this._nodeList.length; i < len; i++) { + const node = this._nodeList[i]; + math.expandAABB3(this._aabb, node.aabb); + } + this._aabbDirty = false; } - } - - return null; -} - -function findLoaderByInitialBytes(loaders, data) { - if (!data) { - return null; - } - - for (const loader of loaders) { - if (typeof data === 'string') { - if (testDataAgainstText(data, loader)) { - return loader; - } - } else if (ArrayBuffer.isView(data)) { - if (testDataAgainstBinary(data.buffer, data.byteOffset, loader)) { - return loader; - } - } else if (data instanceof ArrayBuffer) { - const byteOffset = 0; - if (testDataAgainstBinary(data, byteOffset, loader)) { - return loader; - } + /** @private */ + stateSortCompare(drawable1, drawable2) { } - } - - return null; -} - -function testDataAgainstText(data, loader) { - if (loader.testText) { - return loader.testText(data); - } - - const tests = Array.isArray(loader.tests) ? loader.tests : [loader.tests]; - return tests.some(test => data.startsWith(test)); -} -function testDataAgainstBinary(data, byteOffset, loader) { - const tests = Array.isArray(loader.tests) ? loader.tests : [loader.tests]; - return tests.some(test => testBinary(data, byteOffset, loader, test)); -} + /** @private */ + rebuildRenderFlags() { + this.renderFlags.reset(); + this._updateRenderFlagsVisibleLayers(); + if (this.renderFlags.numLayers > 0 && this.renderFlags.numVisibleLayers === 0) { + this.renderFlags.culled = true; + return; + } + this._updateRenderFlags(); + } -function testBinary(data, byteOffset, loader, test) { - if (test instanceof ArrayBuffer) { - return compareArrayBuffers(test, data, test.byteLength); - } + /** + * @private + */ + _updateRenderFlagsVisibleLayers() { + const renderFlags = this.renderFlags; + renderFlags.numLayers = this._layerList.length; + renderFlags.numVisibleLayers = 0; + for (let layerIndex = 0, len = this._layerList.length; layerIndex < len; layerIndex++) { + const layer = this._layerList[layerIndex]; + const layerVisible = this._getActiveSectionPlanesForLayer(layer); + if (layerVisible) { + renderFlags.visibleLayers[renderFlags.numVisibleLayers++] = layerIndex; + } + } + } - switch (typeof test) { - case 'function': - return test(data, loader); + /** @private */ + _getActiveSectionPlanesForLayer(layer) { - case 'string': - const magic = getMagicString$1(data, byteOffset, test.length); - return test === magic; + const renderFlags = this.renderFlags; + const sectionPlanes = this.scene._sectionPlanesState.sectionPlanes; + const numSectionPlanes = sectionPlanes.length; + const baseIndex = layer.layerIndex * numSectionPlanes; - default: - return false; - } -} + if (numSectionPlanes > 0) { + for (let i = 0; i < numSectionPlanes; i++) { -function getFirstCharacters(data, length = 5) { - if (typeof data === 'string') { - return data.slice(0, length); - } else if (ArrayBuffer.isView(data)) { - return getMagicString$1(data.buffer, data.byteOffset, length); - } else if (data instanceof ArrayBuffer) { - const byteOffset = 0; - return getMagicString$1(data, byteOffset, length); - } + const sectionPlane = sectionPlanes[i]; - return ''; -} + if (!sectionPlane.active) { + renderFlags.sectionPlanesActivePerLayer[baseIndex + i] = false; -function getMagicString$1(arrayBuffer, byteOffset, length) { - if (arrayBuffer.byteLength < byteOffset + length) { - return ''; - } + } else { + renderFlags.sectionPlanesActivePerLayer[baseIndex + i] = true; + renderFlags.sectioned = true; + } + } + } - const dataView = new DataView(arrayBuffer); - let magic = ''; + return true; + } - for (let i = 0; i < length; i++) { - magic += String.fromCharCode(dataView.getUint8(byteOffset + i)); - } + /** @private */ + _updateRenderFlags() { - return magic; -} + if (this.numVisibleLayerPortions === 0) { + return; + } -const DEFAULT_CHUNK_SIZE$2 = 256 * 1024; -function* makeStringIterator(string, options) { - const chunkSize = (options === null || options === void 0 ? void 0 : options.chunkSize) || DEFAULT_CHUNK_SIZE$2; - let offset = 0; - const textEncoder = new TextEncoder(); + if (this.numCulledLayerPortions === this.numPortions) { + return; + } - while (offset < string.length) { - const chunkLength = Math.min(string.length - offset, chunkSize); - const chunk = string.slice(offset, offset + chunkLength); - offset += chunkLength; - yield textEncoder.encode(chunk); - } -} + const renderFlags = this.renderFlags; -const DEFAULT_CHUNK_SIZE$1 = 256 * 1024; -function* makeArrayBufferIterator(arrayBuffer, options = {}) { - const { - chunkSize = DEFAULT_CHUNK_SIZE$1 - } = options; - let byteOffset = 0; + renderFlags.colorOpaque = (this.numTransparentLayerPortions < this.numPortions); - while (byteOffset < arrayBuffer.byteLength) { - const chunkByteLength = Math.min(arrayBuffer.byteLength - byteOffset, chunkSize); - const chunk = new ArrayBuffer(chunkByteLength); - const sourceArray = new Uint8Array(arrayBuffer, byteOffset, chunkByteLength); - const chunkArray = new Uint8Array(chunk); - chunkArray.set(sourceArray); - byteOffset += chunkByteLength; - yield chunk; - } -} + if (this.numTransparentLayerPortions > 0) { + renderFlags.colorTransparent = true; + } -const DEFAULT_CHUNK_SIZE = 1024 * 1024; -async function* makeBlobIterator(blob, options) { - const chunkSize = (options === null || options === void 0 ? void 0 : options.chunkSize) || DEFAULT_CHUNK_SIZE; - let offset = 0; + if (this.numXRayedLayerPortions > 0) { + const xrayMaterial = this.scene.xrayMaterial._state; + if (xrayMaterial.fill) { + if (xrayMaterial.fillAlpha < 1.0) { + renderFlags.xrayedSilhouetteTransparent = true; + } else { + renderFlags.xrayedSilhouetteOpaque = true; + } + } + if (xrayMaterial.edges) { + if (xrayMaterial.edgeAlpha < 1.0) { + renderFlags.xrayedEdgesTransparent = true; + } else { + renderFlags.xrayedEdgesOpaque = true; + } + } + } - while (offset < blob.size) { - const end = offset + chunkSize; - const chunk = await blob.slice(offset, end).arrayBuffer(); - offset = end; - yield chunk; - } -} + if (this.numEdgesLayerPortions > 0) { + const edgeMaterial = this.scene.edgeMaterial._state; + if (edgeMaterial.edges) { + renderFlags.edgesOpaque = (this.numTransparentLayerPortions < this.numPortions); + if (this.numTransparentLayerPortions > 0) { + renderFlags.edgesTransparent = true; + } + } + } -function makeStreamIterator(stream, options) { - return isBrowser$4 ? makeBrowserStreamIterator(stream, options) : makeNodeStreamIterator(stream); -} + if (this.numSelectedLayerPortions > 0) { + const selectedMaterial = this.scene.selectedMaterial._state; + if (selectedMaterial.fill) { + if (selectedMaterial.fillAlpha < 1.0) { + renderFlags.selectedSilhouetteTransparent = true; + } else { + renderFlags.selectedSilhouetteOpaque = true; + } + } + if (selectedMaterial.edges) { + if (selectedMaterial.edgeAlpha < 1.0) { + renderFlags.selectedEdgesTransparent = true; + } else { + renderFlags.selectedEdgesOpaque = true; + } + } + } -async function* makeBrowserStreamIterator(stream, options) { - const reader = stream.getReader(); - let nextBatchPromise; + if (this.numHighlightedLayerPortions > 0) { + const highlightMaterial = this.scene.highlightMaterial._state; + if (highlightMaterial.fill) { + if (highlightMaterial.fillAlpha < 1.0) { + renderFlags.highlightedSilhouetteTransparent = true; + } else { + renderFlags.highlightedSilhouetteOpaque = true; + } + } + if (highlightMaterial.edges) { + if (highlightMaterial.edgeAlpha < 1.0) { + renderFlags.highlightedEdgesTransparent = true; + } else { + renderFlags.highlightedEdgesOpaque = true; + } + } + } + } - try { - while (true) { - const currentBatchPromise = nextBatchPromise || reader.read(); + // -------------- RENDERING --------------------------------------------------------------------------------------- - if (options !== null && options !== void 0 && options._streamReadAhead) { - nextBatchPromise = reader.read(); - } + /** @private */ + drawColorOpaque(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawColorOpaque(renderFlags, frameCtx); + } + } - const { - done, - value - } = await currentBatchPromise; + /** @private */ + drawColorTransparent(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawColorTransparent(renderFlags, frameCtx); + } + } - if (done) { - return; - } + /** @private */ + drawDepth(frameCtx) { // Dedicated to SAO because it skips transparent objects + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawDepth(renderFlags, frameCtx); + } + } - yield toArrayBuffer(value); + /** @private */ + drawNormals(frameCtx) { // Dedicated to SAO because it skips transparent objects + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawNormals(renderFlags, frameCtx); + } } - } catch (error) { - reader.releaseLock(); - } -} -async function* makeNodeStreamIterator(stream, options) { - for await (const chunk of stream) { - yield toArrayBuffer(chunk); - } -} + /** @private */ + drawSilhouetteXRayed(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawSilhouetteXRayed(renderFlags, frameCtx); + } + } -function makeIterator(data, options) { - if (typeof data === 'string') { - return makeStringIterator(data, options); - } + /** @private */ + drawSilhouetteHighlighted(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawSilhouetteHighlighted(renderFlags, frameCtx); + } + } - if (data instanceof ArrayBuffer) { - return makeArrayBufferIterator(data, options); - } + /** @private */ + drawSilhouetteSelected(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawSilhouetteSelected(renderFlags, frameCtx); + } + } - if (isBlob(data)) { - return makeBlobIterator(data, options); - } + /** @private */ + drawEdgesColorOpaque(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawEdgesColorOpaque(renderFlags, frameCtx); + } + } - if (isReadableStream(data)) { - return makeStreamIterator(data, options); - } + /** @private */ + drawEdgesColorTransparent(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawEdgesColorTransparent(renderFlags, frameCtx); + } + } - if (isResponse(data)) { - const response = data; - return makeStreamIterator(response.body, options); - } + /** @private */ + drawEdgesXRayed(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawEdgesXRayed(renderFlags, frameCtx); + } + } - throw new Error('makeIterator'); -} + /** @private */ + drawEdgesHighlighted(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawEdgesHighlighted(renderFlags, frameCtx); + } + } -const ERR_DATA = 'Cannot convert supplied data type'; -function getArrayBufferOrStringFromDataSync(data, loader, options) { - if (loader.text && typeof data === 'string') { - return data; - } + /** @private */ + drawEdgesSelected(frameCtx) { + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawEdgesSelected(renderFlags, frameCtx); + } + } - if (isBuffer(data)) { - data = data.buffer; - } + /** + * @private + */ + drawOcclusion(frameCtx) { + if (this.numVisibleLayerPortions === 0) { + return; + } + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawOcclusion(renderFlags, frameCtx); + } + } - if (data instanceof ArrayBuffer) { - const arrayBuffer = data; + /** + * @private + */ + drawShadow(frameCtx) { + if (this.numVisibleLayerPortions === 0) { + return; + } + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawShadow(renderFlags, frameCtx); + } + } - if (loader.text && !loader.binary) { - const textDecoder = new TextDecoder('utf8'); - return textDecoder.decode(arrayBuffer); + /** @private */ + drawPickMesh(frameCtx) { + if (this.numVisibleLayerPortions === 0) { + return; + } + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawPickMesh(renderFlags, frameCtx); + } } - return arrayBuffer; - } + /** + * Called by VBOSceneModelMesh.drawPickDepths() + * @private + */ + drawPickDepths(frameCtx) { + if (this.numVisibleLayerPortions === 0) { + return; + } + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawPickDepths(renderFlags, frameCtx); + } + } - if (ArrayBuffer.isView(data)) { - if (loader.text && !loader.binary) { - const textDecoder = new TextDecoder('utf8'); - return textDecoder.decode(data); + /** + * Called by VBOSceneModelMesh.drawPickNormals() + * @private + */ + drawPickNormals(frameCtx) { + if (this.numVisibleLayerPortions === 0) { + return; + } + const renderFlags = this.renderFlags; + for (let i = 0, len = renderFlags.visibleLayers.length; i < len; i++) { + const layerIndex = renderFlags.visibleLayers[i]; + this._layerList[layerIndex].drawPickNormals(renderFlags, frameCtx); + } } - let arrayBuffer = data.buffer; - const byteLength = data.byteLength || data.length; + //------------------------------------------------------------------------------------------------------------------ + // Component members + //------------------------------------------------------------------------------------------------------------------ - if (data.byteOffset !== 0 || byteLength !== arrayBuffer.byteLength) { - arrayBuffer = arrayBuffer.slice(data.byteOffset, data.byteOffset + byteLength); + /** + * Destroys this VBOSceneModel. + */ + destroy() { + for (let layerId in this._currentBatchingLayers) { + if (this._currentBatchingLayers.hasOwnProperty(layerId)) { + this._currentBatchingLayers[layerId].destroy(); + } + } + this._currentBatchingLayers = {}; + this.scene.camera.off(this._onCameraViewMatrix); + for (let i = 0, len = this._layerList.length; i < len; i++) { + this._layerList[i].destroy(); + } + for (let i = 0, len = this._nodeList.length; i < len; i++) { + this._nodeList[i]._destroy(); + } + Object.entries(this._geometries).forEach(([key, geometry]) => { + geometry.destroy(); + }); + this._geometries = {}; + this._textures = {}; + this._textureSets = {}; + this._meshes = {}; + this._nodes = {}; + this.scene._aabbDirty = true; + if (this._isModel) { + this.scene._deregisterModel(this); + } + putScratchMemory(); + super.destroy(); } +} - return arrayBuffer; - } +/** + * @desc A high-performance model representation for efficient rendering and low memory usage. + * + * * This class was replaced with {@link VBOSceneModel} in ````xeokit-sdk v2.3.0````. + * * This class currently extends {@link VBOSceneModel}, in order to maintain backward-compatibility until we remove it. + * * See {@link VBOSceneModel} for API details. + * + * @deprecated + * @implements {Drawable} + * @implements {Entity} + * @implements {SceneModel} + */ +class PerformanceModel extends VBOSceneModel { - throw new Error(ERR_DATA); + /** + * See {@link VBOSceneModel} for details. + * + * @param owner + * @param cfg + */ + constructor(owner, cfg = {}) { + super(owner, cfg); + } } -async function getArrayBufferOrStringFromData(data, loader, options) { - const isArrayBuffer = data instanceof ArrayBuffer || ArrayBuffer.isView(data); - if (typeof data === 'string' || isArrayBuffer) { - return getArrayBufferOrStringFromDataSync(data, loader); - } +/** + * @desc A Skybox. + */ +class Skybox extends Component { - if (isBlob(data)) { - data = await makeResponse(data); - } + /** + * @constructor + * @param {Component} owner Owner component. When destroyed, the owner will destroy this PointLight as well. + * @param {*} [cfg] Skybox configuration + * @param {String} [cfg.id] Optional ID, unique among all components in the parent {Scene}, generated automatically when omitted. + * @param {String} [cfg.src=null] Path to skybox texture + * @param {String} [cfg.encoding="linear"] Texture encoding format. See the {@link Texture#encoding} property for more info. + * @param {Number} [cfg.size=1000] Size of this Skybox, given as the distance from the center at ````[0,0,0]```` to each face. + * @param {Boolean} [cfg.active=true] True when this Skybox is visible. + */ + constructor(owner, cfg = {}) { - if (isResponse(data)) { - const response = data; - await checkResponse(response); - return loader.binary ? await response.arrayBuffer() : await response.text(); - } + super(owner, cfg); - if (isReadableStream(data)) { - data = makeIterator(data, options); - } + this._skyboxMesh = new Mesh(this, { - if (isIterable(data) || isAsyncIterable(data)) { - return concatenateArrayBuffersAsync(data); - } + geometry: new ReadableGeometry(this, { // Box-shaped geometry + primitive: "triangles", + positions: [ + 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // v0-v1-v2-v3 front + 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // v0-v3-v4-v5 right + 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // v0-v5-v6-v1 top + -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // v1-v6-v7-v2 left + -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, // v7-v4-v3-v2 bottom + 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 // v4-v7-v6-v5 back + ], + uv: [ + 0.5, 0.6666, 0.25, 0.6666, 0.25, 0.3333, 0.5, 0.3333, 0.5, 0.6666, 0.5, 0.3333, 0.75, 0.3333, 0.75, 0.6666, + 0.5, 0.6666, 0.5, 1, 0.25, 1, 0.25, 0.6666, 0.25, 0.6666, 0.0, 0.6666, 0.0, 0.3333, 0.25, 0.3333, + 0.25, 0, 0.50, 0, 0.50, 0.3333, 0.25, 0.3333, 0.75, 0.3333, 1.0, 0.3333, 1.0, 0.6666, 0.75, 0.6666 + ], + indices: [ + 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, + 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 + ] + }), + background: true, + scale: [2000, 2000, 2000], // Overridden when we initialize the 'size' property, below + rotation: [0, -90, 0], + material: new PhongMaterial(this, { + ambient: [0, 0, 0], + diffuse: [0, 0, 0], + specular: [0, 0, 0], + emissive: [1, 1, 1], + emissiveMap: new Texture(this, { + src: cfg.src, + flipY: true, + wrapS: "clampToEdge", + wrapT: "clampToEdge", + encoding: cfg.encoding || "sRGB" + }), + backfaces: true // Show interior faces of our skybox geometry + }), + // stationary: true, + visible: false, + pickable: false, + clippable: false, + collidable: false + }); - throw new Error(ERR_DATA); -} + this.size = cfg.size; // Sets 'xyz' property on the Mesh's Scale transform + this.active = cfg.active; + } -function getLoaderContext(context, options, previousContext = null) { - if (previousContext) { - return previousContext; - } - const resolvedContext = { - fetch: getFetchFunction(options, context), - ...context - }; + /** + * Sets the size of this Skybox, given as the distance from the center at [0,0,0] to each face. + * + * Default value is ````1000````. + * + * @param {Number} value The size. + */ + set size(value) { + this._size = value || 1000; + this._skyboxMesh.scale = [this._size, this._size, this._size]; + } - if (!Array.isArray(resolvedContext.loaders)) { - resolvedContext.loaders = null; - } + /** + * Gets the size of this Skybox, given as the distance from the center at [0,0,0] to each face. + * + * Default value is ````1000````. + * + * @returns {Number} The size. + */ + get size() { + return this._size; + } - return resolvedContext; -} -function getLoadersFromContext(loaders, context) { - if (!context && loaders && !Array.isArray(loaders)) { - return loaders; - } + /** + * Sets whether this Skybox is visible or not. + * + * Default value is ````true````. + * + * @param {Boolean} active Whether to make active or not. + */ + set active(active) { + this._skyboxMesh.visible = active; + } - let candidateLoaders; + /** + * Gets if this Skybox is visible or not. + * + * Default active is ````true````. + * + * @returns {Boolean} ````true```` if the Skybox is active. + */ + get active() { + return this._skyboxMesh.visible; + } +} - if (loaders) { - candidateLoaders = Array.isArray(loaders) ? loaders : [loaders]; - } +/** + * Transcodes texture data. + * + * A {@link SceneModel} configured with an appropriate TextureTranscoder will allow us to add textures from + * transcoded buffers or files. For a concrete example, see {@link VBOSceneModel}, which can be configured with + * a {@link KTX2TextureTranscoder}, which allows us to add textures from KTX2 buffers and files. + * + * @interface + */ +class TextureTranscoder { - if (context && context.loaders) { - const contextLoaders = Array.isArray(context.loaders) ? context.loaders : [context.loaders]; - candidateLoaders = candidateLoaders ? [...candidateLoaders, ...contextLoaders] : contextLoaders; - } + /** + * Transcodes texture data from transcoded buffers into a {@link Texture2D}. + * + * @param {ArrayBuffer[]} buffers Transcoded texture data. Given as an array of buffers so that we can support + * multi-image textures, such as cube maps. + * @param {*} config Transcoding options. + * @param {Texture2D} texture The texture to load. + * @returns {Promise} Resolves when the texture has loaded. + */ + transcode(buffers, texture, config = {}) { + } - return candidateLoaders && candidateLoaders.length ? candidateLoaders : null; + /** + * Destroys this transcoder. + */ + destroy() { + } } -async function parse$3(data, loaders, options, context) { - assert$4(!context || typeof context === 'object'); +const screenPos = math.vec4(); +const viewPos = math.vec4(); - if (loaders && !Array.isArray(loaders) && !isLoaderObject(loaders)) { - context = undefined; - options = loaders; - loaders = undefined; - } +const tempVec3a$7 = math.vec3(); +const tempVec3b$4 = math.vec3(); +const tempVec3c$3 = math.vec3(); - data = await data; - options = options || {}; - const { - url - } = getResourceUrlAndType(data); - const typedLoaders = loaders; - const candidateLoaders = getLoadersFromContext(typedLoaders, context); - const loader = await selectLoader(data, candidateLoaders, options); +const tempVec4a$4 = math.vec4(); +const tempVec4b$4 = math.vec4(); +const tempVec4c$1 = math.vec4(); - if (!loader) { - return null; - } +/** + * @private + */ +class PanController { - options = normalizeOptions(options, loader, candidateLoaders, url); - context = getLoaderContext({ - url, - parse: parse$3, - loaders: candidateLoaders - }, options, context); - return await parseWithLoader(loader, data, options, context); -} - -async function parseWithLoader(loader, data, options, context) { - validateWorkerVersion(loader); - data = await getArrayBufferOrStringFromData(data, loader, options); - - if (loader.parseTextSync && typeof data === 'string') { - options.dataType = 'text'; - return loader.parseTextSync(data, options, context, loader); - } - - if (canParseWithWorker(loader, options)) { - return await parseWithWorker(loader, data, options, context, parse$3); - } + constructor(scene) { + this._scene = scene; + } - if (loader.parseText && typeof data === 'string') { - return await loader.parseText(data, options, context, loader); - } + /** + * Dollys the Camera towards the given target 2D canvas position. + * + * When the target's corresponding World-space position is also provided, then this function will also test if we've + * dollied past the target, and will return ````true```` if that's the case. + * + * @param [optionalTargetWorldPos] Optional world position of the target + * @param targetCanvasPos Canvas position of the target + * @param dollyDelta Amount to dolly + * @return True if optionalTargetWorldPos was given, and we've dollied past that position. + */ + dollyToCanvasPos(optionalTargetWorldPos, targetCanvasPos, dollyDelta) { - if (loader.parse) { - return await loader.parse(data, options, context, loader); - } + let dolliedThroughSurface = false; - assert$4(!loader.parseSync); - throw new Error("".concat(loader.id, " loader - no parser found and worker is disabled")); -} + const camera = this._scene.camera; -const VERSION$5 = "3.1.8" ; + if (optionalTargetWorldPos) { + const eyeToWorldPosVec = math.subVec3(optionalTargetWorldPos, camera.eye, tempVec3a$7); + const eyeWorldPosDist = math.lenVec3(eyeToWorldPosVec); + dolliedThroughSurface = (eyeWorldPosDist < dollyDelta); + } -const VERSION$4 = "3.1.8" ; + if (camera.projection === "perspective") { -const VERSION$3 = "3.1.8" ; -const BASIS_CDN_ENCODER_WASM = "https://unpkg.com/@loaders.gl/textures@".concat(VERSION$3, "/dist/libs/basis_encoder.wasm"); -const BASIS_CDN_ENCODER_JS = "https://unpkg.com/@loaders.gl/textures@".concat(VERSION$3, "/dist/libs/basis_encoder.js"); -let loadBasisTranscoderPromise; -async function loadBasisTrascoderModule(options) { - const modules = options.modules || {}; + camera.ortho.scale = camera.ortho.scale - dollyDelta; - if (modules.basis) { - return modules.basis; - } + const unprojectedWorldPos = this._unproject(targetCanvasPos, tempVec4a$4); + const offset = math.subVec3(unprojectedWorldPos, camera.eye, tempVec4c$1); + const moveVec = math.mulVec3Scalar(math.normalizeVec3(offset), -dollyDelta, []); - loadBasisTranscoderPromise = loadBasisTranscoderPromise || loadBasisTrascoder(options); - return await loadBasisTranscoderPromise; -} + camera.eye = [camera.eye[0] - moveVec[0], camera.eye[1] - moveVec[1], camera.eye[2] - moveVec[2]]; + camera.look = [camera.look[0] - moveVec[0], camera.look[1] - moveVec[1], camera.look[2] - moveVec[2]]; -async function loadBasisTrascoder(options) { - let BASIS = null; - let wasmBinary = null; - [BASIS, wasmBinary] = await Promise.all([await loadLibrary('basis_transcoder.js', 'textures', options), await loadLibrary('basis_transcoder.wasm', 'textures', options)]); - BASIS = BASIS || globalThis.BASIS; - return await initializeBasisTrascoderModule(BASIS, wasmBinary); -} + if (optionalTargetWorldPos) { -function initializeBasisTrascoderModule(BasisModule, wasmBinary) { - const options = {}; + // Subtle UX tweak - if we have a target World position, then set camera eye->look distance to + // the same distance as from eye->target. This just gives us a better position for look, + // if we subsequently orbit eye about look, so that we don't orbit a position that's + // suddenly a lot closer than the point we pivoted about on the surface of the last object + // that we click-drag-pivoted on. - if (wasmBinary) { - options.wasmBinary = wasmBinary; - } + const eyeTargetVec = math.subVec3(optionalTargetWorldPos, camera.eye, tempVec3a$7); + const lenEyeTargetVec = math.lenVec3(eyeTargetVec); + const eyeLookVec = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(camera.look, camera.eye, tempVec3b$4)), lenEyeTargetVec); + camera.look = [camera.eye[0] + eyeLookVec[0], camera.eye[1] + eyeLookVec[1], camera.eye[2] + eyeLookVec[2]]; + } - return new Promise(resolve => { - BasisModule(options).then(module => { - const { - BasisFile, - initializeBasis - } = module; - initializeBasis(); - resolve({ - BasisFile - }); - }); - }); -} + } else if (camera.projection === "ortho") { -let loadBasisEncoderPromise; -async function loadBasisEncoderModule(options) { - const modules = options.modules || {}; + // - set ortho scale, getting the unprojected targetCanvasPos before and after, get that difference in a vector; + // - get the vector in which we're dollying; + // - add both vectors to camera eye and look. - if (modules.basisEncoder) { - return modules.basisEncoder; - } + const worldPos1 = this._unproject(targetCanvasPos, tempVec4a$4); - loadBasisEncoderPromise = loadBasisEncoderPromise || loadBasisEncoder(options); - return await loadBasisEncoderPromise; -} + camera.ortho.scale = camera.ortho.scale - dollyDelta; + camera.ortho._update(); // HACK -async function loadBasisEncoder(options) { - let BASIS_ENCODER = null; - let wasmBinary = null; - [BASIS_ENCODER, wasmBinary] = await Promise.all([await loadLibrary(BASIS_CDN_ENCODER_JS, 'textures', options), await loadLibrary(BASIS_CDN_ENCODER_WASM, 'textures', options)]); - BASIS_ENCODER = BASIS_ENCODER || globalThis.BASIS; - return await initializeBasisEncoderModule(BASIS_ENCODER, wasmBinary); -} + const worldPos2 = this._unproject(targetCanvasPos, tempVec4b$4); + const offset = math.subVec3(worldPos2, worldPos1, tempVec4c$1); + const eyeLookMoveVec = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(camera.look, camera.eye, tempVec3a$7)), -dollyDelta, tempVec3b$4); + const moveVec = math.addVec3(offset, eyeLookMoveVec, tempVec3c$3); -function initializeBasisEncoderModule(BasisEncoderModule, wasmBinary) { - const options = {}; + camera.eye = [camera.eye[0] - moveVec[0], camera.eye[1] - moveVec[1], camera.eye[2] - moveVec[2]]; + camera.look = [camera.look[0] - moveVec[0], camera.look[1] - moveVec[1], camera.look[2] - moveVec[2]]; + } - if (wasmBinary) { - options.wasmBinary = wasmBinary; - } + return dolliedThroughSurface; + } - return new Promise(resolve => { - BasisEncoderModule(options).then(module => { - const { - BasisFile, - KTX2File, - initializeBasis, - BasisEncoder - } = module; - initializeBasis(); - resolve({ - BasisFile, - KTX2File, - BasisEncoder - }); - }); - }); -} + _unproject(canvasPos, worldPos) { -const GL_EXTENSIONS_CONSTANTS = { - COMPRESSED_RGB_S3TC_DXT1_EXT: 0x83f0, - COMPRESSED_RGBA_S3TC_DXT1_EXT: 0x83f1, - COMPRESSED_RGBA_S3TC_DXT3_EXT: 0x83f2, - COMPRESSED_RGBA_S3TC_DXT5_EXT: 0x83f3, - COMPRESSED_R11_EAC: 0x9270, - COMPRESSED_SIGNED_R11_EAC: 0x9271, - COMPRESSED_RG11_EAC: 0x9272, - COMPRESSED_SIGNED_RG11_EAC: 0x9273, - COMPRESSED_RGB8_ETC2: 0x9274, - COMPRESSED_RGBA8_ETC2_EAC: 0x9275, - COMPRESSED_SRGB8_ETC2: 0x9276, - COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: 0x9277, - COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: 0x9278, - COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: 0x9279, - COMPRESSED_RGB_PVRTC_4BPPV1_IMG: 0x8c00, - COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: 0x8c02, - COMPRESSED_RGB_PVRTC_2BPPV1_IMG: 0x8c01, - COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: 0x8c03, - COMPRESSED_RGB_ETC1_WEBGL: 0x8d64, - COMPRESSED_RGB_ATC_WEBGL: 0x8c92, - COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL: 0x8c93, - COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL: 0x87ee, - COMPRESSED_RGBA_ASTC_4X4_KHR: 0x93b0, - COMPRESSED_RGBA_ASTC_5X4_KHR: 0x93b1, - COMPRESSED_RGBA_ASTC_5X5_KHR: 0x93b2, - COMPRESSED_RGBA_ASTC_6X5_KHR: 0x93b3, - COMPRESSED_RGBA_ASTC_6X6_KHR: 0x93b4, - COMPRESSED_RGBA_ASTC_8X5_KHR: 0x93b5, - COMPRESSED_RGBA_ASTC_8X6_KHR: 0x93b6, - COMPRESSED_RGBA_ASTC_8X8_KHR: 0x93b7, - COMPRESSED_RGBA_ASTC_10X5_KHR: 0x93b8, - COMPRESSED_RGBA_ASTC_10X6_KHR: 0x93b9, - COMPRESSED_RGBA_ASTC_10X8_KHR: 0x93ba, - COMPRESSED_RGBA_ASTC_10X10_KHR: 0x93bb, - COMPRESSED_RGBA_ASTC_12X10_KHR: 0x93bc, - COMPRESSED_RGBA_ASTC_12X12_KHR: 0x93bd, - COMPRESSED_SRGB8_ALPHA8_ASTC_4X4_KHR: 0x93d0, - COMPRESSED_SRGB8_ALPHA8_ASTC_5X4_KHR: 0x93d1, - COMPRESSED_SRGB8_ALPHA8_ASTC_5X5_KHR: 0x93d2, - COMPRESSED_SRGB8_ALPHA8_ASTC_6X5_KHR: 0x93d3, - COMPRESSED_SRGB8_ALPHA8_ASTC_6X6_KHR: 0x93d4, - COMPRESSED_SRGB8_ALPHA8_ASTC_8X5_KHR: 0x93d5, - COMPRESSED_SRGB8_ALPHA8_ASTC_8X6_KHR: 0x93d6, - COMPRESSED_SRGB8_ALPHA8_ASTC_8X8_KHR: 0x93d7, - COMPRESSED_SRGB8_ALPHA8_ASTC_10X5_KHR: 0x93d8, - COMPRESSED_SRGB8_ALPHA8_ASTC_10X6_KHR: 0x93d9, - COMPRESSED_SRGB8_ALPHA8_ASTC_10X8_KHR: 0x93da, - COMPRESSED_SRGB8_ALPHA8_ASTC_10X10_KHR: 0x93db, - COMPRESSED_SRGB8_ALPHA8_ASTC_12X10_KHR: 0x93dc, - COMPRESSED_SRGB8_ALPHA8_ASTC_12X12_KHR: 0x93dd, - COMPRESSED_RED_RGTC1_EXT: 0x8dbb, - COMPRESSED_SIGNED_RED_RGTC1_EXT: 0x8dbc, - COMPRESSED_RED_GREEN_RGTC2_EXT: 0x8dbd, - COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: 0x8dbe, - COMPRESSED_SRGB_S3TC_DXT1_EXT: 0x8c4c, - COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: 0x8c4d, - COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: 0x8c4e, - COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: 0x8c4f -}; + const camera = this._scene.camera; + const transposedProjectMat = camera.project.transposedMatrix; + const Pt3 = transposedProjectMat.subarray(8, 12); + const Pt4 = transposedProjectMat.subarray(12); + const D = [0, 0, -1.0, 1]; + const screenZ = math.dotVec4(D, Pt3) / math.dotVec4(D, Pt4); -const BROWSER_PREFIXES = ['', 'WEBKIT_', 'MOZ_']; -const WEBGL_EXTENSIONS = { - WEBGL_compressed_texture_s3tc: 'dxt', - WEBGL_compressed_texture_s3tc_srgb: 'dxt-srgb', - WEBGL_compressed_texture_etc1: 'etc1', - WEBGL_compressed_texture_etc: 'etc2', - WEBGL_compressed_texture_pvrtc: 'pvrtc', - WEBGL_compressed_texture_atc: 'atc', - WEBGL_compressed_texture_astc: 'astc', - EXT_texture_compression_rgtc: 'rgtc' -}; -let formats = null; -function getSupportedGPUTextureFormats(gl) { - if (!formats) { - gl = gl || getWebGLContext() || undefined; - formats = new Set(); + camera.project.unproject(canvasPos, screenZ, screenPos, viewPos, worldPos); - for (const prefix of BROWSER_PREFIXES) { - for (const extension in WEBGL_EXTENSIONS) { - if (gl && gl.getExtension("".concat(prefix).concat(extension))) { - const gpuTextureFormat = WEBGL_EXTENSIONS[extension]; - formats.add(gpuTextureFormat); - } - } + return worldPos; } - } - return formats; + destroy() { + } } -function getWebGLContext() { - try { - const canvas = document.createElement('canvas'); - return canvas.getContext('webgl'); - } catch (error) { - return null; - } -} +const tempVec3a$6 = math.vec3(); +const tempVec3b$3 = math.vec3(); +const tempVec3c$2 = math.vec3(); -var n,i,s,a,r,o,l,f;!function(t){t[t.NONE=0]="NONE",t[t.BASISLZ=1]="BASISLZ",t[t.ZSTD=2]="ZSTD",t[t.ZLIB=3]="ZLIB";}(n||(n={})),function(t){t[t.BASICFORMAT=0]="BASICFORMAT";}(i||(i={})),function(t){t[t.UNSPECIFIED=0]="UNSPECIFIED",t[t.ETC1S=163]="ETC1S",t[t.UASTC=166]="UASTC";}(s||(s={})),function(t){t[t.UNSPECIFIED=0]="UNSPECIFIED",t[t.SRGB=1]="SRGB";}(a||(a={})),function(t){t[t.UNSPECIFIED=0]="UNSPECIFIED",t[t.LINEAR=1]="LINEAR",t[t.SRGB=2]="SRGB",t[t.ITU=3]="ITU",t[t.NTSC=4]="NTSC",t[t.SLOG=5]="SLOG",t[t.SLOG2=6]="SLOG2";}(r||(r={})),function(t){t[t.ALPHA_STRAIGHT=0]="ALPHA_STRAIGHT",t[t.ALPHA_PREMULTIPLIED=1]="ALPHA_PREMULTIPLIED";}(o||(o={})),function(t){t[t.RGB=0]="RGB",t[t.RRR=3]="RRR",t[t.GGG=4]="GGG",t[t.AAA=15]="AAA";}(l||(l={})),function(t){t[t.RGB=0]="RGB",t[t.RGBA=3]="RGBA",t[t.RRR=4]="RRR",t[t.RRRG=5]="RRRG";}(f||(f={})); +const tempVec4a$3 = math.vec4(); +const tempVec4b$3 = math.vec4(); +const tempVec4c = math.vec4(); -const KTX2_ID = [0xab, 0x4b, 0x54, 0x58, 0x20, 0x32, 0x30, 0xbb, 0x0d, 0x0a, 0x1a, 0x0a]; -function isKTX(data) { - const id = new Uint8Array(data); - const notKTX = id.byteLength < KTX2_ID.length || id[0] !== KTX2_ID[0] || id[1] !== KTX2_ID[1] || id[2] !== KTX2_ID[2] || id[3] !== KTX2_ID[3] || id[4] !== KTX2_ID[4] || id[5] !== KTX2_ID[5] || id[6] !== KTX2_ID[6] || id[7] !== KTX2_ID[7] || id[8] !== KTX2_ID[8] || id[9] !== KTX2_ID[9] || id[10] !== KTX2_ID[10] || id[11] !== KTX2_ID[11]; - return !notKTX; -} -const OutputFormat = { - etc1: { - basisFormat: 0, - compressed: true, - format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_ETC1_WEBGL - }, - etc2: { - basisFormat: 1, - compressed: true - }, - bc1: { - basisFormat: 2, - compressed: true, - format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT - }, - bc3: { - basisFormat: 3, - compressed: true, - format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT - }, - bc4: { - basisFormat: 4, - compressed: true - }, - bc5: { - basisFormat: 5, - compressed: true - }, - 'bc7-m6-opaque-only': { - basisFormat: 6, - compressed: true - }, - 'bc7-m5': { - basisFormat: 7, - compressed: true - }, - 'pvrtc1-4-rgb': { - basisFormat: 8, - compressed: true, - format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_PVRTC_4BPPV1_IMG - }, - 'pvrtc1-4-rgba': { - basisFormat: 9, - compressed: true, - format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG - }, - 'astc-4x4': { - basisFormat: 10, - compressed: true, - format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_4X4_KHR - }, - 'atc-rgb': { - basisFormat: 11, - compressed: true - }, - 'atc-rgba-interpolated-alpha': { - basisFormat: 12, - compressed: true - }, - rgba32: { - basisFormat: 13, - compressed: false - }, - rgb565: { - basisFormat: 14, - compressed: false - }, - bgr565: { - basisFormat: 15, - compressed: false - }, - rgba4444: { - basisFormat: 16, - compressed: false - } -}; -async function parseBasis(data, options) { - if (options.basis.containerFormat === 'auto') { - if (isKTX(data)) { - const fileConstructors = await loadBasisEncoderModule(options); - return parseKTX2File(fileConstructors.KTX2File, data, options); - } +/** @private */ +class PivotController { - const { - BasisFile - } = await loadBasisTrascoderModule(options); - return parseBasisFile(BasisFile, data, options); - } + /** + * @private + */ + constructor(scene, configs) { - switch (options.basis.module) { - case 'encoder': - const fileConstructors = await loadBasisEncoderModule(options); + // Pivot math by: http://www.derschmale.com/ - switch (options.basis.containerFormat) { - case 'ktx2': - return parseKTX2File(fileConstructors.KTX2File, data, options); + this._scene = scene; + this._configs = configs; + this._pivotWorldPos = math.vec3(); + this._cameraOffset = math.vec3(); + this._azimuth = 0; + this._polar = 0; + this._radius = 0; + this._pivotPosSet = false; // Initially false, true as soon as _pivotWorldPos has been set to some value + this._pivoting = false; // True while pivoting + this._shown = false; - case 'basis': - default: - return parseBasisFile(fileConstructors.BasisFile, data, options); - } + this._pivotViewPos = math.vec4(); + this._pivotProjPos = math.vec4(); + this._pivotCanvasPos = math.vec2(); + this._cameraDirty = true; - case 'transcoder': - default: - const { - BasisFile - } = await loadBasisTrascoderModule(options); - return parseBasisFile(BasisFile, data, options); - } -} + this._onViewMatrix = this._scene.camera.on("viewMatrix", () => { + this._cameraDirty = true; + }); -function parseBasisFile(BasisFile, data, options) { - const basisFile = new BasisFile(new Uint8Array(data)); + this._onProjMatrix = this._scene.camera.on("projMatrix", () => { + this._cameraDirty = true; + }); - try { - if (!basisFile.startTranscoding()) { - return null; + this._onTick = this._scene.on("tick", () => { + this.updatePivotElement(); + }); } - const imageCount = basisFile.getNumImages(); - const images = []; - - for (let imageIndex = 0; imageIndex < imageCount; imageIndex++) { - const levelsCount = basisFile.getNumLevels(imageIndex); - const levels = []; - - for (let levelIndex = 0; levelIndex < levelsCount; levelIndex++) { - levels.push(transcodeImage(basisFile, imageIndex, levelIndex, options)); - } + updatePivotElement() { - images.push(levels); - } + const camera = this._scene.camera; + const canvas = this._scene.canvas; - return images; - } finally { - basisFile.close(); - basisFile.delete(); - } -} + if (this._pivoting && this._cameraDirty) { -function transcodeImage(basisFile, imageIndex, levelIndex, options) { - const width = basisFile.getImageWidth(imageIndex, levelIndex); - const height = basisFile.getImageHeight(imageIndex, levelIndex); - const hasAlpha = basisFile.getHasAlpha(); - const { - compressed, - format, - basisFormat - } = getBasisOptions(options, hasAlpha); - const decodedSize = basisFile.getImageTranscodedSizeInBytes(imageIndex, levelIndex, basisFormat); - const decodedData = new Uint8Array(decodedSize); + math.transformPoint3(camera.viewMatrix, this.getPivotPos(), this._pivotViewPos); + this._pivotViewPos[3] = 1; + math.transformPoint4(camera.projMatrix, this._pivotViewPos, this._pivotProjPos); - if (!basisFile.transcodeImage(decodedData, imageIndex, levelIndex, basisFormat, 0, 0)) { - return null; - } + const canvasAABB = canvas.boundary; + const canvasWidth = canvasAABB[2]; + const canvasHeight = canvasAABB[3]; - return { - width, - height, - data: decodedData, - compressed, - hasAlpha, - format - }; -} + this._pivotCanvasPos[0] = Math.floor((1 + this._pivotProjPos[0] / this._pivotProjPos[3]) * canvasWidth / 2); + this._pivotCanvasPos[1] = Math.floor((1 - this._pivotProjPos[1] / this._pivotProjPos[3]) * canvasHeight / 2); -function parseKTX2File(KTX2File, data, options) { - const ktx2File = new KTX2File(new Uint8Array(data)); + const canvasElem = canvas.canvas; + const canvasBoundingRect = canvasElem.getBoundingClientRect(); - try { - if (!ktx2File.startTranscoding()) { - return null; + if (this._pivotElement) { + this._pivotElement.style.left = (Math.floor(canvasBoundingRect.left + this._pivotCanvasPos[0]) - (this._pivotElement.clientWidth / 2) + window.scrollX) + "px"; + this._pivotElement.style.top = (Math.floor(canvasBoundingRect.top + this._pivotCanvasPos[1]) - (this._pivotElement.clientHeight / 2) + window.scrollY) + "px"; + } + this._cameraDirty = false; + } } - const levelsCount = ktx2File.getLevels(); - const levels = []; - - for (let levelIndex = 0; levelIndex < levelsCount; levelIndex++) { - levels.push(transcodeKTX2Image(ktx2File, levelIndex, options)); - break; + /** + * Sets the HTML DOM element that will represent the pivot position. + * + * @param pivotElement + */ + setPivotElement(pivotElement) { + this._pivotElement = pivotElement; } - return levels; - } finally { - ktx2File.close(); - ktx2File.delete(); - } -} - -function transcodeKTX2Image(ktx2File, levelIndex, options) { - const { - alphaFlag, - height, - width - } = ktx2File.getImageLevelInfo(levelIndex, 0, 0); - const { - compressed, - format, - basisFormat - } = getBasisOptions(options, alphaFlag); - const decodedSize = ktx2File.getImageTranscodedSizeInBytes(levelIndex, 0, 0, basisFormat); - const decodedData = new Uint8Array(decodedSize); + /** + * Begins pivoting. + */ + startPivot() { - if (!ktx2File.transcodeImage(decodedData, levelIndex, 0, 0, basisFormat, 0, -1, -1)) { - return null; - } + if (this._cameraLookingDownwards()) { + this._pivoting = false; + return false; + } - return { - width, - height, - data: decodedData, - compressed, - alphaFlag, - format - }; -} + const camera = this._scene.camera; -function getBasisOptions(options, hasAlpha) { - let format = options && options.basis && options.basis.format; + let lookat = math.lookAtMat4v(camera.eye, camera.look, camera.worldUp); + math.transformPoint3(lookat, this.getPivotPos(), this._cameraOffset); - if (format === 'auto') { - format = selectSupportedBasisFormat(); - } + const pivotPos = this.getPivotPos(); + this._cameraOffset[2] += math.distVec3(camera.eye, pivotPos); - if (typeof format === 'object') { - format = hasAlpha ? format.alpha : format.noAlpha; - } + lookat = math.inverseMat4(lookat); - format = format.toLowerCase(); - return OutputFormat[format]; -} + const offset = math.transformVec3(lookat, this._cameraOffset); + const diff = math.vec3(); -function selectSupportedBasisFormat() { - const supportedFormats = getSupportedGPUTextureFormats(); + math.subVec3(camera.eye, pivotPos, diff); + math.addVec3(diff, offset); - if (supportedFormats.has('astc')) { - return 'astc-4x4'; - } else if (supportedFormats.has('dxt')) { - return { - alpha: 'bc3', - noAlpha: 'bc1' - }; - } else if (supportedFormats.has('pvrtc')) { - return { - alpha: 'pvrtc1-4-rgba', - noAlpha: 'pvrtc1-4-rgb' - }; - } else if (supportedFormats.has('etc1')) { - return 'etc1'; - } else if (supportedFormats.has('etc2')) { - return 'etc2'; - } + if (camera.zUp) { + const t = diff[1]; + diff[1] = diff[2]; + diff[2] = t; + } - return 'rgb565'; -} + this._radius = math.lenVec3(diff); + this._polar = Math.acos(diff[1] / this._radius); + this._azimuth = Math.atan2(diff[0], diff[2]); + this._pivoting = true; + } -const BasisWorkerLoader = { - name: 'Basis', - id: 'basis', - module: 'textures', - version: VERSION$4, - worker: true, - extensions: ['basis', 'ktx2'], - mimeTypes: ['application/octet-stream', 'image/ktx2'], - tests: ['sB'], - binary: true, - options: { - basis: { - format: 'auto', - libraryPath: 'libs/', - containerFormat: 'auto', - module: 'transcoder' + _cameraLookingDownwards() { // Returns true if angle between camera viewing direction and World-space "up" axis is too small + const camera = this._scene.camera; + const forwardAxis = math.normalizeVec3(math.subVec3(camera.look, camera.eye, tempVec3a$6)); + const rightAxis = math.cross3Vec3(forwardAxis, camera.worldUp, tempVec3b$3); + let rightAxisLen = math.sqLenVec3(rightAxis); + return (rightAxisLen <= 0.0001); } - } -}; -const BasisLoader = { ...BasisWorkerLoader, - parse: parseBasis -}; -const VERSION$2 = "3.1.8" ; + /** + * Returns true if we are currently pivoting. + * + * @returns {Boolean} + */ + getPivoting() { + return this._pivoting; + } -const { - _parseImageNode -} = globalThis; -const IMAGE_SUPPORTED = typeof Image !== 'undefined'; -const IMAGE_BITMAP_SUPPORTED = typeof ImageBitmap !== 'undefined'; -const NODE_IMAGE_SUPPORTED = Boolean(_parseImageNode); -const DATA_SUPPORTED = isBrowser$4 ? true : NODE_IMAGE_SUPPORTED; -function isImageTypeSupported(type) { - switch (type) { - case 'auto': - return IMAGE_BITMAP_SUPPORTED || IMAGE_SUPPORTED || DATA_SUPPORTED; + /** + * Sets a 3D World-space position to pivot about. + * + * @param {Number[]} worldPos The new World-space pivot position. + */ + setPivotPos(worldPos) { + this._pivotWorldPos.set(worldPos); + this._pivotPosSet = true; + } - case 'imagebitmap': - return IMAGE_BITMAP_SUPPORTED; + /** + * Sets the pivot position to the 3D projection of the given 2D canvas coordinates on a sphere centered + * at the viewpoint. The radius of the sphere is configured via {@link CameraControl#smartPivot}. + * + * @param canvasPos + */ + setCanvasPivotPos(canvasPos) { + const camera = this._scene.camera; + const pivotShereRadius = Math.abs(math.distVec3(this._scene.center, camera.eye)); + const transposedProjectMat = camera.project.transposedMatrix; + const Pt3 = transposedProjectMat.subarray(8, 12); + const Pt4 = transposedProjectMat.subarray(12); + const D = [0, 0, -1.0, 1]; + const screenZ = math.dotVec4(D, Pt3) / math.dotVec4(D, Pt4); + const worldPos = tempVec4a$3; + camera.project.unproject(canvasPos, screenZ, tempVec4b$3, tempVec4c, worldPos); + const eyeWorldPosVec = math.normalizeVec3(math.subVec3(worldPos, camera.eye, tempVec3a$6)); + const posOnSphere = math.addVec3(camera.eye, math.mulVec3Scalar(eyeWorldPosVec, pivotShereRadius, tempVec3b$3), tempVec3c$2); + this.setPivotPos(posOnSphere); + } - case 'image': - return IMAGE_SUPPORTED; + /** + * Gets the current position we're pivoting about. + * @returns {Number[]} The current World-space pivot position. + */ + getPivotPos() { + return (this._pivotPosSet) ? this._pivotWorldPos : this._scene.camera.look; // Avoid pivoting about [0,0,0] by default + } - case 'data': - return DATA_SUPPORTED; + /** + * Continues to pivot. + * + * @param {Number} yawInc Yaw rotation increment. + * @param {Number} pitchInc Pitch rotation increment. + */ + continuePivot(yawInc, pitchInc) { + if (!this._pivoting) { + return; + } + if (yawInc === 0 && pitchInc === 0) { + return; + } + const camera = this._scene.camera; + var dx = -yawInc; + const dy = -pitchInc; + if (camera.worldUp[2] === 1) { + dx = -dx; + } + this._azimuth += -dx * .01; + this._polar += dy * .01; + this._polar = math.clamp(this._polar, .001, Math.PI - .001); + const pos = [ + this._radius * Math.sin(this._polar) * Math.sin(this._azimuth), + this._radius * Math.cos(this._polar), + this._radius * Math.sin(this._polar) * Math.cos(this._azimuth) + ]; + if (camera.worldUp[2] === 1) { + const t = pos[1]; + pos[1] = pos[2]; + pos[2] = t; + } + // Preserve the eye->look distance, since in xeokit "look" is the point-of-interest, not the direction vector. + const eyeLookLen = math.lenVec3(math.subVec3(camera.look, camera.eye, math.vec3())); + const pivotPos = this.getPivotPos(); + math.addVec3(pos, pivotPos); + let lookat = math.lookAtMat4v(pos, pivotPos, camera.worldUp); + lookat = math.inverseMat4(lookat); + const offset = math.transformVec3(lookat, this._cameraOffset); + lookat[12] -= offset[0]; + lookat[13] -= offset[1]; + lookat[14] -= offset[2]; + const zAxis = [lookat[8], lookat[9], lookat[10]]; + camera.eye = [lookat[12], lookat[13], lookat[14]]; + math.subVec3(camera.eye, math.mulVec3Scalar(zAxis, eyeLookLen), camera.look); + camera.up = [lookat[4], lookat[5], lookat[6]]; + this.showPivot(); + } - default: - throw new Error("@loaders.gl/images: image ".concat(type, " not supported in this environment")); - } -} -function getDefaultImageType() { - if (IMAGE_BITMAP_SUPPORTED) { - return 'imagebitmap'; - } + /** + * Shows the pivot position. + * + * Only works if we set an HTML DOM element to represent the pivot position. + */ + showPivot() { + if (this._shown) { + return; + } + if (this._hideTimeout !== null) { + window.clearTimeout(this._hideTimeout); + this._hideTimeout = null; + } + if (this._pivotElement) { + this.updatePivotElement(); + this._pivotElement.style.visibility = "visible"; + this._shown = true; + this._hideTimeout = window.setTimeout(() => { + this.hidePivot(); + }, 1000); + } + } - if (IMAGE_SUPPORTED) { - return 'image'; - } + /** + * Hides the pivot position. + * + * Only works if we set an HTML DOM element to represent the pivot position. + */ + hidePivot() { + if (!this._shown) { + return; + } + if (this._hideTimeout !== null) { + window.clearTimeout(this._hideTimeout); + this._hideTimeout = null; + } + if (this._pivotElement) { + this._pivotElement.style.visibility = "hidden"; + } + this._shown = false; + } - if (DATA_SUPPORTED) { - return 'data'; - } + /** + * Finishes pivoting. + */ + endPivot() { + this._pivoting = false; + } - throw new Error('Install \'@loaders.gl/polyfills\' to parse images under Node.js'); + destroy() { + this._scene.camera.off(this._onViewMatrix); + this._scene.camera.off(this._onProjMatrix); + this._scene.off(this._onTick); + } } -function getImageType(image) { - const format = getImageTypeOrNull(image); +/** + * + * @private + */ +class PickController { - if (!format) { - throw new Error('Not an image'); - } + constructor(cameraControl, configs) { - return format; -} -function getImageData(image) { - switch (getImageType(image)) { - case 'data': - return image; + this._scene = cameraControl.scene; - case 'image': - case 'imagebitmap': - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); + this._cameraControl = cameraControl; - if (!context) { - throw new Error('getImageData'); - } + this._scene.canvas.canvas.oncontextmenu = function (e) { + e.preventDefault(); + }; - canvas.width = image.width; - canvas.height = image.height; - context.drawImage(image, 0, 0); - return context.getImageData(0, 0, image.width, image.height); + this._configs = configs; - default: - throw new Error('getImageData'); - } -} + /** + * Set true to schedule picking of an Entity. + * @type {boolean} + */ + this.schedulePickEntity = false; -function getImageTypeOrNull(image) { - if (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) { - return 'imagebitmap'; - } + /** + * Set true to schedule picking of a position on teh surface of an Entity. + * @type {boolean} + */ + this.schedulePickSurface = false; - if (typeof Image !== 'undefined' && image instanceof Image) { - return 'image'; - } + /** + * The canvas position at which to do the next scheduled pick. + * @type {Number[]} + */ + this.pickCursorPos = math.vec2(); - if (image && typeof image === 'object' && image.data && image.width && image.height) { - return 'data'; - } + /** + * Will be true after picking to indicate that something was picked. + * @type {boolean} + */ + this.picked = false; - return null; -} + /** + * Will be true after picking to indicate that a position on the surface of an Entity was picked. + * @type {boolean} + */ + this.pickedSurface = false; -const SVG_DATA_URL_PATTERN = /^data:image\/svg\+xml/; -const SVG_URL_PATTERN = /\.svg((\?|#).*)?$/; -function isSVG(url) { - return url && (SVG_DATA_URL_PATTERN.test(url) || SVG_URL_PATTERN.test(url)); -} -function getBlobOrSVGDataUrl(arrayBuffer, url) { - if (isSVG(url)) { - const textDecoder = new TextDecoder(); - let xmlText = textDecoder.decode(arrayBuffer); + /** + * Will hold the PickResult after after picking. + * @type {PickResult} + */ + this.pickResult = null; - try { - if (typeof unescape === 'function' && typeof encodeURIComponent === 'function') { - xmlText = unescape(encodeURIComponent(xmlText)); - } - } catch (error) { - throw new Error(error.message); + this._lastPickedEntityId = null; + + this._needFireEvents = false; } - const src = "data:image/svg+xml;base64,".concat(btoa(xmlText)); - return src; - } + /** + * Immediately attempts a pick, if scheduled. + */ + update() { - return getBlob(arrayBuffer, url); -} -function getBlob(arrayBuffer, url) { - if (isSVG(url)) { - throw new Error('SVG cannot be parsed directly to imagebitmap'); - } + if (!this._configs.pointerEnabled) { + return; + } - return new Blob([new Uint8Array(arrayBuffer)]); -} + if (!this.schedulePickEntity && !this.schedulePickSurface) { + return; + } -async function parseToImage(arrayBuffer, options, url) { - const blobOrDataUrl = getBlobOrSVGDataUrl(arrayBuffer, url); - const URL = self.URL || self.webkitURL; - const objectUrl = typeof blobOrDataUrl !== 'string' && URL.createObjectURL(blobOrDataUrl); + this.picked = false; + this.pickedSurface = false; + this._needFireEvents = false; - try { - return await loadToImage(objectUrl || blobOrDataUrl, options); - } finally { - if (objectUrl) { - URL.revokeObjectURL(objectUrl); - } - } -} -async function loadToImage(url, options) { - const image = new Image(); - image.src = url; + const hasHoverSurfaceSubs = this._cameraControl.hasSubs("hoverSurface"); - if (options.image && options.image.decode && image.decode) { - await image.decode(); - return image; - } + if (this.schedulePickSurface) { + if (this.pickResult && this.pickResult.worldPos) { + const pickResultCanvasPos = this.pickResult.canvasPos; + if (pickResultCanvasPos[0] === this.pickCursorPos[0] && pickResultCanvasPos[1] === this.pickCursorPos[1]) { + this.picked = true; + this.pickedSurface = true; + this._needFireEvents = hasHoverSurfaceSubs; + this.schedulePickEntity = false; + this.schedulePickSurface = false; + return; + } + } + } - return await new Promise((resolve, reject) => { - try { - image.onload = () => resolve(image); + if (this.schedulePickEntity) { + if (this.pickResult) { + const pickResultCanvasPos = this.pickResult.canvasPos; + if (pickResultCanvasPos[0] === this.pickCursorPos[0] && pickResultCanvasPos[1] === this.pickCursorPos[1]) { + this.picked = true; + this.pickedSurface = false; + this._needFireEvents = false; + this.schedulePickEntity = false; + this.schedulePickSurface = false; + return; + } + } + } - image.onerror = err => reject(new Error("Could not load image ".concat(url, ": ").concat(err))); - } catch (error) { - reject(error); - } - }); -} + if (this.schedulePickSurface) { -const EMPTY_OBJECT = {}; -let imagebitmapOptionsSupported = true; -async function parseToImageBitmap(arrayBuffer, options, url) { - let blob; + this.pickResult = this._scene.pick({ + pickSurface: true, + pickSurfaceNormal: false, + canvasPos: this.pickCursorPos + }); - if (isSVG(url)) { - const image = await parseToImage(arrayBuffer, options, url); - blob = image; - } else { - blob = getBlob(arrayBuffer, url); - } + if (this.pickResult) { + this.picked = true; + this.pickedSurface = true; + this._needFireEvents = true; + } - const imagebitmapOptions = options && options.imagebitmap; - return await safeCreateImageBitmap(blob, imagebitmapOptions); -} + } else { // schedulePickEntity == true -async function safeCreateImageBitmap(blob, imagebitmapOptions = null) { - if (isEmptyObject(imagebitmapOptions) || !imagebitmapOptionsSupported) { - imagebitmapOptions = null; - } + this.pickResult = this._scene.pick({ + canvasPos: this.pickCursorPos + }); - if (imagebitmapOptions) { - try { - return await createImageBitmap(blob, imagebitmapOptions); - } catch (error) { - console.warn(error); - imagebitmapOptionsSupported = false; - } - } + if (this.pickResult) { + this.picked = true; + this.pickedSurface = false; + this._needFireEvents = true; + } + } - return await createImageBitmap(blob); -} + this.schedulePickEntity = false; + this.schedulePickSurface = false; + } -function isEmptyObject(object) { - for (const key in object || EMPTY_OBJECT) { - return false; - } + fireEvents() { - return true; -} + if (!this._needFireEvents) { + return; + } -const BIG_ENDIAN = false; -const LITTLE_ENDIAN = true; -function getBinaryImageMetadata(binaryData) { - const dataView = toDataView(binaryData); - return getPngMetadata(dataView) || getJpegMetadata(dataView) || getGifMetadata(dataView) || getBmpMetadata(dataView); -} + if (this.picked && this.pickResult && this.pickResult.entity) { -function getPngMetadata(binaryData) { - const dataView = toDataView(binaryData); - const isPng = dataView.byteLength >= 24 && dataView.getUint32(0, BIG_ENDIAN) === 0x89504e47; + const pickedEntityId = this.pickResult.entity.id; - if (!isPng) { - return null; - } + if (this._lastPickedEntityId !== pickedEntityId) { - return { - mimeType: 'image/png', - width: dataView.getUint32(16, BIG_ENDIAN), - height: dataView.getUint32(20, BIG_ENDIAN) - }; -} - -function getGifMetadata(binaryData) { - const dataView = toDataView(binaryData); - const isGif = dataView.byteLength >= 10 && dataView.getUint32(0, BIG_ENDIAN) === 0x47494638; - - if (!isGif) { - return null; - } - - return { - mimeType: 'image/gif', - width: dataView.getUint16(6, LITTLE_ENDIAN), - height: dataView.getUint16(8, LITTLE_ENDIAN) - }; -} + if (this._lastPickedEntityId !== undefined) { + this._cameraControl.fire("hoverOut", { + entity: this._scene.objects[this._lastPickedEntityId] + }, true); + } -function getBmpMetadata(binaryData) { - const dataView = toDataView(binaryData); - const isBmp = dataView.byteLength >= 14 && dataView.getUint16(0, BIG_ENDIAN) === 0x424d && dataView.getUint32(2, LITTLE_ENDIAN) === dataView.byteLength; + this._cameraControl.fire("hoverEnter", this.pickResult, true); + this._lastPickedEntityId = pickedEntityId; + } - if (!isBmp) { - return null; - } + this._cameraControl.fire("hover", this.pickResult, true); - return { - mimeType: 'image/bmp', - width: dataView.getUint32(18, LITTLE_ENDIAN), - height: dataView.getUint32(22, LITTLE_ENDIAN) - }; -} + if (this.pickResult.worldPos) { + this.pickedSurface = true; + this._cameraControl.fire("hoverSurface", this.pickResult, true); + } -function getJpegMetadata(binaryData) { - const dataView = toDataView(binaryData); - const isJpeg = dataView.byteLength >= 3 && dataView.getUint16(0, BIG_ENDIAN) === 0xffd8 && dataView.getUint8(2) === 0xff; + } else { - if (!isJpeg) { - return null; - } + if (this._lastPickedEntityId !== undefined) { + this._cameraControl.fire("hoverOut", { + entity: this._scene.objects[this._lastPickedEntityId] + }, true); + this._lastPickedEntityId = undefined; + } - const { - tableMarkers, - sofMarkers - } = getJpegMarkers(); - let i = 2; + this._cameraControl.fire("hoverOff", { + canvasPos: this.pickCursorPos + }, true); + } - while (i + 9 < dataView.byteLength) { - const marker = dataView.getUint16(i, BIG_ENDIAN); + this.pickResult = null; - if (sofMarkers.has(marker)) { - return { - mimeType: 'image/jpeg', - height: dataView.getUint16(i + 5, BIG_ENDIAN), - width: dataView.getUint16(i + 7, BIG_ENDIAN) - }; + this._needFireEvents = false; } - if (!tableMarkers.has(marker)) { - return null; + destroy() { } - - i += 2; - i += dataView.getUint16(i, BIG_ENDIAN); - } - - return null; -} - -function getJpegMarkers() { - const tableMarkers = new Set([0xffdb, 0xffc4, 0xffcc, 0xffdd, 0xfffe]); - - for (let i = 0xffe0; i < 0xfff0; ++i) { - tableMarkers.add(i); - } - - const sofMarkers = new Set([0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc9, 0xffca, 0xffcb, 0xffcd, 0xffce, 0xffcf, 0xffde]); - return { - tableMarkers, - sofMarkers - }; } -function toDataView(data) { - if (data instanceof DataView) { - return data; - } +/** + * @private + */ - if (ArrayBuffer.isView(data)) { - return new DataView(data.buffer); - } +const canvasPos = math.vec2(); - if (data instanceof ArrayBuffer) { - return new DataView(data); - } +const getCanvasPosFromEvent$4 = function (event, canvasPos) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + let element = event.target; + let totalOffsetLeft = 0; + let totalOffsetTop = 0; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + canvasPos[0] = event.pageX - totalOffsetLeft; + canvasPos[1] = event.pageY - totalOffsetTop; + } + return canvasPos; +}; - throw new Error('toDataView'); -} +/** + * @private + */ +class MousePanRotateDollyHandler { -async function parseToNodeImage(arrayBuffer, options) { - const { - mimeType - } = getBinaryImageMetadata(arrayBuffer) || {}; - const _parseImageNode = globalThis._parseImageNode; - assert$5(_parseImageNode); - return await _parseImageNode(arrayBuffer, mimeType); -} + constructor(scene, controllers, configs, states, updates) { -async function parseImage(arrayBuffer, options, context) { - options = options || {}; - const imageOptions = options.image || {}; - const imageType = imageOptions.type || 'auto'; - const { - url - } = context || {}; - const loadType = getLoadableImageType(imageType); - let image; + this._scene = scene; - switch (loadType) { - case 'imagebitmap': - image = await parseToImageBitmap(arrayBuffer, options, url); - break; + const pickController = controllers.pickController; - case 'image': - image = await parseToImage(arrayBuffer, options, url); - break; + let lastX = 0; + let lastY = 0; + let lastXDown = 0; + let lastYDown = 0; - case 'data': - image = await parseToNodeImage(arrayBuffer); - break; + let mouseDownLeft; + let mouseDownMiddle; + let mouseDownRight; - default: - assert$5(false); - } + let mouseDownPicked = false; + const pickedWorldPos = math.vec3(); - if (imageType === 'data') { - image = getImageData(image); - } + let mouseMovedOnCanvasSinceLastWheel = true; - return image; -} + const canvas = this._scene.canvas.canvas; -function getLoadableImageType(type) { - switch (type) { - case 'auto': - case 'data': - return getDefaultImageType(); + const keyDown = []; - default: - isImageTypeSupported(type); - return type; - } -} + document.addEventListener("keydown", this._documentKeyDownHandler = (e) => { + if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { + return; + } + const keyCode = e.keyCode; + keyDown[keyCode] = true; + }); -const EXTENSIONS$1 = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'ico', 'svg']; -const MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/bmp', 'image/vnd.microsoft.icon', 'image/svg+xml']; -const DEFAULT_IMAGE_LOADER_OPTIONS = { - image: { - type: 'auto', - decode: true - } -}; -const ImageLoader = { - id: 'image', - module: 'images', - name: 'Images', - version: VERSION$2, - mimeTypes: MIME_TYPES, - extensions: EXTENSIONS$1, - parse: parseImage, - tests: [arrayBuffer => Boolean(getBinaryImageMetadata(new DataView(arrayBuffer)))], - options: DEFAULT_IMAGE_LOADER_OPTIONS -}; + document.addEventListener("keyup", this._documentKeyUpHandler = (e) => { + if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { + return; + } + const keyCode = e.keyCode; + keyDown[keyCode] = false; + }); -const NODE_FORMAT_SUPPORT = ['image/png', 'image/jpeg', 'image/gif']; -const mimeTypeSupported = {}; -function _isImageFormatSupported(mimeType) { - if (mimeTypeSupported[mimeType] === undefined) { - mimeTypeSupported[mimeType] = checkFormatSupport(mimeType); - } + function setMousedownState(pick = true) { + canvas.style.cursor = "move"; + setMousedownPositions(); + if (pick) { + setMousedownPick(); + } + } - return mimeTypeSupported[mimeType]; -} + function setMousedownPositions() { -function checkFormatSupport(mimeType) { - switch (mimeType) { - case 'image/webp': - return checkWebPSupport(); + lastX = states.pointerCanvasPos[0]; + lastY = states.pointerCanvasPos[1]; + lastXDown = states.pointerCanvasPos[0]; + lastYDown = states.pointerCanvasPos[1]; + } - case 'image/svg': - return isBrowser$4; + function setMousedownPick() { + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickSurface = true; + pickController.update(); - default: - if (!isBrowser$4) { - const { - _parseImageNode - } = globalThis; - return Boolean(_parseImageNode) && NODE_FORMAT_SUPPORT.includes(mimeType); - } + if (pickController.picked && pickController.pickedSurface && pickController.pickResult && pickController.pickResult.worldPos) { + mouseDownPicked = true; + pickedWorldPos.set(pickController.pickResult.worldPos); + } else { + mouseDownPicked = false; + } + } - return true; - } -} + canvas.addEventListener("mousedown", this._mouseDownHandler = (e) => { -function checkWebPSupport() { - if (!isBrowser$4) { - return false; - } + if (!(configs.active && configs.pointerEnabled)) { + return; + } - try { - const element = document.createElement('canvas'); - return element.toDataURL('image/webp').indexOf('data:image/webp') === 0; - } catch { - return false; - } -} + switch (e.which) { -function assert$1(condition, message) { - if (!condition) { - throw new Error(message || 'assert failed: gltf'); - } -} + case 1: // Left button -function resolveUrl(url, options) { - const absolute = url.startsWith('data:') || url.startsWith('http:') || url.startsWith('https:'); + if (keyDown[scene.input.KEY_SHIFT] || configs.planView) { - if (absolute) { - return url; - } + mouseDownLeft = true; - const baseUrl = options.baseUri || options.uri; + setMousedownState(); - if (!baseUrl) { - throw new Error("'baseUri' must be provided to resolve relative url ".concat(url)); - } + } else { - return baseUrl.substr(0, baseUrl.lastIndexOf('/') + 1) + url; -} + mouseDownLeft = true; -function getTypedArrayForBufferView(json, buffers, bufferViewIndex) { - const bufferView = json.bufferViews[bufferViewIndex]; - assert$1(bufferView); - const bufferIndex = bufferView.buffer; - const binChunk = buffers[bufferIndex]; - assert$1(binChunk); - const byteOffset = (bufferView.byteOffset || 0) + binChunk.byteOffset; - return new Uint8Array(binChunk.arrayBuffer, byteOffset, bufferView.byteLength); -} + setMousedownState(false); + } -const TYPES = ['SCALAR', 'VEC2', 'VEC3', 'VEC4']; -const ARRAY_CONSTRUCTOR_TO_WEBGL_CONSTANT = [[Int8Array, 5120], [Uint8Array, 5121], [Int16Array, 5122], [Uint16Array, 5123], [Uint32Array, 5125], [Float32Array, 5126], [Float64Array, 5130]]; -const ARRAY_TO_COMPONENT_TYPE = new Map(ARRAY_CONSTRUCTOR_TO_WEBGL_CONSTANT); -const ATTRIBUTE_TYPE_TO_COMPONENTS = { - SCALAR: 1, - VEC2: 2, - VEC3: 3, - VEC4: 4, - MAT2: 4, - MAT3: 9, - MAT4: 16 -}; -const ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE = { - 5120: 1, - 5121: 1, - 5122: 2, - 5123: 2, - 5125: 4, - 5126: 4 -}; -const ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = { - 5120: Int8Array, - 5121: Uint8Array, - 5122: Int16Array, - 5123: Uint16Array, - 5125: Uint32Array, - 5126: Float32Array -}; -function getAccessorTypeFromSize(size) { - const type = TYPES[size - 1]; - return type || TYPES[0]; -} -function getComponentTypeFromArray(typedArray) { - const componentType = ARRAY_TO_COMPONENT_TYPE.get(typedArray.constructor); + break; - if (!componentType) { - throw new Error('Illegal typed array'); - } + case 2: // Middle/both buttons - return componentType; -} -function getAccessorArrayTypeAndLength(accessor, bufferView) { - const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType]; - const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type]; - const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[accessor.componentType]; - const length = accessor.count * components; - const byteLength = accessor.count * components * bytesPerComponent; - assert$1(byteLength >= 0 && byteLength <= bufferView.byteLength); - return { - ArrayType, - length, - byteLength - }; -} + mouseDownMiddle = true; -const DEFAULT_GLTF_JSON = { - asset: { - version: '2.0', - generator: 'loaders.gl' - }, - buffers: [] -}; -class GLTFScenegraph { - constructor(gltf) { - _defineProperty(this, "gltf", void 0); + setMousedownState(); - _defineProperty(this, "sourceBuffers", void 0); + break; - _defineProperty(this, "byteLength", void 0); + case 3: // Right button - this.gltf = gltf || { - json: { ...DEFAULT_GLTF_JSON - }, - buffers: [] - }; - this.sourceBuffers = []; - this.byteLength = 0; + mouseDownRight = true; - if (this.gltf.buffers && this.gltf.buffers[0]) { - this.byteLength = this.gltf.buffers[0].byteLength; - this.sourceBuffers = [this.gltf.buffers[0]]; - } - } + if (configs.panRightClick) { - get json() { - return this.gltf.json; - } + setMousedownState(); + } - getApplicationData(key) { - const data = this.json[key]; - return data; - } + break; + } + }); - getExtraData(key) { - const extras = this.json.extras || {}; - return extras[key]; - } + document.addEventListener("mousemove", this._documentMouseMoveHandler = () => { - getExtension(extensionName) { - const isExtension = this.getUsedExtensions().find(name => name === extensionName); - const extensions = this.json.extensions || {}; - return isExtension ? extensions[extensionName] || true : null; - } + if (!(configs.active && configs.pointerEnabled)) { + return; + } - getRequiredExtension(extensionName) { - const isRequired = this.getRequiredExtensions().find(name => name === extensionName); - return isRequired ? this.getExtension(extensionName) : null; - } + if (!mouseDownLeft && !mouseDownMiddle && !mouseDownRight) { + return; + } - getRequiredExtensions() { - return this.json.extensionsRequired || []; - } + // Scaling drag-rotate to canvas boundary - getUsedExtensions() { - return this.json.extensionsUsed || []; - } + const canvasBoundary = scene.canvas.boundary; - getObjectExtension(object, extensionName) { - const extensions = object.extensions || {}; - return extensions[extensionName]; - } + const canvasWidth = canvasBoundary[2]; + const canvasHeight = canvasBoundary[3]; + const x = states.pointerCanvasPos[0]; + const y = states.pointerCanvasPos[1]; - getScene(index) { - return this.getObject('scenes', index); - } + const panning = keyDown[scene.input.KEY_SHIFT] || configs.planView || (!configs.panRightClick && mouseDownMiddle) || (configs.panRightClick && mouseDownRight); - getNode(index) { - return this.getObject('nodes', index); - } + if (panning) { - getSkin(index) { - return this.getObject('skins', index); - } + const xPanDelta = (x - lastX); + const yPanDelta = (y - lastY); - getMesh(index) { - return this.getObject('meshes', index); - } + const camera = scene.camera; - getMaterial(index) { - return this.getObject('materials', index); - } + // We use only canvasHeight here so that aspect ratio does not distort speed - getAccessor(index) { - return this.getObject('accessors', index); - } + if (camera.projection === "perspective") { - getTexture(index) { - return this.getObject('textures', index); - } + const depth = Math.abs(mouseDownPicked ? math.lenVec3(math.subVec3(pickedWorldPos, scene.camera.eye, [])) : scene.camera.eyeLookDist); + const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0); - getSampler(index) { - return this.getObject('samplers', index); - } + updates.panDeltaX += (1.5 * xPanDelta * targetDistance / canvasHeight); + updates.panDeltaY += (1.5 * yPanDelta * targetDistance / canvasHeight); - getImage(index) { - return this.getObject('images', index); - } + } else { - getBufferView(index) { - return this.getObject('bufferViews', index); - } + updates.panDeltaX += 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight); + updates.panDeltaY += 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight); + } - getBuffer(index) { - return this.getObject('buffers', index); - } + } else if (mouseDownLeft && !mouseDownMiddle && !mouseDownRight) { - getObject(array, index) { - if (typeof index === 'object') { - return index; - } + if (!configs.planView) { // No rotating in plan-view mode - const object = this.json[array] && this.json[array][index]; + if (configs.firstPerson) { + updates.rotateDeltaY -= ((x - lastX) / canvasWidth) * configs.dragRotationRate / 2; + updates.rotateDeltaX += ((y - lastY) / canvasHeight) * (configs.dragRotationRate / 4); - if (!object) { - throw new Error("glTF file error: Could not find ".concat(array, "[").concat(index, "]")); - } + } else { + updates.rotateDeltaY -= ((x - lastX) / canvasWidth) * (configs.dragRotationRate * 1.5); + updates.rotateDeltaX += ((y - lastY) / canvasHeight) * (configs.dragRotationRate * 1.5); + } + } + } - return object; - } + lastX = x; + lastY = y; + }); - getTypedArrayForBufferView(bufferView) { - bufferView = this.getBufferView(bufferView); - const bufferIndex = bufferView.buffer; - const binChunk = this.gltf.buffers[bufferIndex]; - assert$1(binChunk); - const byteOffset = (bufferView.byteOffset || 0) + binChunk.byteOffset; - return new Uint8Array(binChunk.arrayBuffer, byteOffset, bufferView.byteLength); - } + canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => { - getTypedArrayForAccessor(accessor) { - accessor = this.getAccessor(accessor); - const bufferView = this.getBufferView(accessor.bufferView); - const buffer = this.getBuffer(bufferView.buffer); - const arrayBuffer = buffer.data; - const { - ArrayType, - length - } = getAccessorArrayTypeAndLength(accessor, bufferView); - const byteOffset = bufferView.byteOffset + accessor.byteOffset; - return new ArrayType(arrayBuffer, byteOffset, length); - } + if (!(configs.active && configs.pointerEnabled)) { + return; + } - getTypedArrayForImageData(image) { - image = this.getAccessor(image); - const bufferView = this.getBufferView(image.bufferView); - const buffer = this.getBuffer(bufferView.buffer); - const arrayBuffer = buffer.data; - const byteOffset = bufferView.byteOffset || 0; - return new Uint8Array(arrayBuffer, byteOffset, bufferView.byteLength); - } + if (!states.mouseover) { + return; + } - addApplicationData(key, data) { - this.json[key] = data; - return this; - } + mouseMovedOnCanvasSinceLastWheel = true; + }); - addExtraData(key, data) { - this.json.extras = this.json.extras || {}; - this.json.extras[key] = data; - return this; - } + document.addEventListener("mouseup", this._documentMouseUpHandler = (e) => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } + switch (e.which) { + case 1: // Left button + mouseDownLeft = false; + mouseDownMiddle = false; + mouseDownRight = false; + break; + case 2: // Middle/both buttons + mouseDownLeft = false; + mouseDownMiddle = false; + mouseDownRight = false; + break; + case 3: // Right button + mouseDownLeft = false; + mouseDownMiddle = false; + mouseDownRight = false; + break; + } + }); - addObjectExtension(object, extensionName, data) { - object.extensions = object.extensions || {}; - object.extensions[extensionName] = data; - this.registerUsedExtension(extensionName); - return this; - } + canvas.addEventListener("mouseup", this._mouseUpHandler = (e) => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } + switch (e.which) { + case 3: // Right button + getCanvasPosFromEvent$4(e, canvasPos); + const x = canvasPos[0]; + const y = canvasPos[1]; + if (Math.abs(x - lastXDown) < 3 && Math.abs(y - lastYDown) < 3) { + controllers.cameraControl.fire("rightClick", { // For context menus + pagePos: [Math.round(e.pageX), Math.round(e.pageY)], + canvasPos: canvasPos, + event: e + }, true); + } + break; + } + canvas.style.removeProperty("cursor"); + }); - setObjectExtension(object, extensionName, data) { - const extensions = object.extensions || {}; - extensions[extensionName] = data; - } + canvas.addEventListener("mouseenter", this._mouseEnterHandler = () => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } + }); - removeObjectExtension(object, extensionName) { - const extensions = object.extensions || {}; - const extension = extensions[extensionName]; - delete extensions[extensionName]; - return extension; - } + const maxElapsed = 1 / 20; + const minElapsed = 1 / 60; - addExtension(extensionName, extensionData = {}) { - assert$1(extensionData); - this.json.extensions = this.json.extensions || {}; - this.json.extensions[extensionName] = extensionData; - this.registerUsedExtension(extensionName); - return extensionData; - } + let secsNowLast = null; - addRequiredExtension(extensionName, extensionData = {}) { - assert$1(extensionData); - this.addExtension(extensionName, extensionData); - this.registerRequiredExtension(extensionName); - return extensionData; - } + canvas.addEventListener("wheel", this._mouseWheelHandler = (e) => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } + const secsNow = performance.now() / 1000.0; + var secsElapsed = (secsNowLast !== null) ? (secsNow - secsNowLast) : 0; + secsNowLast = secsNow; + if (secsElapsed > maxElapsed) { + secsElapsed = maxElapsed; + } + if (secsElapsed < minElapsed) { + secsElapsed = minElapsed; + } + const delta = Math.max(-1, Math.min(1, -e.deltaY * 40)); + if (delta === 0) { + return; + } + const normalizedDelta = delta / Math.abs(delta); + updates.dollyDelta += -normalizedDelta * secsElapsed * configs.mouseWheelDollyRate; - registerUsedExtension(extensionName) { - this.json.extensionsUsed = this.json.extensionsUsed || []; + if (mouseMovedOnCanvasSinceLastWheel) { + states.followPointerDirty = true; + mouseMovedOnCanvasSinceLastWheel = false; + } - if (!this.json.extensionsUsed.find(ext => ext === extensionName)) { - this.json.extensionsUsed.push(extensionName); + }, {passive: true}); } - } - - registerRequiredExtension(extensionName) { - this.registerUsedExtension(extensionName); - this.json.extensionsRequired = this.json.extensionsRequired || []; - if (!this.json.extensionsRequired.find(ext => ext === extensionName)) { - this.json.extensionsRequired.push(extensionName); + reset() { } - } - removeExtension(extensionName) { - if (this.json.extensionsRequired) { - this._removeStringFromArray(this.json.extensionsRequired, extensionName); - } + destroy() { - if (this.json.extensionsUsed) { - this._removeStringFromArray(this.json.extensionsUsed, extensionName); - } + const canvas = this._scene.canvas.canvas; - if (this.json.extensions) { - delete this.json.extensions[extensionName]; + document.removeEventListener("keydown", this._documentKeyDownHandler); + document.removeEventListener("keyup", this._documentKeyUpHandler); + canvas.removeEventListener("mousedown", this._mouseDownHandler); + document.removeEventListener("mousemove", this._documentMouseMoveHandler); + canvas.removeEventListener("mousemove", this._canvasMouseMoveHandler); + document.removeEventListener("mouseup", this._documentMouseUpHandler); + canvas.removeEventListener("mouseup", this._mouseUpHandler); + canvas.removeEventListener("mouseenter", this._mouseEnterHandler); + canvas.removeEventListener("wheel", this._mouseWheelHandler); } - } - - setDefaultScene(sceneIndex) { - this.json.scene = sceneIndex; - } +} - addScene(scene) { - const { - nodeIndices - } = scene; - this.json.scenes = this.json.scenes || []; - this.json.scenes.push({ - nodes: nodeIndices - }); - return this.json.scenes.length - 1; - } +const center = math.vec3(); +const tempVec3a$5 = math.vec3(); +const tempVec3b$2 = math.vec3(); +const tempVec3c$1 = math.vec3(); +const tempVec3d = math.vec3(); - addNode(node) { - const { - meshIndex, - matrix - } = node; - this.json.nodes = this.json.nodes || []; - const nodeData = { - mesh: meshIndex - }; +const tempCameraTarget = { + eye: math.vec3(), + look: math.vec3(), + up: math.vec3() +}; - if (matrix) { - nodeData.matrix = matrix; - } +/** + * @private + */ +class KeyboardAxisViewHandler { - this.json.nodes.push(nodeData); - return this.json.nodes.length - 1; - } + constructor(scene, controllers, configs, states) { - addMesh(mesh) { - const { - attributes, - indices, - material, - mode = 4 - } = mesh; + this._scene = scene; + const cameraControl = controllers.cameraControl; + const camera = scene.camera; - const accessors = this._addAttributes(attributes); + this._onSceneKeyDown = scene.input.on("keydown", () => { - const glTFMesh = { - primitives: [{ - attributes: accessors, - mode - }] - }; + if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { + return; + } - if (indices) { - const indicesAccessor = this._addIndices(indices); + if (!states.mouseover) { + return; + } - glTFMesh.primitives[0].indices = indicesAccessor; - } + const axisViewRight = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_RIGHT); + const axisViewBack = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_BACK); + const axisViewLeft = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_LEFT); + const axisViewFront = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_FRONT); + const axisViewTop = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_TOP); + const axisViewBottom = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_BOTTOM); - if (Number.isFinite(material)) { - glTFMesh.primitives[0].material = material; - } + if ((!axisViewRight) && (!axisViewBack) && (!axisViewLeft) && (!axisViewFront) && (!axisViewTop) && (!axisViewBottom)) { + return; + } - this.json.meshes = this.json.meshes || []; - this.json.meshes.push(glTFMesh); - return this.json.meshes.length - 1; - } + const aabb = scene.aabb; + const diag = math.getAABB3Diag(aabb); - addPointCloud(attributes) { - const accessorIndices = this._addAttributes(attributes); + math.getAABB3Center(aabb, center); - const glTFMesh = { - primitives: [{ - attributes: accessorIndices, - mode: 0 - }] - }; - this.json.meshes = this.json.meshes || []; - this.json.meshes.push(glTFMesh); - return this.json.meshes.length - 1; - } + const perspectiveDist = Math.abs(diag / Math.tan(controllers.cameraFlight.fitFOV * math.DEGTORAD)); + const orthoScale = diag * 1.1; - addImage(imageData, mimeTypeOpt) { - const metadata = getBinaryImageMetadata(imageData); - const mimeType = mimeTypeOpt || (metadata === null || metadata === void 0 ? void 0 : metadata.mimeType); - const bufferViewIndex = this.addBufferView(imageData); - const glTFImage = { - bufferView: bufferViewIndex, - mimeType - }; - this.json.images = this.json.images || []; - this.json.images.push(glTFImage); - return this.json.images.length - 1; - } + tempCameraTarget.orthoScale = orthoScale; - addBufferView(buffer) { - const byteLength = buffer.byteLength; - assert$1(Number.isFinite(byteLength)); - this.sourceBuffers = this.sourceBuffers || []; - this.sourceBuffers.push(buffer); - const glTFBufferView = { - buffer: 0, - byteOffset: this.byteLength, - byteLength - }; - this.byteLength += padToNBytes(byteLength, 4); - this.json.bufferViews = this.json.bufferViews || []; - this.json.bufferViews.push(glTFBufferView); - return this.json.bufferViews.length - 1; - } + if (axisViewRight) { - addAccessor(bufferViewIndex, accessor) { - const glTFAccessor = { - bufferView: bufferViewIndex, - type: getAccessorTypeFromSize(accessor.size), - componentType: accessor.componentType, - count: accessor.count, - max: accessor.max, - min: accessor.min - }; - this.json.accessors = this.json.accessors || []; - this.json.accessors.push(glTFAccessor); - return this.json.accessors.length - 1; - } + tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldRight, perspectiveDist, tempVec3a$5), tempVec3d)); + tempCameraTarget.look.set(center); + tempCameraTarget.up.set(camera.worldUp); - addBinaryBuffer(sourceBuffer, accessor = { - size: 3 - }) { - const bufferViewIndex = this.addBufferView(sourceBuffer); - let minMax = { - min: accessor.min, - max: accessor.max - }; + } else if (axisViewBack) { - if (!minMax.min || !minMax.max) { - minMax = this._getAccessorMinMax(sourceBuffer, accessor.size); - } + tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldForward, perspectiveDist, tempVec3a$5), tempVec3d)); + tempCameraTarget.look.set(center); + tempCameraTarget.up.set(camera.worldUp); - const accessorDefaults = { - size: accessor.size, - componentType: getComponentTypeFromArray(sourceBuffer), - count: Math.round(sourceBuffer.length / accessor.size), - min: minMax.min, - max: minMax.max - }; - return this.addAccessor(bufferViewIndex, Object.assign(accessorDefaults, accessor)); - } + } else if (axisViewLeft) { - addTexture(texture) { - const { - imageIndex - } = texture; - const glTFTexture = { - source: imageIndex - }; - this.json.textures = this.json.textures || []; - this.json.textures.push(glTFTexture); - return this.json.textures.length - 1; - } + tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldRight, -perspectiveDist, tempVec3a$5), tempVec3d)); + tempCameraTarget.look.set(center); + tempCameraTarget.up.set(camera.worldUp); - addMaterial(pbrMaterialInfo) { - this.json.materials = this.json.materials || []; - this.json.materials.push(pbrMaterialInfo); - return this.json.materials.length - 1; - } + } else if (axisViewFront) { - createBinaryChunk() { - var _this$json, _this$json$buffers; + tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldForward, -perspectiveDist, tempVec3a$5), tempVec3d)); + tempCameraTarget.look.set(center); + tempCameraTarget.up.set(camera.worldUp); - this.gltf.buffers = []; - const totalByteLength = this.byteLength; - const arrayBuffer = new ArrayBuffer(totalByteLength); - const targetArray = new Uint8Array(arrayBuffer); - let dstByteOffset = 0; + } else if (axisViewTop) { - for (const sourceBuffer of this.sourceBuffers || []) { - dstByteOffset = copyToArray(sourceBuffer, targetArray, dstByteOffset); - } + tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldUp, perspectiveDist, tempVec3a$5), tempVec3d)); + tempCameraTarget.look.set(center); + tempCameraTarget.up.set(math.normalizeVec3(math.mulVec3Scalar(camera.worldForward, 1, tempVec3b$2), tempVec3c$1)); - if ((_this$json = this.json) !== null && _this$json !== void 0 && (_this$json$buffers = _this$json.buffers) !== null && _this$json$buffers !== void 0 && _this$json$buffers[0]) { - this.json.buffers[0].byteLength = totalByteLength; - } else { - this.json.buffers = [{ - byteLength: totalByteLength - }]; - } + } else if (axisViewBottom) { - this.gltf.binary = arrayBuffer; - this.sourceBuffers = [arrayBuffer]; - } + tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldUp, -perspectiveDist, tempVec3a$5), tempVec3d)); + tempCameraTarget.look.set(center); + tempCameraTarget.up.set(math.normalizeVec3(math.mulVec3Scalar(camera.worldForward, -1, tempVec3b$2))); + } - _removeStringFromArray(array, string) { - let found = true; + if ((!configs.firstPerson) && configs.followPointer) { + controllers.pivotController.setPivotPos(center); + } - while (found) { - const index = array.indexOf(string); + if (controllers.cameraFlight.duration > 0) { + controllers.cameraFlight.flyTo(tempCameraTarget, () => { + if (controllers.pivotController.getPivoting() && configs.followPointer) { + controllers.pivotController.showPivot(); + } + }); - if (index > -1) { - array.splice(index, 1); - } else { - found = false; - } + } else { + controllers.cameraFlight.jumpTo(tempCameraTarget); + if (controllers.pivotController.getPivoting() && configs.followPointer) { + controllers.pivotController.showPivot(); + } + } + }); } - } - - _addAttributes(attributes = {}) { - const result = {}; - - for (const attributeKey in attributes) { - const attributeData = attributes[attributeKey]; - - const attrName = this._getGltfAttributeName(attributeKey); - const accessor = this.addBinaryBuffer(attributeData.value, attributeData); - result[attrName] = accessor; + reset() { } - return result; - } - - _addIndices(indices) { - return this.addBinaryBuffer(indices, { - size: 1 - }); - } + destroy() { + this._scene.input.off(this._onSceneKeyDown); + } +} - _getGltfAttributeName(attributeName) { - switch (attributeName.toLowerCase()) { - case 'position': - case 'positions': - case 'vertices': - return 'POSITION'; +/** + * @private + */ +class MousePickHandler { - case 'normal': - case 'normals': - return 'NORMAL'; + constructor(scene, controllers, configs, states, updates) { - case 'color': - case 'colors': - return 'COLOR_0'; + this._scene = scene; - case 'texcoord': - case 'texcoords': - return 'TEXCOORD_0'; + const pickController = controllers.pickController; + const pivotController = controllers.pivotController; + const cameraControl = controllers.cameraControl; - default: - return attributeName; - } - } + this._clicks = 0; + this._timeout = null; + this._lastPickedEntityId = null; - _getAccessorMinMax(buffer, size) { - const result = { - min: null, - max: null - }; + let leftDown = false; + let rightDown = false; - if (buffer.length < size) { - return result; - } + const canvas = this._scene.canvas.canvas; - result.min = []; - result.max = []; - const initValues = buffer.subarray(0, size); - - for (const value of initValues) { - result.min.push(value); - result.max.push(value); - } + const flyCameraTo = (pickResult) => { + let pos; + if (pickResult && pickResult.worldPos) { + pos = pickResult.worldPos; + } + const aabb = pickResult && pickResult.entity ? pickResult.entity.aabb : scene.aabb; + if (pos) { // Fly to look at point, don't change eye->look dist + const camera = scene.camera; + math.subVec3(camera.eye, camera.look, []); + controllers.cameraFlight.flyTo({ + // look: pos, + // eye: xeokit.math.addVec3(pos, diff, []), + // up: camera.up, + aabb: aabb + }); + // TODO: Option to back off to fit AABB in view + } else {// Fly to fit target boundary in view + controllers.cameraFlight.flyTo({ + aabb: aabb + }); + } + }; - for (let index = size; index < buffer.length; index += size) { - for (let componentIndex = 0; componentIndex < size; componentIndex++) { - result.min[0 + componentIndex] = Math.min(result.min[0 + componentIndex], buffer[index + componentIndex]); - result.max[0 + componentIndex] = Math.max(result.max[0 + componentIndex], buffer[index + componentIndex]); - } - } + canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => { - return result; - } + if (!(configs.active && configs.pointerEnabled)) { + return; + } -} + if (leftDown || rightDown) { + return; + } -const isWebAssemblySupported = typeof WebAssembly !== 'object'; -const wasm_base = 'B9h9z9tFBBBF8fL9gBB9gLaaaaaFa9gEaaaB9gFaFa9gEaaaFaEMcBFFFGGGEIIILF9wFFFLEFBFKNFaFCx/IFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBF8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBGy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBEn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBIi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBKI9z9iqlBOc+x8ycGBM/qQFTa8jUUUUBCU/EBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAGTkUUUBRNCUoBAG9uC/wgBZHKCUGAKCUG9JyRVAECFJRICBRcGXEXAcAF9PQFAVAFAclAcAVJAF9JyRMGXGXAG9FQBAMCbJHKC9wZRSAKCIrCEJCGrRQANCUGJRfCBRbAIRTEXGXAOATlAQ9PQBCBRISEMATAQJRIGXAS9FQBCBRtCBREEXGXAOAIlCi9PQBCBRISLMANCU/CBJAEJRKGXGXGXGXGXATAECKrJ2BBAtCKZrCEZfIBFGEBMAKhB83EBAKCNJhB83EBSEMAKAI2BIAI2BBHmCKrHYAYCE6HYy86BBAKCFJAICIJAYJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCGJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCEJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCIJAYAmJHY2BBAI2BFHmCKrHPAPCE6HPy86BBAKCLJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCKJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCOJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCNJAYAmJHY2BBAI2BGHmCKrHPAPCE6HPy86BBAKCVJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCcJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCMJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCSJAYAmJHm2BBAI2BEHICKrHYAYCE6HYy86BBAKCQJAmAYJHm2BBAICIrCEZHYAYCE6HYy86BBAKCfJAmAYJHm2BBAICGrCEZHYAYCE6HYy86BBAKCbJAmAYJHK2BBAICEZHIAICE6HIy86BBAKAIJRISGMAKAI2BNAI2BBHmCIrHYAYCb6HYy86BBAKCFJAICNJAYJHY2BBAmCbZHmAmCb6Hmy86BBAKCGJAYAmJHm2BBAI2BFHYCIrHPAPCb6HPy86BBAKCEJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCIJAmAYJHm2BBAI2BGHYCIrHPAPCb6HPy86BBAKCLJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCKJAmAYJHm2BBAI2BEHYCIrHPAPCb6HPy86BBAKCOJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCNJAmAYJHm2BBAI2BIHYCIrHPAPCb6HPy86BBAKCVJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCcJAmAYJHm2BBAI2BLHYCIrHPAPCb6HPy86BBAKCMJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCSJAmAYJHm2BBAI2BKHYCIrHPAPCb6HPy86BBAKCQJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCfJAmAYJHm2BBAI2BOHICIrHYAYCb6HYy86BBAKCbJAmAYJHK2BBAICbZHIAICb6HIy86BBAKAIJRISFMAKAI8pBB83BBAKCNJAICNJ8pBB83BBAICTJRIMAtCGJRtAECTJHEAS9JQBMMGXAIQBCBRISEMGXAM9FQBANAbJ2BBRtCBRKAfREEXAEANCU/CBJAKJ2BBHTCFrCBATCFZl9zAtJHt86BBAEAGJREAKCFJHKAM9HQBMMAfCFJRfAIRTAbCFJHbAG9HQBMMABAcAG9sJANCUGJAMAG9sTkUUUBpANANCUGJAMCaJAG9sJAGTkUUUBpMAMCBAIyAcJRcAIQBMC9+RKSFMCBC99AOAIlAGCAAGCA9Ly6yRKMALCU/EBJ8kUUUUBAKM+OmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUFT+JUUUBpALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM+lLKFaF99GaG99FaG99GXGXAGCI9HQBAF9FQFEXGXGX9DBBB8/9DBBB+/ABCGJHG1BB+yAB1BBHE+yHI+L+TABCFJHL1BBHK+yHO+L+THN9DBBBB9gHVyAN9DBB/+hANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE86BBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG86BBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG86BBABCIJRBAFCaJHFQBSGMMAF9FQBEXGXGX9DBBB8/9DBBB+/ABCIJHG8uFB+yAB8uFBHE+yHI+L+TABCGJHL8uFBHK+yHO+L+THN9DBBBB9gHVyAN9DB/+g6ANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE87FBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG87FBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG87FBABCNJRBAFCaJHFQBMMM/SEIEaE99EaF99GXAF9FQBCBREABRIEXGXGX9D/zI818/AICKJ8uFBHLCEq+y+VHKAI8uFB+y+UHO9DB/+g6+U9DBBB8/9DBBB+/AO9DBBBB9gy+SHN+L9DBBB9P9d9FQBAN+oRVSFMCUUUU94RVMAICIJ8uFBRcAICGJ8uFBRMABALCFJCEZAEqCFWJAV87FBGXGXAKAM+y+UHN9DB/+g6+U9DBBB8/9DBBB+/AN9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRMSFMCUUUU94RMMABALCGJCEZAEqCFWJAM87FBGXGXAKAc+y+UHK9DB/+g6+U9DBBB8/9DBBB+/AK9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRcSFMCUUUU94RcMABALCaJCEZAEqCFWJAc87FBGXGX9DBBU8/AOAO+U+TANAN+U+TAKAK+U+THO9DBBBBAO9DBBBB9gy+R9DB/+g6+U9DBBB8/+SHO+L9DBBB9P9d9FQBAO+oRcSFMCUUUU94RcMABALCEZAEqCFWJAc87FBAICNJRIAECIJREAFCaJHFQBMMM9JBGXAGCGrAF9sHF9FQBEXABAB8oGBHGCNWCN91+yAGCi91CnWCUUU/8EJ+++U84GBABCIJRBAFCaJHFQBMMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEM/lFFFaGXGXAFABqCEZ9FQBABRESFMGXGXAGCT9PQBABRESFMABREEXAEAF8oGBjGBAECIJAFCIJ8oGBjGBAECNJAFCNJ8oGBjGBAECSJAFCSJ8oGBjGBAECTJREAFCTJRFAGC9wJHGCb9LQBMMAGCI9JQBEXAEAF8oGBjGBAFCIJRFAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF2BB86BBAECFJREAFCFJRFAGCaJHGQBMMABMoFFGaGXGXABCEZ9FQBABRESFMAFCgFZC+BwsN9sRIGXGXAGCT9PQBABRESFMABREEXAEAIjGBAECSJAIjGBAECNJAIjGBAECIJAIjGBAECTJREAGC9wJHGCb9LQBMMAGCI9JQBEXAEAIjGBAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF86BBAECFJREAGCaJHGQBMMABMMMFBCUNMIT9kBB'; -const wasm_simd = 'B9h9z9tFBBBF8dL9gBB9gLaaaaaFa9gEaaaB9gGaaB9gFaFaEQSBBFBFFGEGEGIILF9wFFFLEFBFKNFaFCx/aFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBG8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBIy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBKi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBNn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBcI9z9iqlBMc/j9JSIBTEM9+FLa8jUUUUBCTlRBCBRFEXCBRGCBREEXABCNJAGJAECUaAFAGrCFZHIy86BBAEAIJREAGCFJHGCN9HQBMAFCx+YUUBJAE86BBAFCEWCxkUUBJAB8pEN83EBAFCFJHFCUG9HQBMMkRIbaG97FaK978jUUUUBCU/KBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAG/8cBBCUoBAG9uC/wgBZHKCUGAKCUG9JyRNAECFJRKCBRVGXEXAVAF9PQFANAFAVlAVANJAF9JyRcGXGXAG9FQBAcCbJHIC9wZHMCE9sRSAMCFWRQAICIrCEJCGrRfCBRbEXAKRTCBRtGXEXGXAOATlAf9PQBCBRKSLMALCU/CBJAtAM9sJRmATAfJRKCBREGXAMCoB9JQBAOAKlC/gB9JQBCBRIEXAmAIJREGXGXGXGXGXATAICKrJ2BBHYCEZfIBFGEBMAECBDtDMIBSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAEAKDBBBDMIBAKCTJRKMGXGXGXGXGXAYCGrCEZfIBFGEBMAECBDtDMITSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAEAKDBBBDMITAKCTJRKMGXGXGXGXGXAYCIrCEZfIBFGEBMAECBDtDMIASEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAEAKDBBBDMIAAKCTJRKMGXGXGXGXGXAYCKrfIBFGEBMAECBDtDMI8wSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCIJAnDeBJAYCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCNJAnDeBJAYCx+YUUBJ2BBJRKSFMAEAKDBBBDMI8wAKCTJRKMAICoBJREAICUFJAM9LQFAERIAOAKlC/fB9LQBMMGXAEAM9PQBAECErRIEXGXAOAKlCi9PQBCBRKSOMAmAEJRYGXGXGXGXGXATAECKrJ2BBAICKZrCEZfIBFGEBMAYCBDtDMIBSEMAYAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAYAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAYAKDBBBDMIBAKCTJRKMAICGJRIAECTJHEAM9JQBMMGXAK9FQBAKRTAtCFJHtCI6QGSFMMCBRKSEMGXAM9FQBALCUGJAbJREALAbJDBGBRnCBRYEXAEALCU/CBJAYJHIDBIBHdCFD9tAdCFDbHPD9OD9hD9RHdAIAMJDBIBHiCFD9tAiAPD9OD9hD9RHiDQBTFtGmEYIPLdKeOnH8ZAIAQJDBIBHpCFD9tApAPD9OD9hD9RHpAIASJDBIBHyCFD9tAyAPD9OD9hD9RHyDQBTFtGmEYIPLdKeOnH8cDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGEAnD9uHnDyBjGBAEAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJHIAnA8ZA8cDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHnDyBjGBAIAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJHIAnAdAiDQNiV8ZcpMyS8cQ8df8eb8fHdApAyDQNiV8ZcpMyS8cQ8df8eb8fHiDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGED9uHnDyBjGBAIAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJHIAnAdAiDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHnDyBjGBAIAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJREAYCTJHYAM9JQBMMAbCIJHbAG9JQBMMABAVAG9sJALCUGJAcAG9s/8cBBALALCUGJAcCaJAG9sJAG/8cBBMAcCBAKyAVJRVAKQBMC9+RKSFMCBC99AOAKlAGCAAGCA9Ly6yRKMALCU/KBJ8kUUUUBAKMNBT+BUUUBM+KmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUF/8MBALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM/xLGEaK978jUUUUBCAlHE8kUUUUBGXGXAGCI9HQBGXAFC98ZHI9FQBABRGCBRLEXAGAGDBBBHKCiD+rFCiD+sFD/6FHOAKCND+rFCiD+sFD/6FAOD/gFAKCTD+rFCiD+sFD/6FHND/gFD/kFD/lFHVCBDtD+2FHcAOCUUUU94DtHMD9OD9RD/kFHO9DBB/+hDYAOAOD/mFAVAVD/mFANAcANAMD9OD9RD/kFHOAOD/mFD/kFD/kFD/jFD/nFHND/mF9DBBX9LDYHcD/kFCgFDtD9OAKCUUU94DtD9OD9QAOAND/mFAcD/kFCND+rFCU/+EDtD9OD9QAVAND/mFAcD/kFCTD+rFCUU/8ODtD9OD9QDMBBAGCTJRGALCIJHLAI9JQBMMAIAF9PQFAEAFCEZHLCGWHGqCBCTAGl/8MBAEABAICGWJHIAG/8cBBGXAL9FQBAEAEDBIBHKCiD+rFCiD+sFD/6FHOAKCND+rFCiD+sFD/6FAOD/gFAKCTD+rFCiD+sFD/6FHND/gFD/kFD/lFHVCBDtD+2FHcAOCUUUU94DtHMD9OD9RD/kFHO9DBB/+hDYAOAOD/mFAVAVD/mFANAcANAMD9OD9RD/kFHOAOD/mFD/kFD/kFD/jFD/nFHND/mF9DBBX9LDYHcD/kFCgFDtD9OAKCUUU94DtD9OD9QAOAND/mFAcD/kFCND+rFCU/+EDtD9OD9QAVAND/mFAcD/kFCTD+rFCUU/8ODtD9OD9QDMIBMAIAEAG/8cBBSFMABAFC98ZHGT+HUUUBAGAF9PQBAEAFCEZHICEWHLJCBCAALl/8MBAEABAGCEWJHGAL/8cBBAEAIT+HUUUBAGAEAL/8cBBMAECAJ8kUUUUBM+yEGGaO97GXAF9FQBCBRGEXABCTJHEAEDBBBHICBDtHLCUU98D8cFCUU98D8cEHKD9OABDBBBHOAIDQILKOSQfbPden8c8d8e8fCggFDtD9OD/6FAOAIDQBFGENVcMTtmYi8ZpyHICTD+sFD/6FHND/gFAICTD+rFCTD+sFD/6FHVD/gFD/kFD/lFHI9DB/+g6DYAVAIALD+2FHLAVCUUUU94DtHcD9OD9RD/kFHVAVD/mFAIAID/mFANALANAcD9OD9RD/kFHIAID/mFD/kFD/kFD/jFD/nFHND/mF9DBBX9LDYHLD/kFCTD+rFAVAND/mFALD/kFCggEDtD9OD9QHVAIAND/mFALD/kFCaDbCBDnGCBDnECBDnKCBDnOCBDncCBDnMCBDnfCBDnbD9OHIDQNVi8ZcMpySQ8c8dfb8e8fD9QDMBBABAOAKD9OAVAIDQBFTtGEmYILPdKOenD9QDMBBABCAJRBAGCIJHGAF9JQBMMM94FEa8jUUUUBCAlHE8kUUUUBABAFC98ZHIT+JUUUBGXAIAF9PQBAEAFCEZHLCEWHFJCBCAAFl/8MBAEABAICEWJHBAF/8cBBAEALT+JUUUBABAEAF/8cBBMAECAJ8kUUUUBM/hEIGaF97FaL978jUUUUBCTlRGGXAF9FQBCBREEXAGABDBBBHIABCTJHLDBBBHKDQILKOSQfbPden8c8d8e8fHOCTD+sFHNCID+rFDMIBAB9DBBU8/DY9D/zI818/DYANCEDtD9QD/6FD/nFHNAIAKDQBFGENVcMTtmYi8ZpyHICTD+rFCTD+sFD/6FD/mFHKAKD/mFANAICTD+sFD/6FD/mFHVAVD/mFANAOCTD+rFCTD+sFD/6FD/mFHOAOD/mFD/kFD/kFD/lFCBDtD+4FD/jF9DB/+g6DYHND/mF9DBBX9LDYHID/kFCggEDtHcD9OAVAND/mFAID/kFCTD+rFD9QHVAOAND/mFAID/kFCTD+rFAKAND/mFAID/kFAcD9OD9QHNDQBFTtGEmYILPdKOenHID8dBAGDBIBDyB+t+J83EBABCNJAID8dFAGDBIBDyF+t+J83EBALAVANDQNVi8ZcMpySQ8c8dfb8e8fHND8dBAGDBIBDyG+t+J83EBABCiJAND8dFAGDBIBDyE+t+J83EBABCAJRBAECIJHEAF9JQBMMM/3FGEaF978jUUUUBCoBlREGXAGCGrAF9sHIC98ZHL9FQBCBRGABRFEXAFAFDBBBHKCND+rFCND+sFD/6FAKCiD+sFCnD+rFCUUU/8EDtD+uFD/mFDMBBAFCTJRFAGCIJHGAL9JQBMMGXALAI9PQBAEAICEZHGCGWHFqCBCoBAFl/8MBAEABALCGWJHLAF/8cBBGXAG9FQBAEAEDBIBHKCND+rFCND+sFD/6FAKCiD+sFCnD+rFCUUU/8EDtD+uFD/mFDMIBMALAEAF/8cBBMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEMMMFBCUNMIT9tBB'; -const detector = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 3, 2, 0, 0, 5, 3, 1, 0, 1, 12, 1, 0, 10, 22, 2, 12, 0, 65, 0, 65, 0, 65, 0, 252, 10, 0, 0, 11, 7, 0, 65, 0, 253, 15, 26, 11]); -const wasmpack = new Uint8Array([32, 0, 65, 253, 3, 1, 2, 34, 4, 106, 6, 5, 11, 8, 7, 20, 13, 33, 12, 16, 128, 9, 116, 64, 19, 113, 127, 15, 10, 21, 22, 14, 255, 66, 24, 54, 136, 107, 18, 23, 192, 26, 114, 118, 132, 17, 77, 101, 130, 144, 27, 87, 131, 44, 45, 74, 156, 154, 70, 167]); -const FILTERS = { - 0: '', - 1: 'meshopt_decodeFilterOct', - 2: 'meshopt_decodeFilterQuat', - 3: 'meshopt_decodeFilterExp', - NONE: '', - OCTAHEDRAL: 'meshopt_decodeFilterOct', - QUATERNION: 'meshopt_decodeFilterQuat', - EXPONENTIAL: 'meshopt_decodeFilterExp' -}; -const DECODERS = { - 0: 'meshopt_decodeVertexBuffer', - 1: 'meshopt_decodeIndexBuffer', - 2: 'meshopt_decodeIndexSequence', - ATTRIBUTES: 'meshopt_decodeVertexBuffer', - TRIANGLES: 'meshopt_decodeIndexBuffer', - INDICES: 'meshopt_decodeIndexSequence' -}; -function isMeshoptSupported() { - return isWebAssemblySupported; -} -async function meshoptDecodeGltfBuffer(target, count, size, source, mode, filter = 'NONE') { - const instance = await loadWasmInstance(); - decode$5(instance, instance.exports[DECODERS[mode]], target, count, size, source, instance.exports[FILTERS[filter || 'NONE']]); -} -let wasmPromise; + const hoverSubs = cameraControl.hasSubs("hover"); + const hoverOutSubs = cameraControl.hasSubs("hoverOut"); + const hoverOffSubs = cameraControl.hasSubs("hoverOff"); + const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface"); -async function loadWasmInstance() { - if (!wasmPromise) { - wasmPromise = loadWasmModule(); - } + if (hoverSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs) { - return wasmPromise; -} + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickEntity = true; + pickController.schedulePickSurface = hoverSurfaceSubs; -async function loadWasmModule() { - let wasm = wasm_base; + pickController.update(); - if (WebAssembly.validate(detector)) { - wasm = wasm_simd; - console.log('Warning: meshopt_decoder is using experimental SIMD support'); - } + if (pickController.pickResult) { - const result = await WebAssembly.instantiate(unpack(wasm), {}); - await result.instance.exports.__wasm_call_ctors(); - return result.instance; -} + const pickedEntityId = pickController.pickResult.entity.id; -function unpack(data) { - const result = new Uint8Array(data.length); + if (this._lastPickedEntityId !== pickedEntityId) { - for (let i = 0; i < data.length; ++i) { - const ch = data.charCodeAt(i); - result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62; - } + if (this._lastPickedEntityId !== undefined) { - let write = 0; + cameraControl.fire("hoverOut", { // Hovered off an entity + entity: scene.objects[this._lastPickedEntityId] + }, true); + } - for (let i = 0; i < data.length; ++i) { - result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; - } + cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity - return result.buffer.slice(0, write); -} + this._lastPickedEntityId = pickedEntityId; + } -function decode$5(instance, fun, target, count, size, source, filter) { - const sbrk = instance.exports.sbrk; - const count4 = count + 3 & ~3; - const tp = sbrk(count4 * size); - const sp = sbrk(source.length); - const heap = new Uint8Array(instance.exports.memory.buffer); - heap.set(source, sp); - const res = fun(tp, count, size, sp, source.length); + cameraControl.fire("hover", pickController.pickResult, true); - if (res === 0 && filter) { - filter(tp, count4, size); - } + if (pickController.pickResult.worldPos) { // Hovering the surface of an entity + cameraControl.fire("hoverSurface", pickController.pickResult, true); + } - target.set(heap.subarray(tp, tp + count * size)); - sbrk(tp - sbrk(0)); + } else { - if (res !== 0) { - throw new Error("Malformed buffer data: ".concat(res)); - } -} + if (this._lastPickedEntityId !== undefined) { -const EXT_MESHOPT_COMPRESSION = 'EXT_meshopt_compression'; -const name$6 = EXT_MESHOPT_COMPRESSION; -function preprocess$4(gltfData) { - const scenegraph = new GLTFScenegraph(gltfData); + cameraControl.fire("hoverOut", { // Hovered off an entity + entity: scene.objects[this._lastPickedEntityId] + }, true); - if (scenegraph.getRequiredExtensions().includes(EXT_MESHOPT_COMPRESSION) && !isMeshoptSupported()) { - throw new Error("gltf: Required extension ".concat(EXT_MESHOPT_COMPRESSION, " not supported by browser")); - } -} -async function decode$4(gltfData, options) { - var _options$gltf; + this._lastPickedEntityId = undefined; + } - const scenegraph = new GLTFScenegraph(gltfData); + cameraControl.fire("hoverOff", { // Not hovering on any entity + canvasPos: pickController.pickCursorPos + }, true); + } + } + }); - if (!(options !== null && options !== void 0 && (_options$gltf = options.gltf) !== null && _options$gltf !== void 0 && _options$gltf.decompressMeshes)) { - return; - } + canvas.addEventListener('mousedown', this._canvasMouseDownHandler = (e) => { - const promises = []; + if (e.which === 1) { + leftDown = true; + } - for (const bufferViewIndex of gltfData.json.bufferViews || []) { - promises.push(decodeMeshoptBufferView(scenegraph, bufferViewIndex)); - } + if (e.which === 3) { + rightDown = true; + } - await Promise.all(promises); - scenegraph.removeExtension(EXT_MESHOPT_COMPRESSION); -} + const leftButtonDown = (e.which === 1); -async function decodeMeshoptBufferView(scenegraph, bufferView) { - const meshoptExtension = scenegraph.getObjectExtension(bufferView, EXT_MESHOPT_COMPRESSION); + if (!leftButtonDown) { + return; + } - if (meshoptExtension) { - const buffer = bufferView.buffer; - const { - byteOffset = 0, - byteLength = 0, - byteStride, - count, - mode, - filter = 'NONE' - } = meshoptExtension; - const source = new Uint8Array(buffer, byteOffset, byteLength); - const result = new ArrayBuffer(count * byteStride); - await meshoptDecodeGltfBuffer(new Uint8Array(result), count, byteStride, source, mode, filter); - return result; - } + if (!(configs.active && configs.pointerEnabled)) { + return; + } - return null; -} + // Left mouse button down to start pivoting -var EXT_meshopt_compression = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name$6, - preprocess: preprocess$4, - decode: decode$4 -}); + states.mouseDownClientX = e.clientX; + states.mouseDownClientY = e.clientY; + states.mouseDownCursorX = states.pointerCanvasPos[0]; + states.mouseDownCursorY = states.pointerCanvasPos[1]; -const EXT_TEXTURE_WEBP = 'EXT_texture_webp'; -const name$5 = EXT_TEXTURE_WEBP; -function preprocess$3(gltfData, options) { - const scenegraph = new GLTFScenegraph(gltfData); + if ((!configs.firstPerson) && configs.followPointer) { - if (!_isImageFormatSupported('image/webp')) { - if (scenegraph.getRequiredExtensions().includes(EXT_TEXTURE_WEBP)) { - throw new Error("gltf: Required extension ".concat(EXT_TEXTURE_WEBP, " not supported by browser")); - } + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickSurface = true; - return; - } + pickController.update(); - const { - json - } = scenegraph; + if (e.which === 1) {// Left button + const pickResult = pickController.pickResult; + if (pickResult && pickResult.worldPos) { + pivotController.setPivotPos(pickResult.worldPos); + pivotController.startPivot(); + } else { + if (configs.smartPivot) { + pivotController.setCanvasPivotPos(states.pointerCanvasPos); + } else { + pivotController.setPivotPos(scene.camera.look); + } + pivotController.startPivot(); + } + } + } + }); - for (const texture of json.textures || []) { - const extension = scenegraph.getObjectExtension(texture, EXT_TEXTURE_WEBP); + document.addEventListener('mouseup', this._documentMouseUpHandler = (e) => { - if (extension) { - texture.source = extension.source; - } + if (e.which === 1) { + leftDown = false; + } - scenegraph.removeObjectExtension(texture, EXT_TEXTURE_WEBP); - } + if (e.which === 3) { + rightDown = false; + } + }); - scenegraph.removeExtension(EXT_TEXTURE_WEBP); -} + canvas.addEventListener('mouseup', this._canvasMouseUpHandler = (e) => { -var EXT_texture_webp = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name$5, - preprocess: preprocess$3 -}); + if (!(configs.active && configs.pointerEnabled)) { + return; + } -const KHR_TEXTURE_BASISU = 'KHR_texture_basisu'; -const name$4 = KHR_TEXTURE_BASISU; -function preprocess$2(gltfData, options) { - const scene = new GLTFScenegraph(gltfData); - const { - json - } = scene; + const leftButtonUp = (e.which === 1); - for (const texture of json.textures || []) { - const extension = scene.getObjectExtension(texture, KHR_TEXTURE_BASISU); + if (!leftButtonUp) { + return; + } - if (extension) { - texture.source = extension.source; - } + // Left mouse button up to possibly pick or double-pick - scene.removeObjectExtension(texture, KHR_TEXTURE_BASISU); - } + pivotController.hidePivot(); - scene.removeExtension(KHR_TEXTURE_BASISU); -} + if (Math.abs(e.clientX - states.mouseDownClientX) > 3 || Math.abs(e.clientY - states.mouseDownClientY) > 3) { + return; + } -var KHR_texture_basisu = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name$4, - preprocess: preprocess$2 -}); + const pickedSubs = cameraControl.hasSubs("picked"); + const pickedNothingSubs = cameraControl.hasSubs("pickedNothing"); + const pickedSurfaceSubs = cameraControl.hasSubs("pickedSurface"); + const doublePickedSubs = cameraControl.hasSubs("doublePicked"); + const doublePickedSurfaceSubs = cameraControl.hasSubs("doublePickedSurface"); + const doublePickedNothingSubs = cameraControl.hasSubs("doublePickedNothing"); -const VERSION$1 = "3.1.8" ; + if ((!configs.doublePickFlyTo) && + (!doublePickedSubs) && + (!doublePickedSurfaceSubs) && + (!doublePickedNothingSubs)) { -const DEFAULT_DRACO_OPTIONS = { - draco: { - decoderType: typeof WebAssembly === 'object' ? 'wasm' : 'js', - libraryPath: 'libs/', - extraAttributes: {}, - attributeNameEntry: undefined - } -}; -const DracoLoader$1 = { - name: 'Draco', - id: 'draco', - module: 'draco', - shapes: ['mesh'], - version: VERSION$1, - worker: true, - extensions: ['drc'], - mimeTypes: ['application/octet-stream'], - binary: true, - tests: ['DRACO'], - options: DEFAULT_DRACO_OPTIONS -}; + // Avoid the single/double click differentiation timeout -function getMeshBoundingBox(attributes) { - let minX = Infinity; - let minY = Infinity; - let minZ = Infinity; - let maxX = -Infinity; - let maxY = -Infinity; - let maxZ = -Infinity; - const positions = attributes.POSITION ? attributes.POSITION.value : []; - const len = positions && positions.length; + if (pickedSubs || pickedNothingSubs || pickedSurfaceSubs) { - for (let i = 0; i < len; i += 3) { - const x = positions[i]; - const y = positions[i + 1]; - const z = positions[i + 2]; - minX = x < minX ? x : minX; - minY = y < minY ? y : minY; - minZ = z < minZ ? z : minZ; - maxX = x > maxX ? x : maxX; - maxY = y > maxY ? y : maxY; - maxZ = z > maxZ ? z : maxZ; - } + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickEntity = true; + pickController.schedulePickSurface = pickedSurfaceSubs; + pickController.update(); - return [[minX, minY, minZ], [maxX, maxY, maxZ]]; -} + if (pickController.pickResult) { -function assert(condition, message) { - if (!condition) { - throw new Error(message || 'loader assertion failed.'); - } -} + cameraControl.fire("picked", pickController.pickResult, true); -class Schema { - constructor(fields, metadata) { - _defineProperty(this, "fields", void 0); + if (pickController.pickedSurface) { + cameraControl.fire("pickedSurface", pickController.pickResult, true); + } + } else { + cameraControl.fire("pickedNothing", { + canvasPos: states.pointerCanvasPos + }, true); + } + } - _defineProperty(this, "metadata", void 0); + this._clicks = 0; - assert(Array.isArray(fields)); - checkNames(fields); - this.fields = fields; - this.metadata = metadata || new Map(); - } + return; + } - compareTo(other) { - if (this.metadata !== other.metadata) { - return false; - } + this._clicks++; - if (this.fields.length !== other.fields.length) { - return false; - } + if (this._clicks === 1) { // First click - for (let i = 0; i < this.fields.length; ++i) { - if (!this.fields[i].compareTo(other.fields[i])) { - return false; - } - } + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickEntity = configs.doublePickFlyTo; + pickController.schedulePickSurface = pickedSurfaceSubs; + pickController.update(); - return true; - } + const firstClickPickResult = pickController.pickResult; + const firstClickPickSurface = pickController.pickedSurface; - select(...columnNames) { - const nameMap = Object.create(null); + this._timeout = setTimeout(() => { - for (const name of columnNames) { - nameMap[name] = true; - } + if (firstClickPickResult) { - const selectedFields = this.fields.filter(field => nameMap[field.name]); - return new Schema(selectedFields, this.metadata); - } + cameraControl.fire("picked", firstClickPickResult, true); - selectAt(...columnIndices) { - const selectedFields = columnIndices.map(index => this.fields[index]).filter(Boolean); - return new Schema(selectedFields, this.metadata); - } + if (firstClickPickSurface) { - assign(schemaOrFields) { - let fields; - let metadata = this.metadata; + cameraControl.fire("pickedSurface", firstClickPickResult, true); - if (schemaOrFields instanceof Schema) { - const otherSchema = schemaOrFields; - fields = otherSchema.fields; - metadata = mergeMaps(mergeMaps(new Map(), this.metadata), otherSchema.metadata); - } else { - fields = schemaOrFields; - } + if ((!configs.firstPerson) && configs.followPointer) { + controllers.pivotController.setPivotPos(firstClickPickResult.worldPos); + if (controllers.pivotController.startPivot()) { + controllers.pivotController.showPivot(); + } + } + } + } else { + cameraControl.fire("pickedNothing", { + canvasPos: states.pointerCanvasPos + }, true); + } - const fieldMap = Object.create(null); + this._clicks = 0; - for (const field of this.fields) { - fieldMap[field.name] = field; - } + }, configs.doubleClickTimeFrame); - for (const field of fields) { - fieldMap[field.name] = field; - } + } else { // Second click - const mergedFields = Object.values(fieldMap); - return new Schema(mergedFields, metadata); - } + if (this._timeout !== null) { + window.clearTimeout(this._timeout); + this._timeout = null; + } -} + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickEntity = configs.doublePickFlyTo || doublePickedSubs || doublePickedSurfaceSubs; + pickController.schedulePickSurface = pickController.schedulePickEntity && doublePickedSurfaceSubs; + pickController.update(); -function checkNames(fields) { - const usedNames = {}; + if (pickController.pickResult) { - for (const field of fields) { - if (usedNames[field.name]) { - console.warn('Schema: duplicated field name', field.name, field); - } + cameraControl.fire("doublePicked", pickController.pickResult, true); - usedNames[field.name] = true; - } -} + if (pickController.pickedSurface) { + cameraControl.fire("doublePickedSurface", pickController.pickResult, true); + } -function mergeMaps(m1, m2) { - return new Map([...(m1 || new Map()), ...(m2 || new Map())]); -} + if (configs.doublePickFlyTo) { -class Field { - constructor(name, type, nullable = false, metadata = new Map()) { - _defineProperty(this, "name", void 0); + flyCameraTo(pickController.pickResult); - _defineProperty(this, "type", void 0); + if ((!configs.firstPerson) && configs.followPointer) { - _defineProperty(this, "nullable", void 0); + const pickedEntityAABB = pickController.pickResult.entity.aabb; + const pickedEntityCenterPos = math.getAABB3Center(pickedEntityAABB); - _defineProperty(this, "metadata", void 0); + controllers.pivotController.setPivotPos(pickedEntityCenterPos); - this.name = name; - this.type = type; - this.nullable = nullable; - this.metadata = metadata; - } + if (controllers.pivotController.startPivot()) { + controllers.pivotController.showPivot(); + } + } + } - get typeId() { - return this.type && this.type.typeId; - } + } else { - clone() { - return new Field(this.name, this.type, this.nullable, this.metadata); - } + cameraControl.fire("doublePickedNothing", { + canvasPos: states.pointerCanvasPos + }, true); - compareTo(other) { - return this.name === other.name && this.type === other.type && this.nullable === other.nullable && this.metadata === other.metadata; - } + if (configs.doublePickFlyTo) { - toString() { - return "".concat(this.type).concat(this.nullable ? ', nullable' : '').concat(this.metadata ? ", metadata: ".concat(this.metadata) : ''); - } + flyCameraTo(); -} + if ((!configs.firstPerson) && configs.followPointer) { -let Type; + const sceneAABB = scene.aabb; + const sceneCenterPos = math.getAABB3Center(sceneAABB); -(function (Type) { - Type[Type["NONE"] = 0] = "NONE"; - Type[Type["Null"] = 1] = "Null"; - Type[Type["Int"] = 2] = "Int"; - Type[Type["Float"] = 3] = "Float"; - Type[Type["Binary"] = 4] = "Binary"; - Type[Type["Utf8"] = 5] = "Utf8"; - Type[Type["Bool"] = 6] = "Bool"; - Type[Type["Decimal"] = 7] = "Decimal"; - Type[Type["Date"] = 8] = "Date"; - Type[Type["Time"] = 9] = "Time"; - Type[Type["Timestamp"] = 10] = "Timestamp"; - Type[Type["Interval"] = 11] = "Interval"; - Type[Type["List"] = 12] = "List"; - Type[Type["Struct"] = 13] = "Struct"; - Type[Type["Union"] = 14] = "Union"; - Type[Type["FixedSizeBinary"] = 15] = "FixedSizeBinary"; - Type[Type["FixedSizeList"] = 16] = "FixedSizeList"; - Type[Type["Map"] = 17] = "Map"; - Type[Type["Dictionary"] = -1] = "Dictionary"; - Type[Type["Int8"] = -2] = "Int8"; - Type[Type["Int16"] = -3] = "Int16"; - Type[Type["Int32"] = -4] = "Int32"; - Type[Type["Int64"] = -5] = "Int64"; - Type[Type["Uint8"] = -6] = "Uint8"; - Type[Type["Uint16"] = -7] = "Uint16"; - Type[Type["Uint32"] = -8] = "Uint32"; - Type[Type["Uint64"] = -9] = "Uint64"; - Type[Type["Float16"] = -10] = "Float16"; - Type[Type["Float32"] = -11] = "Float32"; - Type[Type["Float64"] = -12] = "Float64"; - Type[Type["DateDay"] = -13] = "DateDay"; - Type[Type["DateMillisecond"] = -14] = "DateMillisecond"; - Type[Type["TimestampSecond"] = -15] = "TimestampSecond"; - Type[Type["TimestampMillisecond"] = -16] = "TimestampMillisecond"; - Type[Type["TimestampMicrosecond"] = -17] = "TimestampMicrosecond"; - Type[Type["TimestampNanosecond"] = -18] = "TimestampNanosecond"; - Type[Type["TimeSecond"] = -19] = "TimeSecond"; - Type[Type["TimeMillisecond"] = -20] = "TimeMillisecond"; - Type[Type["TimeMicrosecond"] = -21] = "TimeMicrosecond"; - Type[Type["TimeNanosecond"] = -22] = "TimeNanosecond"; - Type[Type["DenseUnion"] = -23] = "DenseUnion"; - Type[Type["SparseUnion"] = -24] = "SparseUnion"; - Type[Type["IntervalDayTime"] = -25] = "IntervalDayTime"; - Type[Type["IntervalYearMonth"] = -26] = "IntervalYearMonth"; -})(Type || (Type = {})); + controllers.pivotController.setPivotPos(sceneCenterPos); -let _Symbol$toStringTag, _Symbol$toStringTag2, _Symbol$toStringTag7; -class DataType { - static isNull(x) { - return x && x.typeId === Type.Null; - } + if (controllers.pivotController.startPivot()) { + controllers.pivotController.showPivot(); + } + } + } + } - static isInt(x) { - return x && x.typeId === Type.Int; - } + this._clicks = 0; + } + }, false); + } - static isFloat(x) { - return x && x.typeId === Type.Float; - } + reset() { + this._clicks = 0; + this._lastPickedEntityId = null; + if (this._timeout) { + window.clearTimeout(this._timeout); + this._timeout = null; + } + } - static isBinary(x) { - return x && x.typeId === Type.Binary; - } + destroy() { + const canvas = this._scene.canvas.canvas; + canvas.removeEventListener("mousemove", this._canvasMouseMoveHandler); + canvas.removeEventListener("mousedown", this._canvasMouseDownHandler); + document.removeEventListener("mouseup", this._documentMouseUpHandler); + canvas.removeEventListener("mouseup", this._canvasMouseUpHandler); + if (this._timeout) { + window.clearTimeout(this._timeout); + this._timeout = null; + } + } +} - static isUtf8(x) { - return x && x.typeId === Type.Utf8; - } +/** + * @private + */ +class KeyboardPanRotateDollyHandler { - static isBool(x) { - return x && x.typeId === Type.Bool; - } + constructor(scene, controllers, configs, states, updates) { - static isDecimal(x) { - return x && x.typeId === Type.Decimal; - } + this._scene = scene; + const input = scene.input; - static isDate(x) { - return x && x.typeId === Type.Date; - } + const keyDownMap = []; - static isTime(x) { - return x && x.typeId === Type.Time; - } + const canvas = scene.canvas.canvas; - static isTimestamp(x) { - return x && x.typeId === Type.Timestamp; - } + let mouseMovedSinceLastKeyboardDolly = true; - static isInterval(x) { - return x && x.typeId === Type.Interval; - } + this._onSceneMouseMove = input.on("mousemove", () => { + mouseMovedSinceLastKeyboardDolly = true; + }); - static isList(x) { - return x && x.typeId === Type.List; - } + this._onSceneKeyDown = input.on("keydown", (keyCode) => { + if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { + return; + } + if (!states.mouseover) { + return; + } + keyDownMap[keyCode] = true; - static isStruct(x) { - return x && x.typeId === Type.Struct; - } + if (keyCode === input.KEY_SHIFT) { + canvas.style.cursor = "move"; + } + }); - static isUnion(x) { - return x && x.typeId === Type.Union; - } + this._onSceneKeyUp = input.on("keyup", (keyCode) => { + if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { + return; + } + if (!states.mouseover) { + return; + } + keyDownMap[keyCode] = false; - static isFixedSizeBinary(x) { - return x && x.typeId === Type.FixedSizeBinary; - } + if (keyCode === input.KEY_SHIFT) { + canvas.style.cursor = null; + } + }); - static isFixedSizeList(x) { - return x && x.typeId === Type.FixedSizeList; - } + this._onTick = scene.on("tick", (e) => { - static isMap(x) { - return x && x.typeId === Type.Map; - } + if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { + return; + } - static isDictionary(x) { - return x && x.typeId === Type.Dictionary; - } + if (!states.mouseover) { + return; + } - get typeId() { - return Type.NONE; - } + const cameraControl = controllers.cameraControl; + const elapsedSecs = (e.deltaTime / 1000.0); - compareTo(other) { - return this === other; - } + //------------------------------------------------------------------------------------------------- + // Keyboard rotation + //------------------------------------------------------------------------------------------------- -} -_Symbol$toStringTag = Symbol.toStringTag; -class Int extends DataType { - constructor(isSigned, bitWidth) { - super(); + if (!configs.planView) { - _defineProperty(this, "isSigned", void 0); + const rotateYPos = cameraControl._isKeyDownForAction(cameraControl.ROTATE_Y_POS, keyDownMap); + const rotateYNeg = cameraControl._isKeyDownForAction(cameraControl.ROTATE_Y_NEG, keyDownMap); + const rotateXPos = cameraControl._isKeyDownForAction(cameraControl.ROTATE_X_POS, keyDownMap); + const rotateXNeg = cameraControl._isKeyDownForAction(cameraControl.ROTATE_X_NEG, keyDownMap); - _defineProperty(this, "bitWidth", void 0); + const orbitDelta = elapsedSecs * configs.keyboardRotationRate; - this.isSigned = isSigned; - this.bitWidth = bitWidth; - } + if (rotateYPos || rotateYNeg || rotateXPos || rotateXNeg) { - get typeId() { - return Type.Int; - } + if ((!configs.firstPerson) && configs.followPointer) { + controllers.pivotController.startPivot(); + } - get [_Symbol$toStringTag]() { - return 'Int'; - } + if (rotateYPos) { + updates.rotateDeltaY += orbitDelta; - toString() { - return "".concat(this.isSigned ? 'I' : 'Ui', "nt").concat(this.bitWidth); - } + } else if (rotateYNeg) { + updates.rotateDeltaY -= orbitDelta; + } -} -class Int8 extends Int { - constructor() { - super(true, 8); - } + if (rotateXPos) { + updates.rotateDeltaX += orbitDelta; -} -class Int16 extends Int { - constructor() { - super(true, 16); - } + } else if (rotateXNeg) { + updates.rotateDeltaX -= orbitDelta; + } -} -class Int32 extends Int { - constructor() { - super(true, 32); - } + if ((!configs.firstPerson) && configs.followPointer) { + controllers.pivotController.startPivot(); + } + } + } -} -class Uint8 extends Int { - constructor() { - super(false, 8); - } + //------------------------------------------------------------------------------------------------- + // Keyboard panning + //------------------------------------------------------------------------------------------------- -} -class Uint16 extends Int { - constructor() { - super(false, 16); - } + if (!keyDownMap[input.KEY_CTRL] && !keyDownMap[input.KEY_ALT]) { -} -class Uint32 extends Int { - constructor() { - super(false, 32); - } + const dollyBackwards = cameraControl._isKeyDownForAction(cameraControl.DOLLY_BACKWARDS, keyDownMap); + const dollyForwards = cameraControl._isKeyDownForAction(cameraControl.DOLLY_FORWARDS, keyDownMap); -} -const Precision = { - HALF: 16, - SINGLE: 32, - DOUBLE: 64 -}; -_Symbol$toStringTag2 = Symbol.toStringTag; -class Float extends DataType { - constructor(precision) { - super(); + if (dollyBackwards || dollyForwards) { - _defineProperty(this, "precision", void 0); + const dollyDelta = elapsedSecs * configs.keyboardDollyRate; - this.precision = precision; - } + if ((!configs.firstPerson) && configs.followPointer) { + controllers.pivotController.startPivot(); + } + if (dollyForwards) { + updates.dollyDelta -= dollyDelta; + } else if (dollyBackwards) { + updates.dollyDelta += dollyDelta; + } - get typeId() { - return Type.Float; - } + if (mouseMovedSinceLastKeyboardDolly) { + states.followPointerDirty = true; + mouseMovedSinceLastKeyboardDolly = false; + } + } + } - get [_Symbol$toStringTag2]() { - return 'Float'; - } + const panForwards = cameraControl._isKeyDownForAction(cameraControl.PAN_FORWARDS, keyDownMap); + const panBackwards = cameraControl._isKeyDownForAction(cameraControl.PAN_BACKWARDS, keyDownMap); + const panLeft = cameraControl._isKeyDownForAction(cameraControl.PAN_LEFT, keyDownMap); + const panRight = cameraControl._isKeyDownForAction(cameraControl.PAN_RIGHT, keyDownMap); + const panUp = cameraControl._isKeyDownForAction(cameraControl.PAN_UP, keyDownMap); + const panDown = cameraControl._isKeyDownForAction(cameraControl.PAN_DOWN, keyDownMap); - toString() { - return "Float".concat(this.precision); - } + const panDelta = (keyDownMap[input.KEY_ALT] ? 0.3 : 1.0) * elapsedSecs * configs.keyboardPanRate; // ALT for slower pan rate -} -class Float32 extends Float { - constructor() { - super(Precision.SINGLE); - } + if (panForwards || panBackwards || panLeft || panRight || panUp || panDown) { -} -class Float64 extends Float { - constructor() { - super(Precision.DOUBLE); - } + if ((!configs.firstPerson) && configs.followPointer) { + controllers.pivotController.startPivot(); + } -} -_Symbol$toStringTag7 = Symbol.toStringTag; -class FixedSizeList extends DataType { - constructor(listSize, child) { - super(); + if (panDown) { + updates.panDeltaY += panDelta; - _defineProperty(this, "listSize", void 0); + } else if (panUp) { + updates.panDeltaY += -panDelta; + } - _defineProperty(this, "children", void 0); + if (panRight) { + updates.panDeltaX += -panDelta; - this.listSize = listSize; - this.children = [child]; - } + } else if (panLeft) { + updates.panDeltaX += panDelta; + } - get typeId() { - return Type.FixedSizeList; - } + if (panBackwards) { + updates.panDeltaZ += panDelta; - get valueType() { - return this.children[0].type; - } + } else if (panForwards) { + updates.panDeltaZ += -panDelta; + } + } + }); + } - get valueField() { - return this.children[0]; - } + reset() { + } - get [_Symbol$toStringTag7]() { - return 'FixedSizeList'; - } + destroy() { - toString() { - return "FixedSizeList[".concat(this.listSize, "]<").concat(this.valueType, ">"); - } + this._scene.off(this._onTick); + this._scene.input.off(this._onSceneMouseMove); + this._scene.input.off(this._onSceneKeyDown); + this._scene.input.off(this._onSceneKeyUp); + } } -function getArrowTypeFromTypedArray(array) { - switch (array.constructor) { - case Int8Array: - return new Int8(); +const SCALE_DOLLY_EACH_FRAME = 1; // Recalculate dolly speed for eye->target distance on each Nth frame +const EPSILON = 0.001; +const tempVec3$1 = math.vec3(); - case Uint8Array: - return new Uint8(); +/** + * Handles camera updates on each "tick" that were scheduled by the various controllers. + * + * @private + */ +class CameraUpdater { - case Int16Array: - return new Int16(); + constructor(scene, controllers, configs, states, updates) { - case Uint16Array: - return new Uint16(); + this._scene = scene; + const camera = scene.camera; + const pickController = controllers.pickController; + const pivotController = controllers.pivotController; + const panController = controllers.panController; - case Int32Array: - return new Int32(); + let countDown = SCALE_DOLLY_EACH_FRAME; // Decrements on each tick + let dollyDistFactor = 1.0; // Calculated when countDown is zero + let followPointerWorldPos = null; // Holds the pointer's World position when configs.followPointer is true + + this._onTick = scene.on("tick", () => { - case Uint32Array: - return new Uint32(); + if (!(configs.active && configs.pointerEnabled)) { + return; + } - case Float32Array: - return new Float32(); + let cursorType = "default"; - case Float64Array: - return new Float64(); + //---------------------------------------------------------------------------------------------------------- + // Dolly decay + //------------------------------------------------------------------------------------ ---------------------- - default: - throw new Error('array type not supported'); - } -} + if (Math.abs(updates.dollyDelta) < EPSILON) { + updates.dollyDelta = 0; + } -function deduceMeshField(attributeName, attribute, optionalMetadata) { - const type = getArrowTypeFromTypedArray(attribute.value); - const metadata = optionalMetadata ? optionalMetadata : makeMeshAttributeMetadata(attribute); - const field = new Field(attributeName, new FixedSizeList(attribute.size, new Field('value', type)), false, metadata); - return field; -} + //---------------------------------------------------------------------------------------------------------- + // Rotation decay + //---------------------------------------------------------------------------------------------------------- -function makeMeshAttributeMetadata(attribute) { - const result = new Map(); + if (Math.abs(updates.rotateDeltaX) < EPSILON) { + updates.rotateDeltaX = 0; + } - if ('byteOffset' in attribute) { - result.set('byteOffset', attribute.byteOffset.toString(10)); - } + if (Math.abs(updates.rotateDeltaY) < EPSILON) { + updates.rotateDeltaY = 0; + } - if ('byteStride' in attribute) { - result.set('byteStride', attribute.byteStride.toString(10)); - } + if (updates.rotateDeltaX !== 0 || updates.rotateDeltaY !== 0) { + updates.dollyDelta = 0; + } - if ('normalized' in attribute) { - result.set('normalized', attribute.normalized.toString()); - } + //---------------------------------------------------------------------------------------------------------- + // Dolly speed eye->look scaling + // + // If pointer is over an object, then dolly speed is proportional to the distance to that object. + // + // If pointer is not over an object, then dolly speed is proportional to the distance to the last + // object the pointer was over. This is so that we can dolly to structures that may have gaps through + // which empty background shows, that the pointer may inadvertently be over. In these cases, we don't + // want dolly speed wildly varying depending on how accurately the user avoids the gaps with the pointer. + //---------------------------------------------------------------------------------------------------------- - return result; -} + if (configs.followPointer) { -function getDracoSchema(attributes, loaderData, indices) { - const metadataMap = makeMetadata(loaderData.metadata); - const fields = []; - const namedLoaderDataAttributes = transformAttributesLoaderData(loaderData.attributes); + if (--countDown <= 0) { - for (const attributeName in attributes) { - const attribute = attributes[attributeName]; - const field = getArrowFieldFromAttribute(attributeName, attribute, namedLoaderDataAttributes[attributeName]); - fields.push(field); - } + countDown = SCALE_DOLLY_EACH_FRAME; - if (indices) { - const indicesField = getArrowFieldFromAttribute('indices', indices); - fields.push(indicesField); - } + if (updates.dollyDelta !== 0) { + if (updates.rotateDeltaY === 0 && updates.rotateDeltaX === 0) { - return new Schema(fields, metadataMap); -} - -function transformAttributesLoaderData(loaderData) { - const result = {}; + if (configs.followPointer && states.followPointerDirty) { - for (const key in loaderData) { - const dracoAttribute = loaderData[key]; - result[dracoAttribute.name || 'undefined'] = dracoAttribute; - } + pickController.pickCursorPos = states.pointerCanvasPos; + pickController.schedulePickSurface = true; + pickController.update(); - return result; -} + if (pickController.pickResult && pickController.pickResult.worldPos) { + followPointerWorldPos = pickController.pickResult.worldPos; + + } else { + dollyDistFactor = 1.0; + followPointerWorldPos = null; + } -function getArrowFieldFromAttribute(attributeName, attribute, loaderData) { - const metadataMap = loaderData ? makeMetadata(loaderData.metadata) : undefined; - const field = deduceMeshField(attributeName, attribute, metadataMap); - return field; -} + states.followPointerDirty = false; + } + } -function makeMetadata(metadata) { - const metadataMap = new Map(); + if (followPointerWorldPos) { + const dist = Math.abs(math.lenVec3(math.subVec3(followPointerWorldPos, scene.camera.eye, tempVec3$1))); + dollyDistFactor = dist / configs.dollyProximityThreshold; + } - for (const key in metadata) { - metadataMap.set("".concat(key, ".string"), JSON.stringify(metadata[key])); - } + if (dollyDistFactor < configs.dollyMinSpeed) { + dollyDistFactor = configs.dollyMinSpeed; + } + } + } + } - return metadataMap; -} + const dollyDeltaForDist = (updates.dollyDelta * dollyDistFactor); -const DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP = { - POSITION: 'POSITION', - NORMAL: 'NORMAL', - COLOR: 'COLOR_0', - TEX_COORD: 'TEXCOORD_0' -}; -const DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP = { - 1: Int8Array, - 2: Uint8Array, - 3: Int16Array, - 4: Uint16Array, - 5: Int32Array, - 6: Uint32Array, - 9: Float32Array -}; -const INDEX_ITEM_SIZE = 4; -class DracoParser { - constructor(draco) { - _defineProperty(this, "draco", void 0); + //---------------------------------------------------------------------------------------------------------- + // Rotation + //---------------------------------------------------------------------------------------------------------- - _defineProperty(this, "decoder", void 0); + if (updates.rotateDeltaY !== 0 || updates.rotateDeltaX !== 0) { - _defineProperty(this, "metadataQuerier", void 0); + if ((!configs.firstPerson) && configs.followPointer && pivotController.getPivoting()) { + pivotController.continuePivot(updates.rotateDeltaY, updates.rotateDeltaX); + pivotController.showPivot(); - this.draco = draco; - this.decoder = new this.draco.Decoder(); - this.metadataQuerier = new this.draco.MetadataQuerier(); - } + } else { - destroy() { - this.draco.destroy(this.decoder); - this.draco.destroy(this.metadataQuerier); - } + if (updates.rotateDeltaX !== 0) { + if (configs.firstPerson) { + camera.pitch(-updates.rotateDeltaX); + } else { + camera.orbitPitch(updates.rotateDeltaX); + } + } - parseSync(arrayBuffer, options = {}) { - const buffer = new this.draco.DecoderBuffer(); - buffer.Init(new Int8Array(arrayBuffer), arrayBuffer.byteLength); + if (updates.rotateDeltaY !== 0) { + if (configs.firstPerson) { + camera.yaw(updates.rotateDeltaY); + } else { + camera.orbitYaw(updates.rotateDeltaY); + } + } + } - this._disableAttributeTransforms(options); + updates.rotateDeltaX *= configs.rotationInertia; + updates.rotateDeltaY *= configs.rotationInertia; - const geometry_type = this.decoder.GetEncodedGeometryType(buffer); - const dracoGeometry = geometry_type === this.draco.TRIANGULAR_MESH ? new this.draco.Mesh() : new this.draco.PointCloud(); + cursorType = "grabbing"; + } - try { - let dracoStatus; + //---------------------------------------------------------------------------------------------------------- + // Panning + //---------------------------------------------------------------------------------------------------------- - switch (geometry_type) { - case this.draco.TRIANGULAR_MESH: - dracoStatus = this.decoder.DecodeBufferToMesh(buffer, dracoGeometry); - break; + if (Math.abs(updates.panDeltaX) < EPSILON) { + updates.panDeltaX = 0; + } - case this.draco.POINT_CLOUD: - dracoStatus = this.decoder.DecodeBufferToPointCloud(buffer, dracoGeometry); - break; + if (Math.abs(updates.panDeltaY) < EPSILON) { + updates.panDeltaY = 0; + } - default: - throw new Error('DRACO: Unknown geometry type.'); - } + if (Math.abs(updates.panDeltaZ) < EPSILON) { + updates.panDeltaZ = 0; + } - if (!dracoStatus.ok() || !dracoGeometry.ptr) { - const message = "DRACO decompression failed: ".concat(dracoStatus.error_msg()); - throw new Error(message); - } + if (updates.panDeltaX !== 0 || updates.panDeltaY !== 0 || updates.panDeltaZ !== 0) { - const loaderData = this._getDracoLoaderData(dracoGeometry, geometry_type, options); + const vec = math.vec3(); - const geometry = this._getMeshData(dracoGeometry, loaderData, options); + vec[0] = updates.panDeltaX; + vec[1] = updates.panDeltaY; + vec[2] = updates.panDeltaZ; - const boundingBox = getMeshBoundingBox(geometry.attributes); - const schema = getDracoSchema(geometry.attributes, loaderData, geometry.indices); - const data = { - loader: 'draco', - loaderData, - header: { - vertexCount: dracoGeometry.num_points(), - boundingBox - }, - ...geometry, - schema - }; - return data; - } finally { - this.draco.destroy(buffer); + let verticalEye; + let verticalLook; - if (dracoGeometry) { - this.draco.destroy(dracoGeometry); - } - } - } + if (configs.constrainVertical) { - _getDracoLoaderData(dracoGeometry, geometry_type, options) { - const metadata = this._getTopLevelMetadata(dracoGeometry); + if (camera.xUp) { + verticalEye = camera.eye[0]; + verticalLook = camera.look[0]; + } else if (camera.yUp) { + verticalEye = camera.eye[1]; + verticalLook = camera.look[1]; + } else if (camera.zUp) { + verticalEye = camera.eye[2]; + verticalLook = camera.look[2]; + } - const attributes = this._getDracoAttributes(dracoGeometry, options); + camera.pan(vec); - return { - geometry_type, - num_attributes: dracoGeometry.num_attributes(), - num_points: dracoGeometry.num_points(), - num_faces: dracoGeometry instanceof this.draco.Mesh ? dracoGeometry.num_faces() : 0, - metadata, - attributes - }; - } + const eye = camera.eye; + const look = camera.look; - _getDracoAttributes(dracoGeometry, options) { - const dracoAttributes = {}; + if (camera.xUp) { + eye[0] = verticalEye; + look[0] = verticalLook; + } else if (camera.yUp) { + eye[1] = verticalEye; + look[1] = verticalLook; + } else if (camera.zUp) { + eye[2] = verticalEye; + look[2] = verticalLook; + } - for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) { - const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId); + camera.eye = eye; + camera.look = look; - const metadata = this._getAttributeMetadata(dracoGeometry, attributeId); + } else { + camera.pan(vec); + } - dracoAttributes[dracoAttribute.unique_id()] = { - unique_id: dracoAttribute.unique_id(), - attribute_type: dracoAttribute.attribute_type(), - data_type: dracoAttribute.data_type(), - num_components: dracoAttribute.num_components(), - byte_offset: dracoAttribute.byte_offset(), - byte_stride: dracoAttribute.byte_stride(), - normalized: dracoAttribute.normalized(), - attribute_index: attributeId, - metadata - }; + cursorType = "grabbing"; + } - const quantization = this._getQuantizationTransform(dracoAttribute, options); + updates.panDeltaX *= configs.panInertia; + updates.panDeltaY *= configs.panInertia; + updates.panDeltaZ *= configs.panInertia; - if (quantization) { - dracoAttributes[dracoAttribute.unique_id()].quantization_transform = quantization; - } + //---------------------------------------------------------------------------------------------------------- + // Dollying + //---------------------------------------------------------------------------------------------------------- - const octahedron = this._getOctahedronTransform(dracoAttribute, options); + if (dollyDeltaForDist !== 0) { - if (octahedron) { - dracoAttributes[dracoAttribute.unique_id()].octahedron_transform = octahedron; - } - } + if (dollyDeltaForDist < 0) { + cursorType = "zoom-in"; + } else { + cursorType = "zoom-out"; + } - return dracoAttributes; - } + if (configs.firstPerson) { - _getMeshData(dracoGeometry, loaderData, options) { - const attributes = this._getMeshAttributes(loaderData, dracoGeometry, options); + let verticalEye; + let verticalLook; - const positionAttribute = attributes.POSITION; + if (configs.constrainVertical) { + if (camera.xUp) { + verticalEye = camera.eye[0]; + verticalLook = camera.look[0]; + } else if (camera.yUp) { + verticalEye = camera.eye[1]; + verticalLook = camera.look[1]; + } else if (camera.zUp) { + verticalEye = camera.eye[2]; + verticalLook = camera.look[2]; + } + } - if (!positionAttribute) { - throw new Error('DRACO: No position attribute found.'); - } + if (configs.followPointer) { + const dolliedThroughSurface = panController.dollyToCanvasPos(followPointerWorldPos, states.pointerCanvasPos, -dollyDeltaForDist); + if (dolliedThroughSurface) { + states.followPointerDirty = true; + } + } else { + camera.pan([0, 0, dollyDeltaForDist]); + camera.ortho.scale = camera.ortho.scale - dollyDeltaForDist; + } - if (dracoGeometry instanceof this.draco.Mesh) { - switch (options.topology) { - case 'triangle-strip': - return { - topology: 'triangle-strip', - mode: 4, - attributes, - indices: { - value: this._getTriangleStripIndices(dracoGeometry), - size: 1 - } - }; + if (configs.constrainVertical) { + const eye = camera.eye; + const look = camera.look; + if (camera.xUp) { + eye[0] = verticalEye; + look[0] = verticalLook; + } else if (camera.yUp) { + eye[1] = verticalEye; + look[1] = verticalLook; + } else if (camera.zUp) { + eye[2] = verticalEye; + look[2] = verticalLook; + } + camera.eye = eye; + camera.look = look; + } - case 'triangle-list': - default: - return { - topology: 'triangle-list', - mode: 5, - attributes, - indices: { - value: this._getTriangleListIndices(dracoGeometry), - size: 1 - } - }; - } - } + } else if (configs.planView) { - return { - topology: 'point-list', - mode: 0, - attributes - }; - } + if (configs.followPointer) { + const dolliedThroughSurface = panController.dollyToCanvasPos(followPointerWorldPos, states.pointerCanvasPos, -dollyDeltaForDist); + if (dolliedThroughSurface) { + states.followPointerDirty = true; + } + } else { + camera.ortho.scale = camera.ortho.scale + dollyDeltaForDist; + camera.zoom(dollyDeltaForDist); + } - _getMeshAttributes(loaderData, dracoGeometry, options) { - const attributes = {}; + } else { // Orbiting - for (const loaderAttribute of Object.values(loaderData.attributes)) { - const attributeName = this._deduceAttributeName(loaderAttribute, options); + if (configs.followPointer) { + const dolliedThroughSurface = panController.dollyToCanvasPos(followPointerWorldPos, states.pointerCanvasPos, -dollyDeltaForDist); + if (dolliedThroughSurface) { + states.followPointerDirty = true; + } + } else { + camera.ortho.scale = camera.ortho.scale + dollyDeltaForDist; + camera.zoom(dollyDeltaForDist); + } + } - loaderAttribute.name = attributeName; + updates.dollyDelta *= configs.dollyInertia; + } - const { - value, - size - } = this._getAttributeValues(dracoGeometry, loaderAttribute); + pickController.fireEvents(); - attributes[attributeName] = { - value, - size, - byteOffset: loaderAttribute.byte_offset, - byteStride: loaderAttribute.byte_stride, - normalized: loaderAttribute.normalized - }; + document.body.style.cursor = cursorType; + }); } - return attributes; - } - _getTriangleListIndices(dracoGeometry) { - const numFaces = dracoGeometry.num_faces(); - const numIndices = numFaces * 3; - const byteLength = numIndices * INDEX_ITEM_SIZE; + destroy() { + this._scene.off(this._onTick); + } +} - const ptr = this.draco._malloc(byteLength); +/** + * @private + */ +class MouseMiscHandler { - try { - this.decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); - return new Uint32Array(this.draco.HEAPF32.buffer, ptr, numIndices).slice(); - } finally { - this.draco._free(ptr); - } - } + constructor(scene, controllers, configs, states, updates) { - _getTriangleStripIndices(dracoGeometry) { - const dracoArray = new this.draco.DracoInt32Array(); + this._scene = scene; - try { - this.decoder.GetTriangleStripsFromMesh(dracoGeometry, dracoArray); - return getUint32Array(dracoArray); - } finally { - this.draco.destroy(dracoArray); - } - } + const canvas = this._scene.canvas.canvas; - _getAttributeValues(dracoGeometry, attribute) { - const TypedArrayCtor = DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP[attribute.data_type]; - const numComponents = attribute.num_components; - const numPoints = dracoGeometry.num_points(); - const numValues = numPoints * numComponents; - const byteLength = numValues * TypedArrayCtor.BYTES_PER_ELEMENT; - const dataType = getDracoDataType(this.draco, TypedArrayCtor); - let value; + canvas.addEventListener("mouseenter", this._mouseEnterHandler = () => { + states.mouseover = true; + }); - const ptr = this.draco._malloc(byteLength); + canvas.addEventListener("mouseleave", this._mouseLeaveHandler = () => { + states.mouseover = false; + canvas.style.cursor = null; + }); - try { - const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attribute.attribute_index); - this.decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, dracoAttribute, dataType, byteLength, ptr); - value = new TypedArrayCtor(this.draco.HEAPF32.buffer, ptr, numValues).slice(); - } finally { - this.draco._free(ptr); - } + document.addEventListener("mousemove", this._mouseMoveHandler = (e) => { + getCanvasPosFromEvent$3(e, canvas, states.pointerCanvasPos); + }); - return { - value, - size: numComponents - }; - } + canvas.addEventListener("mousedown", this._mouseDownHandler = (e) => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } + getCanvasPosFromEvent$3(e, canvas, states.pointerCanvasPos); + states.mouseover = true; + }); - _deduceAttributeName(attribute, options) { - const uniqueId = attribute.unique_id; + canvas.addEventListener("mouseup", this._mouseUpHandler = (e) => { + if (!(configs.active && configs.pointerEnabled)) { + return; + } + }); + } - for (const [attributeName, attributeUniqueId] of Object.entries(options.extraAttributes || {})) { - if (attributeUniqueId === uniqueId) { - return attributeName; - } + reset() { } - const thisAttributeType = attribute.attribute_type; + destroy() { - for (const dracoAttributeConstant in DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP) { - const attributeType = this.draco[dracoAttributeConstant]; + const canvas = this._scene.canvas.canvas; - if (attributeType === thisAttributeType) { - return DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP[dracoAttributeConstant]; - } + document.removeEventListener("mousemove", this._mouseMoveHandler); + canvas.removeEventListener("mouseenter", this._mouseEnterHandler); + canvas.removeEventListener("mouseleave", this._mouseLeaveHandler); + canvas.removeEventListener("mousedown", this._mouseDownHandler); + canvas.removeEventListener("mouseup", this._mouseUpHandler); } +} - const entryName = options.attributeNameEntry || 'name'; - - if (attribute.metadata[entryName]) { - return attribute.metadata[entryName].string; +function getCanvasPosFromEvent$3(event, canvas, canvasPos) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + const { x, y } = canvas.getBoundingClientRect(); + canvasPos[0] = event.clientX - x; + canvasPos[1] = event.clientY - y; } + return canvasPos; +} - return "CUSTOM_ATTRIBUTE_".concat(uniqueId); - } - - _getTopLevelMetadata(dracoGeometry) { - const dracoMetadata = this.decoder.GetMetadata(dracoGeometry); - return this._getDracoMetadata(dracoMetadata); - } - - _getAttributeMetadata(dracoGeometry, attributeId) { - const dracoMetadata = this.decoder.GetAttributeMetadata(dracoGeometry, attributeId); - return this._getDracoMetadata(dracoMetadata); - } - - _getDracoMetadata(dracoMetadata) { - if (!dracoMetadata || !dracoMetadata.ptr) { - return {}; +const getCanvasPosFromEvent$2 = function (event, canvasPos) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + let element = event.target; + let totalOffsetLeft = 0; + let totalOffsetTop = 0; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + canvasPos[0] = event.pageX - totalOffsetLeft; + canvasPos[1] = event.pageY - totalOffsetTop; } + return canvasPos; +}; - const result = {}; - const numEntries = this.metadataQuerier.NumEntries(dracoMetadata); +/** + * @private + */ +class TouchPanRotateAndDollyHandler { - for (let entryIndex = 0; entryIndex < numEntries; entryIndex++) { - const entryName = this.metadataQuerier.GetEntryName(dracoMetadata, entryIndex); - result[entryName] = this._getDracoMetadataField(dracoMetadata, entryName); - } + constructor(scene, controllers, configs, states, updates) { - return result; - } + this._scene = scene; - _getDracoMetadataField(dracoMetadata, entryName) { - const dracoArray = new this.draco.DracoInt32Array(); + const pickController = controllers.pickController; + const pivotController = controllers.pivotController; - try { - this.metadataQuerier.GetIntEntryArray(dracoMetadata, entryName, dracoArray); - const intArray = getInt32Array(dracoArray); - return { - int: this.metadataQuerier.GetIntEntry(dracoMetadata, entryName), - string: this.metadataQuerier.GetStringEntry(dracoMetadata, entryName), - double: this.metadataQuerier.GetDoubleEntry(dracoMetadata, entryName), - intArray - }; - } finally { - this.draco.destroy(dracoArray); - } - } + const tapStartCanvasPos = math.vec2(); + const tapCanvasPos0 = math.vec2(); + const tapCanvasPos1 = math.vec2(); + const touch0Vec = math.vec2(); - _disableAttributeTransforms(options) { - const { - quantizedAttributes = [], - octahedronAttributes = [] - } = options; - const skipAttributes = [...quantizedAttributes, ...octahedronAttributes]; + const lastCanvasTouchPosList = []; + const canvas = this._scene.canvas.canvas; - for (const dracoAttributeName of skipAttributes) { - this.decoder.SkipAttributeTransform(this.draco[dracoAttributeName]); - } - } + let numTouches = 0; + let waitForTick = false; - _getQuantizationTransform(dracoAttribute, options) { - const { - quantizedAttributes = [] - } = options; - const attribute_type = dracoAttribute.attribute_type(); - const skip = quantizedAttributes.map(type => this.decoder[type]).includes(attribute_type); + this._onTick = scene.on("tick", () => { + waitForTick = false; + }); - if (skip) { - const transform = new this.draco.AttributeQuantizationTransform(); + canvas.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => { - try { - if (transform.InitFromAttribute(dracoAttribute)) { - return { - quantization_bits: transform.quantization_bits(), - range: transform.range(), - min_values: new Float32Array([1, 2, 3]).map(i => transform.min_value(i)) - }; - } - } finally { - this.draco.destroy(transform); - } - } + if (!(configs.active && configs.pointerEnabled)) { + return; + } - return null; - } + event.preventDefault(); - _getOctahedronTransform(dracoAttribute, options) { - const { - octahedronAttributes = [] - } = options; - const attribute_type = dracoAttribute.attribute_type(); - const octahedron = octahedronAttributes.map(type => this.decoder[type]).includes(attribute_type); + const touches = event.touches; + const changedTouches = event.changedTouches; - if (octahedron) { - const transform = new this.draco.AttributeQuantizationTransform(); + states.touchStartTime = Date.now(); - try { - if (transform.InitFromAttribute(dracoAttribute)) { - return { - quantization_bits: transform.quantization_bits() - }; - } - } finally { - this.draco.destroy(transform); - } - } + if (touches.length === 1 && changedTouches.length === 1) { - return null; - } + getCanvasPosFromEvent$2(touches[0], tapStartCanvasPos); -} + if (configs.followPointer) { -function getDracoDataType(draco, attributeType) { - switch (attributeType) { - case Float32Array: - return draco.DT_FLOAT32; + pickController.pickCursorPos = tapStartCanvasPos; + pickController.schedulePickSurface = true; + pickController.update(); - case Int8Array: - return draco.DT_INT8; + if (!configs.planView) { - case Int16Array: - return draco.DT_INT16; + if (pickController.picked && pickController.pickedSurface && pickController.pickResult && pickController.pickResult.worldPos) { - case Int32Array: - return draco.DT_INT32; + pivotController.setPivotPos(pickController.pickResult.worldPos); - case Uint8Array: - return draco.DT_UINT8; + if (!configs.firstPerson && pivotController.startPivot()) { + pivotController.showPivot(); + } - case Uint16Array: - return draco.DT_UINT16; + } else { - case Uint32Array: - return draco.DT_UINT32; + if (configs.smartPivot) { + pivotController.setCanvasPivotPos(states.pointerCanvasPos); + } else { + pivotController.setPivotPos(scene.camera.look); + } - default: - return draco.DT_INVALID; - } -} + if (!configs.firstPerson && pivotController.startPivot()) { + pivotController.showPivot(); + } + } + } + } -function getInt32Array(dracoArray) { - const numValues = dracoArray.size(); - const intArray = new Int32Array(numValues); + } - for (let i = 0; i < numValues; i++) { - intArray[i] = dracoArray.GetValue(i); - } + while (lastCanvasTouchPosList.length < touches.length) { + lastCanvasTouchPosList.push(math.vec2()); + } - return intArray; -} + for (let i = 0, len = touches.length; i < len; ++i) { + getCanvasPosFromEvent$2(touches[i], lastCanvasTouchPosList[i]); + } -function getUint32Array(dracoArray) { - const numValues = dracoArray.size(); - const intArray = new Int32Array(numValues); + numTouches = touches.length; + }); - for (let i = 0; i < numValues; i++) { - intArray[i] = dracoArray.GetValue(i); - } + canvas.addEventListener("touchmove", this._canvasTouchMoveHandler = (event) => { - return intArray; -} + if (!(configs.active && configs.pointerEnabled)) { + return; + } -const DRACO_VERSION = '1.4.1'; -const DRACO_JS_DECODER_URL = "https://www.gstatic.com/draco/versioned/decoders/".concat(DRACO_VERSION, "/draco_decoder.js"); -const DRACO_WASM_WRAPPER_URL = "https://www.gstatic.com/draco/versioned/decoders/".concat(DRACO_VERSION, "/draco_wasm_wrapper.js"); -const DRACO_WASM_DECODER_URL = "https://www.gstatic.com/draco/versioned/decoders/".concat(DRACO_VERSION, "/draco_decoder.wasm"); -let loadDecoderPromise; -async function loadDracoDecoderModule(options) { - const modules = options.modules || {}; + event.stopPropagation(); + event.preventDefault(); - if (modules.draco3d) { - loadDecoderPromise = loadDecoderPromise || modules.draco3d.createDecoderModule({}).then(draco => { - return { - draco - }; - }); - } else { - loadDecoderPromise = loadDecoderPromise || loadDracoDecoder(options); - } + if (waitForTick) { + // Limit changes detection to one per frame + return; + } - return await loadDecoderPromise; -} + waitForTick = true; -async function loadDracoDecoder(options) { - let DracoDecoderModule; - let wasmBinary; + // Scaling drag-rotate to canvas boundary - switch (options.draco && options.draco.decoderType) { - case 'js': - DracoDecoderModule = await loadLibrary(DRACO_JS_DECODER_URL, 'draco', options); - break; + const canvasBoundary = scene.canvas.boundary; + const canvasWidth = canvasBoundary[2]; + const canvasHeight = canvasBoundary[3]; - case 'wasm': - default: - [DracoDecoderModule, wasmBinary] = await Promise.all([await loadLibrary(DRACO_WASM_WRAPPER_URL, 'draco', options), await loadLibrary(DRACO_WASM_DECODER_URL, 'draco', options)]); - } + const touches = event.touches; - DracoDecoderModule = DracoDecoderModule || globalThis.DracoDecoderModule; - return await initializeDracoDecoder(DracoDecoderModule, wasmBinary); -} + if (event.touches.length !== numTouches) { + // Two fingers were pressed, then one of them is removed + // We don't want to rotate in this case (weird behavior) + return; + } -function initializeDracoDecoder(DracoDecoderModule, wasmBinary) { - const options = {}; + if (numTouches === 1) { - if (wasmBinary) { - options.wasmBinary = wasmBinary; - } + getCanvasPosFromEvent$2(touches[0], tapCanvasPos0); - return new Promise(resolve => { - DracoDecoderModule({ ...options, - onModuleLoaded: draco => resolve({ - draco - }) - }); - }); -} + //----------------------------------------------------------------------------------------------- + // Drag rotation + //----------------------------------------------------------------------------------------------- -const DracoLoader = { ...DracoLoader$1, - parse: parse$2 -}; + math.subVec2(tapCanvasPos0, lastCanvasTouchPosList[0], touch0Vec); -async function parse$2(arrayBuffer, options) { - const { - draco - } = await loadDracoDecoderModule(options); - const dracoParser = new DracoParser(draco); + const xPanDelta = touch0Vec[0]; + const yPanDelta = touch0Vec[1]; - try { - return dracoParser.parseSync(arrayBuffer, options === null || options === void 0 ? void 0 : options.draco); - } finally { - dracoParser.destroy(); - } -} + if (states.longTouchTimeout !== null && (Math.abs(xPanDelta) > configs.longTapRadius || Math.abs(yPanDelta) > configs.longTapRadius)) { + clearTimeout(states.longTouchTimeout); + states.longTouchTimeout = null; + } -function getGLTFAccessors(attributes) { - const accessors = {}; + if (configs.planView) { // No rotating in plan-view mode - for (const name in attributes) { - const attribute = attributes[name]; + const camera = scene.camera; - if (name !== 'indices') { - const glTFAccessor = getGLTFAccessor(attribute); - accessors[name] = glTFAccessor; - } - } + // We use only canvasHeight here so that aspect ratio does not distort speed - return accessors; -} -function getGLTFAccessor(attribute) { - const { - buffer, - size, - count - } = getAccessorData(attribute); - const glTFAccessor = { - value: buffer, - size, - byteOffset: 0, - count, - type: getAccessorTypeFromSize(size), - componentType: getComponentTypeFromArray(buffer) - }; - return glTFAccessor; -} + if (camera.projection === "perspective") { -function getAccessorData(attribute) { - let buffer = attribute; - let size = 1; - let count = 0; + const depth = Math.abs(scene.camera.eyeLookDist); + const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0); - if (attribute && attribute.value) { - buffer = attribute.value; - size = attribute.size || 1; - } + updates.panDeltaX += (xPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; + updates.panDeltaY += (yPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; - if (buffer) { - if (!ArrayBuffer.isView(buffer)) { - buffer = toTypedArray(buffer, Float32Array); - } + } else { - count = buffer.length / size; - } + updates.panDeltaX += 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight) * configs.touchPanRate; + updates.panDeltaY += 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight) * configs.touchPanRate; + } - return { - buffer, - size, - count - }; -} + } else { + updates.rotateDeltaY -= (xPanDelta / canvasWidth) * (configs.dragRotationRate * 1.0); // Full horizontal rotation + updates.rotateDeltaX += (yPanDelta / canvasHeight) * (configs.dragRotationRate * 1.5); // Half vertical rotation + } -function toTypedArray(array, ArrayType, convertTypedArrays = false) { - if (!array) { - return null; - } + } else if (numTouches === 2) { - if (Array.isArray(array)) { - return new ArrayType(array); - } + const touch0 = touches[0]; + const touch1 = touches[1]; - if (convertTypedArrays && !(array instanceof ArrayType)) { - return new ArrayType(array); - } + getCanvasPosFromEvent$2(touch0, tapCanvasPos0); + getCanvasPosFromEvent$2(touch1, tapCanvasPos1); - return array; -} + const lastMiddleTouch = math.geometricMeanVec2(lastCanvasTouchPosList[0], lastCanvasTouchPosList[1]); + const currentMiddleTouch = math.geometricMeanVec2(tapCanvasPos0, tapCanvasPos1); -const KHR_DRACO_MESH_COMPRESSION = 'KHR_draco_mesh_compression'; -const name$3 = KHR_DRACO_MESH_COMPRESSION; -function preprocess$1(gltfData, options, context) { - const scenegraph = new GLTFScenegraph(gltfData); + const touchDelta = math.vec2(); - for (const primitive of makeMeshPrimitiveIterator(scenegraph)) { - if (scenegraph.getObjectExtension(primitive, KHR_DRACO_MESH_COMPRESSION)) ; - } -} -async function decode$3(gltfData, options, context) { - var _options$gltf; + math.subVec2(lastMiddleTouch, currentMiddleTouch, touchDelta); - if (!(options !== null && options !== void 0 && (_options$gltf = options.gltf) !== null && _options$gltf !== void 0 && _options$gltf.decompressMeshes)) { - return; - } + const xPanDelta = touchDelta[0]; + const yPanDelta = touchDelta[1]; - const scenegraph = new GLTFScenegraph(gltfData); - const promises = []; + const camera = scene.camera; - for (const primitive of makeMeshPrimitiveIterator(scenegraph)) { - if (scenegraph.getObjectExtension(primitive, KHR_DRACO_MESH_COMPRESSION)) { - promises.push(decompressPrimitive(scenegraph, primitive, options, context)); - } - } + // Dollying - await Promise.all(promises); - scenegraph.removeExtension(KHR_DRACO_MESH_COMPRESSION); -} -function encode$3(gltfData, options = {}) { - const scenegraph = new GLTFScenegraph(gltfData); + const d1 = math.distVec2([touch0.pageX, touch0.pageY], [touch1.pageX, touch1.pageY]); + const d2 = math.distVec2(lastCanvasTouchPosList[0], lastCanvasTouchPosList[1]); - for (const mesh of scenegraph.json.meshes || []) { - compressMesh(mesh); - scenegraph.addRequiredExtension(KHR_DRACO_MESH_COMPRESSION); - } -} + const dollyDelta = (d2 - d1) * configs.touchDollyRate; -async function decompressPrimitive(scenegraph, primitive, options, context) { - const dracoExtension = scenegraph.getObjectExtension(primitive, KHR_DRACO_MESH_COMPRESSION); + updates.dollyDelta = dollyDelta; - if (!dracoExtension) { - return; - } + if (Math.abs(dollyDelta) < 1.0) { - const buffer = scenegraph.getTypedArrayForBufferView(dracoExtension.bufferView); - const bufferCopy = sliceArrayBuffer(buffer.buffer, buffer.byteOffset); - const { - parse - } = context; - const dracoOptions = { ...options - }; - delete dracoOptions['3d-tiles']; - const decodedData = await parse(bufferCopy, DracoLoader, dracoOptions, context); - const decodedAttributes = getGLTFAccessors(decodedData.attributes); + // We use only canvasHeight here so that aspect ratio does not distort speed - for (const [attributeName, decodedAttribute] of Object.entries(decodedAttributes)) { - if (attributeName in primitive.attributes) { - const accessorIndex = primitive.attributes[attributeName]; - const accessor = scenegraph.getAccessor(accessorIndex); + if (camera.projection === "perspective") { + const pickedWorldPos = pickController.pickResult ? pickController.pickResult.worldPos : scene.center; - if (accessor !== null && accessor !== void 0 && accessor.min && accessor !== null && accessor !== void 0 && accessor.max) { - decodedAttribute.min = accessor.min; - decodedAttribute.max = accessor.max; - } - } - } + const depth = Math.abs(math.lenVec3(math.subVec3(pickedWorldPos, scene.camera.eye, []))); + const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0); - primitive.attributes = decodedAttributes; + updates.panDeltaX -= (xPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; + updates.panDeltaY -= (yPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; - if (decodedData.indices) { - primitive.indices = getGLTFAccessor(decodedData.indices); - } + } else { - checkPrimitive(primitive); -} + updates.panDeltaX -= 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight) * configs.touchPanRate; + updates.panDeltaY -= 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight) * configs.touchPanRate; + } + } -function compressMesh(attributes, indices, mode = 4, options, context) { - var _context$parseSync; - if (!options.DracoWriter) { - throw new Error('options.gltf.DracoWriter not provided'); - } + states.pointerCanvasPos = currentMiddleTouch; + } - const compressedData = options.DracoWriter.encodeSync({ - attributes - }); - const decodedData = context === null || context === void 0 ? void 0 : (_context$parseSync = context.parseSync) === null || _context$parseSync === void 0 ? void 0 : _context$parseSync.call(context, { - attributes - }); + for (let i = 0; i < numTouches; ++i) { + getCanvasPosFromEvent$2(touches[i], lastCanvasTouchPosList[i]); + } + }); + } - const fauxAccessors = options._addFauxAttributes(decodedData.attributes); + reset() { + } - const bufferViewIndex = options.addBufferView(compressedData); - const glTFMesh = { - primitives: [{ - attributes: fauxAccessors, - mode, - extensions: { - [KHR_DRACO_MESH_COMPRESSION]: { - bufferView: bufferViewIndex, - attributes: fauxAccessors - } - } - }] - }; - return glTFMesh; + destroy() { + const canvas = this._scene.canvas.canvas; + canvas.removeEventListener("touchstart", this._canvasTouchStartHandler); + canvas.removeEventListener("touchmove", this._canvasTouchMoveHandler); + this._scene.off(this._onTick); + } } -function checkPrimitive(primitive) { - if (!primitive.attributes && Object.keys(primitive.attributes).length > 0) { - throw new Error('glTF: Empty primitive detected: Draco decompression failure?'); - } -} +const TAP_INTERVAL = 150; +const DBL_TAP_INTERVAL = 325; +const TAP_DISTANCE_THRESHOLD = 4; -function* makeMeshPrimitiveIterator(scenegraph) { - for (const mesh of scenegraph.json.meshes || []) { - for (const primitive of mesh.primitives) { - yield primitive; +const getCanvasPosFromEvent$1 = function (event, canvasPos) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + let element = event.target; + let totalOffsetLeft = 0; + let totalOffsetTop = 0; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + canvasPos[0] = event.pageX - totalOffsetLeft; + canvasPos[1] = event.pageY - totalOffsetTop; } - } -} + return canvasPos; +}; -var KHR_draco_mesh_compression = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name$3, - preprocess: preprocess$1, - decode: decode$3, - encode: encode$3 -}); +/** + * @private + */ +class TouchPickHandler { -const KHR_LIGHTS_PUNCTUAL = 'KHR_lights_punctual'; -const name$2 = KHR_LIGHTS_PUNCTUAL; -async function decode$2(gltfData) { - const gltfScenegraph = new GLTFScenegraph(gltfData); - const { - json - } = gltfScenegraph; - const extension = gltfScenegraph.getExtension(KHR_LIGHTS_PUNCTUAL); + constructor(scene, controllers, configs, states, updates) { - if (extension) { - gltfScenegraph.json.lights = extension.lights; - gltfScenegraph.removeExtension(KHR_LIGHTS_PUNCTUAL); - } - - for (const node of json.nodes || []) { - const nodeExtension = gltfScenegraph.getObjectExtension(node, KHR_LIGHTS_PUNCTUAL); + this._scene = scene; - if (nodeExtension) { - node.light = nodeExtension.light; - } + const pickController = controllers.pickController; + const cameraControl = controllers.cameraControl; - gltfScenegraph.removeObjectExtension(node, KHR_LIGHTS_PUNCTUAL); - } -} -async function encode$2(gltfData) { - const gltfScenegraph = new GLTFScenegraph(gltfData); - const { - json - } = gltfScenegraph; + let touchStartTime; + const activeTouches = []; + const tapStartPos = new Float32Array(2); + let tapStartTime = -1; + let lastTapTime = -1; - if (json.lights) { - const extension = gltfScenegraph.addExtension(KHR_LIGHTS_PUNCTUAL); - assert$1(!extension.lights); - extension.lights = json.lights; - delete json.lights; - } + const canvas = this._scene.canvas.canvas; - if (gltfScenegraph.json.lights) { - for (const light of gltfScenegraph.json.lights) { - const node = light.node; - gltfScenegraph.addObjectExtension(node, KHR_LIGHTS_PUNCTUAL, light); - } + const flyCameraTo = (pickResult) => { + let pos; + if (pickResult && pickResult.worldPos) { + pos = pickResult.worldPos; + } + const aabb = pickResult ? pickResult.entity.aabb : scene.aabb; + if (pos) { // Fly to look at point, don't change eye->look dist + const camera = scene.camera; + math.subVec3(camera.eye, camera.look, []); + controllers.cameraFlight.flyTo({ + aabb: aabb + }); + // TODO: Option to back off to fit AABB in view + } else {// Fly to fit target boundary in view + controllers.cameraFlight.flyTo({ + aabb: aabb + }); + } + }; - delete gltfScenegraph.json.lights; - } -} + canvas.addEventListener("touchstart", this._canvasTouchStartHandler = (e) => { -var KHR_lights_punctual = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name$2, - decode: decode$2, - encode: encode$2 -}); + if (!(configs.active && configs.pointerEnabled)) { + return; + } -const KHR_MATERIALS_UNLIT = 'KHR_materials_unlit'; -const name$1 = KHR_MATERIALS_UNLIT; -async function decode$1(gltfData) { - const gltfScenegraph = new GLTFScenegraph(gltfData); - const { - json - } = gltfScenegraph; - gltfScenegraph.removeExtension(KHR_MATERIALS_UNLIT); + if (states.longTouchTimeout !== null) { + clearTimeout(states.longTouchTimeout); + states.longTouchTimeout = null; + } - for (const material of json.materials || []) { - const extension = material.extensions && material.extensions.KHR_materials_unlit; + const touches = e.touches; + const changedTouches = e.changedTouches; - if (extension) { - material.unlit = true; - } + touchStartTime = Date.now(); - gltfScenegraph.removeObjectExtension(material, KHR_MATERIALS_UNLIT); - } -} -function encode$1(gltfData) { - const gltfScenegraph = new GLTFScenegraph(gltfData); - const { - json - } = gltfScenegraph; + if (touches.length === 1 && changedTouches.length === 1) { + tapStartTime = touchStartTime; - if (gltfScenegraph.materials) { - for (const material of json.materials || []) { - if (material.unlit) { - delete material.unlit; - gltfScenegraph.addObjectExtension(material, KHR_MATERIALS_UNLIT, {}); - gltfScenegraph.addExtension(KHR_MATERIALS_UNLIT); - } - } - } -} + getCanvasPosFromEvent$1(touches[0], tapStartPos); -var KHR_materials_unlit = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name$1, - decode: decode$1, - encode: encode$1 -}); + const rightClickClientX = tapStartPos[0]; + const rightClickClientY = tapStartPos[1]; -const KHR_TECHNIQUES_WEBGL = 'KHR_techniques_webgl'; -const name = KHR_TECHNIQUES_WEBGL; -async function decode(gltfData) { - const gltfScenegraph = new GLTFScenegraph(gltfData); - const { - json - } = gltfScenegraph; - const extension = gltfScenegraph.getExtension(KHR_TECHNIQUES_WEBGL); + const rightClickPageX = touches[0].pageX; + const rightClickPageY = touches[0].pageY; - if (extension) { - const techniques = resolveTechniques(extension, gltfScenegraph); + states.longTouchTimeout = setTimeout(() => { + controllers.cameraControl.fire("rightClick", { // For context menus + pagePos: [Math.round(rightClickPageX), Math.round(rightClickPageY)], + canvasPos: [Math.round(rightClickClientX), Math.round(rightClickClientY)], + event: e + }, true); - for (const material of json.materials || []) { - const materialExtension = gltfScenegraph.getObjectExtension(material, KHR_TECHNIQUES_WEBGL); + states.longTouchTimeout = null; + }, configs.longTapTimeout); - if (materialExtension) { - material.technique = Object.assign({}, materialExtension, techniques[materialExtension.technique]); - material.technique.values = resolveValues(material.technique, gltfScenegraph); - } + } else { + tapStartTime = -1; + } - gltfScenegraph.removeObjectExtension(material, KHR_TECHNIQUES_WEBGL); - } + while (activeTouches.length < touches.length) { + activeTouches.push(new Float32Array(2)); + } - gltfScenegraph.removeExtension(KHR_TECHNIQUES_WEBGL); - } -} -async function encode(gltfData, options) {} + for (let i = 0, len = touches.length; i < len; ++i) { + getCanvasPosFromEvent$1(touches[i], activeTouches[i]); + } -function resolveTechniques(techniquesExtension, gltfScenegraph) { - const { - programs = [], - shaders = [], - techniques = [] - } = techniquesExtension; - const textDecoder = new TextDecoder(); - shaders.forEach(shader => { - if (Number.isFinite(shader.bufferView)) { - shader.code = textDecoder.decode(gltfScenegraph.getTypedArrayForBufferView(shader.bufferView)); - } else { - throw new Error('KHR_techniques_webgl: no shader code'); - } - }); - programs.forEach(program => { - program.fragmentShader = shaders[program.fragmentShader]; - program.vertexShader = shaders[program.vertexShader]; - }); - techniques.forEach(technique => { - technique.program = programs[technique.program]; - }); - return techniques; -} + activeTouches.length = touches.length; -function resolveValues(technique, gltfScenegraph) { - const values = Object.assign({}, technique.values); - Object.keys(technique.uniforms || {}).forEach(uniform => { - if (technique.uniforms[uniform].value && !(uniform in values)) { - values[uniform] = technique.uniforms[uniform].value; - } - }); - Object.keys(values).forEach(uniform => { - if (typeof values[uniform] === 'object' && values[uniform].index !== undefined) { - values[uniform].texture = gltfScenegraph.getTexture(values[uniform].index); - } - }); - return values; -} + }, {passive: true}); -var KHR_techniques_webgl = /*#__PURE__*/Object.freeze({ - __proto__: null, - name: name, - decode: decode, - encode: encode -}); -const EXTENSIONS = [EXT_meshopt_compression, EXT_texture_webp, KHR_texture_basisu, KHR_draco_mesh_compression, KHR_lights_punctual, KHR_materials_unlit, KHR_techniques_webgl]; -function preprocessExtensions(gltf, options = {}, context) { - const extensions = EXTENSIONS.filter(extension => useExtension(extension.name, options)); + canvas.addEventListener("touchend", this._canvasTouchEndHandler = (e) => { - for (const extension of extensions) { - var _extension$preprocess; + if (!(configs.active && configs.pointerEnabled)) { + return; + } - (_extension$preprocess = extension.preprocess) === null || _extension$preprocess === void 0 ? void 0 : _extension$preprocess.call(extension, gltf, options, context); - } -} -async function decodeExtensions(gltf, options = {}, context) { - const extensions = EXTENSIONS.filter(extension => useExtension(extension.name, options)); + const currentTime = Date.now(); + const touches = e.touches; + const changedTouches = e.changedTouches; - for (const extension of extensions) { - var _extension$decode; + const pickedSurfaceSubs = cameraControl.hasSubs("pickedSurface"); - await ((_extension$decode = extension.decode) === null || _extension$decode === void 0 ? void 0 : _extension$decode.call(extension, gltf, options, context)); - } -} + if (states.longTouchTimeout !== null) { + clearTimeout(states.longTouchTimeout); + states.longTouchTimeout = null; + } -function useExtension(extensionName, options) { - var _options$gltf; + // process tap - const excludes = (options === null || options === void 0 ? void 0 : (_options$gltf = options.gltf) === null || _options$gltf === void 0 ? void 0 : _options$gltf.excludeExtensions) || {}; - const exclude = extensionName in excludes && !excludes[extensionName]; - return !exclude; -} + if (touches.length === 0 && changedTouches.length === 1) { -const KHR_BINARY_GLTF = 'KHR_binary_glTF'; -function preprocess(gltfData) { - const gltfScenegraph = new GLTFScenegraph(gltfData); - const { - json - } = gltfScenegraph; + if (tapStartTime > -1 && currentTime - tapStartTime < TAP_INTERVAL) { - for (const image of json.images || []) { - const extension = gltfScenegraph.getObjectExtension(image, KHR_BINARY_GLTF); + if (lastTapTime > -1 && tapStartTime - lastTapTime < DBL_TAP_INTERVAL) { - if (extension) { - Object.assign(image, extension); - } + // Double-tap - gltfScenegraph.removeObjectExtension(image, KHR_BINARY_GLTF); - } + getCanvasPosFromEvent$1(changedTouches[0], pickController.pickCursorPos); + pickController.schedulePickEntity = true; + pickController.schedulePickSurface = pickedSurfaceSubs; - if (json.buffers && json.buffers[0]) { - delete json.buffers[0].uri; - } + pickController.update(); - gltfScenegraph.removeExtension(KHR_BINARY_GLTF); -} + if (pickController.pickResult) { -const GLTF_ARRAYS = { - accessors: 'accessor', - animations: 'animation', - buffers: 'buffer', - bufferViews: 'bufferView', - images: 'image', - materials: 'material', - meshes: 'mesh', - nodes: 'node', - samplers: 'sampler', - scenes: 'scene', - skins: 'skin', - textures: 'texture' -}; -const GLTF_KEYS = { - accessor: 'accessors', - animations: 'animation', - buffer: 'buffers', - bufferView: 'bufferViews', - image: 'images', - material: 'materials', - mesh: 'meshes', - node: 'nodes', - sampler: 'samplers', - scene: 'scenes', - skin: 'skins', - texture: 'textures' -}; + pickController.pickResult.touchInput = true; -class GLTFV1Normalizer { - constructor() { - _defineProperty(this, "idToIndexMap", { - animations: {}, - accessors: {}, - buffers: {}, - bufferViews: {}, - images: {}, - materials: {}, - meshes: {}, - nodes: {}, - samplers: {}, - scenes: {}, - skins: {}, - textures: {} - }); + cameraControl.fire("doublePicked", pickController.pickResult); - _defineProperty(this, "json", void 0); - } + if (pickController.pickedSurface) { + cameraControl.fire("doublePickedSurface", pickController.pickResult); + } - normalize(gltf, options) { - this.json = gltf.json; - const json = gltf.json; + if (configs.doublePickFlyTo) { + flyCameraTo(pickController.pickResult); + } + } else { + cameraControl.fire("doublePickedNothing"); + if (configs.doublePickFlyTo) { + flyCameraTo(); + } + } - switch (json.asset && json.asset.version) { - case '2.0': - return; + lastTapTime = -1; - case undefined: - case '1.0': - break; + } else if (math.distVec2(activeTouches[0], tapStartPos) < TAP_DISTANCE_THRESHOLD) { - default: - console.warn("glTF: Unknown version ".concat(json.asset.version)); - return; - } + // Single-tap - if (!options.normalize) { - throw new Error('glTF v1 is not supported.'); - } + getCanvasPosFromEvent$1(changedTouches[0], pickController.pickCursorPos); + pickController.schedulePickEntity = true; + pickController.schedulePickSurface = pickedSurfaceSubs; - console.warn('Converting glTF v1 to glTF v2 format. This is experimental and may fail.'); + pickController.update(); - this._addAsset(json); + if (pickController.pickResult) { - this._convertTopLevelObjectsToArrays(json); + pickController.pickResult.touchInput = true; - preprocess(gltf); + cameraControl.fire("picked", pickController.pickResult); - this._convertObjectIdsToArrayIndices(json); + if (pickController.pickedSurface) { + cameraControl.fire("pickedSurface", pickController.pickResult); + } - this._updateObjects(json); + } else { + cameraControl.fire("pickedNothing"); + } - this._updateMaterial(json); - } + lastTapTime = currentTime; + } - _addAsset(json) { - json.asset = json.asset || {}; - json.asset.version = '2.0'; - json.asset.generator = json.asset.generator || 'Normalized to glTF 2.0 by loaders.gl'; - } + tapStartTime = -1; + } + } - _convertTopLevelObjectsToArrays(json) { - for (const arrayName in GLTF_ARRAYS) { - this._convertTopLevelObjectToArray(json, arrayName); - } - } + activeTouches.length = touches.length; - _convertTopLevelObjectToArray(json, mapName) { - const objectMap = json[mapName]; + for (let i = 0, len = touches.length; i < len; ++i) { + activeTouches[i][0] = touches[i].pageX; + activeTouches[i][1] = touches[i].pageY; + } - if (!objectMap || Array.isArray(objectMap)) { - return; - } + // e.stopPropagation(); - json[mapName] = []; + }, {passive: true}); - for (const id in objectMap) { - const object = objectMap[id]; - object.id = object.id || id; - const index = json[mapName].length; - json[mapName].push(object); - this.idToIndexMap[mapName][id] = index; } - } - _convertObjectIdsToArrayIndices(json) { - for (const arrayName in GLTF_ARRAYS) { - this._convertIdsToIndices(json, arrayName); - } + reset() { + // TODO + // tapStartTime = -1; + // lastTapTime = -1; - if ('scene' in json) { - json.scene = this._convertIdToIndex(json.scene, 'scene'); } - for (const texture of json.textures) { - this._convertTextureIds(texture); + destroy() { + const canvas = this._scene.canvas.canvas; + canvas.removeEventListener("touchstart", this._canvasTouchStartHandler); + canvas.removeEventListener("touchend", this._canvasTouchEndHandler); } +} - for (const mesh of json.meshes) { - this._convertMeshIds(mesh); - } +/** + * @desc Controls the {@link Camera} with user input, and fires events when the user interacts with pickable {@link Entity}s. + * + * # Contents + * + * * [Overview](#overview) + * * [Examples](#examples) + * * [Orbit Mode](#orbit-mode) + * + [Following the Pointer in Orbit Mode](#--following-the-pointer-in-orbit-mode--) + * + [Showing the Pivot Position](#--showing-the-pivot-position--) + * + [Axis-Aligned Views in Orbit Mode](#--axis-aligned-views-in-orbit-mode--) + * + [View-Fitting Entitys in Orbit Mode](#--view-fitting-entitys-in-orbit-mode--) + * * [First-Person Mode](#first-person-mode) + * + [Following the Pointer in First-Person Mode](#--following-the-pointer-in-first-person-mode--) + * + [Constraining Vertical Position in First-Person Mode](#--constraining-vertical-position-in-first-person-mode--) + * + [Axis-Aligned Views in First-Person Mode](#--axis-aligned-views-in-first-person-mode--) + * + [View-Fitting Entitys in First-Person Mode](#--view-fitting-entitys-in-first-person-mode--) + * * [Plan-View Mode](#plan-view-mode) + * + [Following the Pointer in Plan-View Mode](#--following-the-pointer-in-plan-view-mode--) + * + [Axis-Aligned Views in Plan-View Mode](#--axis-aligned-views-in-plan-view-mode--) + * * [CameraControl Events](#cameracontrol-events) + * + ["hover"](#---hover---) + * + ["hoverOff"](#---hoveroff---) + * + ["hoverEnter"](#---hoverenter---) + * + ["hoverOut"](#---hoverout---) + * + ["picked"](#---picked---) + * + ["pickedSurface"](#---pickedsurface---) + * + ["pickedNothing"](#---pickednothing---) + * + ["doublePicked"](#---doublepicked---) + * + ["doublePickedSurface"](#---doublepickedsurface---) + * + ["doublePickedNothing"](#---doublepickednothing---) + * + ["rightClick"](#---rightclick---) + * * [Custom Keyboard Mappings](#custom-keyboard-mappings) + * + *

+ * + * # Overview + * + * * Each {@link Viewer} has a ````CameraControl````, located at {@link Viewer#cameraControl}. + * * {@link CameraControl#navMode} selects the navigation mode: + * * ````"orbit"```` rotates the {@link Camera} position about the target. + * * ````"firstPerson"```` rotates the World about the Camera position. + * * ````"planView"```` never rotates, but still allows to pan and dolly, typically for an axis-aligned view. + * * {@link CameraControl#followPointer} makes the Camera follow the mouse or touch pointer. + * * {@link CameraControl#constrainVertical} locks the Camera to its current height when in first-person mode. + * * ````CameraControl```` fires pick events when we hover, click or tap on an {@link Entity}. + *

+ * + * # Examples + * + * * [Orbit Navigation - Duplex Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_orbit_Duplex) + * * [Orbit Navigation - Holter Tower Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_orbit_HolterTower) + * * [First-Person Navigation - Duplex Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_firstPerson_Duplex) + * * [First-Person Navigation - Holter Tower Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_firstPerson_HolterTower) + * * [Plan-view Navigation - Schependomlaan Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_planView_Schependomlaan) + * * [Custom Keyboard Mapping](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_keyMap) + *

+ * + * # Orbit Mode + * + * In orbit mode, ````CameraControl```` orbits the {@link Camera} about the target. + * + * To enable orbit mode: + * + * ````javascript + * const cameraControl = myViewer.cameraControl; + * cameraControl.navMode = "orbit"; + * ```` + * + * Then orbit by: + * + * * left-dragging the mouse, + * * tap-dragging the touch pad, and + * * pressing arrow keys, or ````Q```` and ````E```` on a QWERTY keyboard, or ````A```` and ````E```` on an AZERTY keyboard. + *

+ * + * Dolly forwards and backwards by: + * + * * spinning the mouse wheel, + * * pinching on the touch pad, and + * * pressing the ````+```` and ````-```` keys, or ````W```` and ````S```` on a QWERTY keyboard, or ````Z```` and ````S```` for AZERTY. + *

+ * + * Pan horizontally and vertically by: + * + * * right-dragging the mouse, + * * left-dragging the mouse with the SHIFT key down, + * * tap-dragging the touch pad with SHIFT down, + * * pressing the ````A````, ````D````, ````Z```` and ````X```` keys on a QWERTY keyboard, and + * * pressing the ````Q````, ````D````, ````W```` and ````X```` keys on an AZERTY keyboard, + *

+ * + * ## Following the Pointer in Orbit Mode + * + * When {@link CameraControl#followPointer} is ````true````in orbiting mode, the mouse or touch pointer will dynamically + * indicate the target that the {@link Camera} will orbit, as well as dolly to and from. + * + * Lets ensure that we're in orbit mode, then enable the {@link Camera} to follow the pointer: + * + * ````javascript + * cameraControl.navMode = "orbit"; + * cameraControl.followPointer = true; + * ```` + * + * ## Smart Pivoting + * + * TODO + * + * ## Showing the Pivot Position + * + * We can configure {@link CameraControl#pivotElement} with an HTML element to indicate the current + * pivot position. The indicator will appear momentarily each time we move the {@link Camera} while in orbit mode with + * {@link CameraControl#followPointer} set ````true````. + * + * First we'll define some CSS to style our pivot indicator as a black dot with a white border: + * + * ````css + * .camera-pivot-marker { + * color: #ffffff; + * position: absolute; + * width: 25px; + * height: 25px; + * border-radius: 15px; + * border: 2px solid #ebebeb; + * background: black; + * visibility: hidden; + * box-shadow: 5px 5px 15px 1px #000000; + * z-index: 10000; + * pointer-events: none; + * } + * ```` + * + * Then we'll attach our pivot indicator's HTML element to the ````CameraControl````: + * + * ````javascript + * const pivotElement = document.createRange().createContextualFragment("
").firstChild; + * + * document.body.appendChild(pivotElement); + * + * cameraControl.pivotElement = pivotElement; + * ```` + * + * ## Axis-Aligned Views in Orbit Mode + * + * In orbit mode, we can use keys 1-6 to position the {@link Camera} to look at the center of the {@link Scene} from along each of the + * six World-space axis. Pressing one of these keys will fly the {@link Camera} to the corresponding axis-aligned view. + * + * ## View-Fitting Entitys in Orbit Mode + * + * When {@link CameraControl#doublePickFlyTo} is ````true````, we can left-double-click or + * double-tap (ie. "double-pick") an {@link Entity} to fit it to view. This will cause the {@link Camera} + * to fly to that Entity. Our target then becomes the center of that Entity. If we are currently pivoting, + * then our pivot position is then also set to the Entity center. + * + * Disable that behaviour by setting {@link CameraControl#doublePickFlyTo} ````false````. + * + * # First-Person Mode + * + * In first-person mode, ````CameraControl```` rotates the World about the {@link Camera} position. + * + * To enable first-person mode: + * + * ````javascript + * cameraControl.navMode = "firstPerson"; + * ```` + * + * Then rotate by: + * + * * left-dragging the mouse, + * * tap-dragging the touch pad, + * * pressing arrow keys, or ````Q```` and ````E```` on a QWERTY keyboard, or ````A```` and ````E```` on an AZERTY keyboard. + *

+ * + * Dolly forwards and backwards by: + * + * * spinning the mouse wheel, + * * pinching on the touch pad, and + * * pressing the ````+```` and ````-```` keys, or ````W```` and ````S```` on a QWERTY keyboard, or ````Z```` and ````S```` for AZERTY. + *

+ * + * Pan left, right, up and down by: + * + * * left-dragging or right-dragging the mouse, and + * * tap-dragging the touch pad with SHIFT down. + * + * Pan forwards, backwards, left, right, up and down by pressing the ````WSADZX```` keys on a QWERTY keyboard, + * or ````WSQDWX```` keys on an AZERTY keyboard. + *

+ * + * ## Following the Pointer in First-Person Mode + * + * When {@link CameraControl#followPointer} is ````true```` in first-person mode, the mouse or touch pointer will dynamically + * indicate the target to which the {@link Camera} will dolly to and from. In first-person mode, however, the World will always rotate + * about the {@link Camera} position. + * + * Lets ensure that we're in first-person mode, then enable the {@link Camera} to follow the pointer: + * + * ````javascript + * cameraControl.navMode = "firstPerson"; + * cameraControl.followPointer = true; + * ```` + * + * When the pointer is over empty space, the target will remain the last object that the pointer was over. + * + * ## Constraining Vertical Position in First-Person Mode + * + * In first-person mode, we can lock the {@link Camera} to its current position on the vertical World axis, which is useful for walk-through navigation: + * + * ````javascript + * cameraControl.constrainVertical = true; + * ```` + * + * ## Axis-Aligned Views in First-Person Mode + * + * In first-person mode we can use keys 1-6 to position the {@link Camera} to look at the center of + * the {@link Scene} from along each of the six World-space axis. Pressing one of these keys will fly the {@link Camera} to the + * corresponding axis-aligned view. + * + * ## View-Fitting Entitys in First-Person Mode + * + * As in orbit mode, when in first-person mode and {@link CameraControl#doublePickFlyTo} is ````true````, we can double-click + * or double-tap an {@link Entity} (ie. "double-picking") to fit it in view. This will cause the {@link Camera} to fly to + * that Entity. Our target then becomes the center of that Entity. + * + * Disable that behaviour by setting {@link CameraControl#doublePickFlyTo} ````false````. + * + * # Plan-View Mode + * + * In plan-view mode, ````CameraControl```` pans and rotates the {@link Camera}, without rotating it. + * + * To enable plan-view mode: + * + * ````javascript + * cameraControl.navMode = "planView"; + * ```` + * + * Dolly forwards and backwards by: + * + * * spinning the mouse wheel, + * * pinching on the touch pad, and + * * pressing the ````+```` and ````-```` keys. + * + *
+ * Pan left, right, up and down by: + * + * * left-dragging or right-dragging the mouse, and + * * tap-dragging the touch pad with SHIFT down. + * + * Pan forwards, backwards, left, right, up and down by pressing the ````WSADZX```` keys on a QWERTY keyboard, + * or ````WSQDWX```` keys on an AZERTY keyboard. + *

+ * + * ## Following the Pointer in Plan-View Mode + * + * When {@link CameraControl#followPointer} is ````true```` in plan-view mode, the mouse or touch pointer will dynamically + * indicate the target to which the {@link Camera} will dolly to and from. In plan-view mode, however, the {@link Camera} cannot rotate. + * + * Lets ensure that we're in plan-view mode, then enable the {@link Camera} to follow the pointer: + * + * ````javascript + * cameraControl.navMode = "planView"; + * cameraControl.followPointer = true; // Default + * ```` + * + * When the pointer is over empty space, the target will remain the last object that the pointer was over. + * + * ## Axis-Aligned Views in Plan-View Mode + * + * As in orbit and first-person modes, in plan-view mode we can use keys 1-6 to position the {@link Camera} to look at the center of + * the {@link Scene} from along each of the six World-space axis. Pressing one of these keys will fly the {@link Camera} to the + * corresponding axis-aligned view. + * + * # CameraControl Events + * + * ````CameraControl```` fires events as we interact with {@link Entity}s using mouse or touch input. + * + * The following examples demonstrate how to subscribe to those events. + * + * The first example shows how to save a handle to a subscription, which we can later use to unsubscribe. + * + * ## "hover" + * + * Event fired when the pointer moves while hovering over an Entity. + * + * ````javascript + * const onHover = cameraControl.on("hover", (e) => { + * const entity = e.entity; // Entity + * const canvasPos = e.canvasPos; // 2D canvas position + * }); + * ```` + * + * To unsubscribe from the event: + * + * ````javascript + * cameraControl.off(onHover); + * ```` + * + * ## "hoverOff" + * + * Event fired when the pointer moves while hovering over empty space. + * + * ````javascript + * cameraControl.on("hoverOff", (e) => { + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "hoverEnter" + * + * Event fired when the pointer moves onto an Entity. + * + * ````javascript + * cameraControl.on("hoverEnter", (e) => { + * const entity = e.entity; + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "hoverOut" + * + * Event fired when the pointer moves off an Entity. + * + * ````javascript + * cameraControl.on("hoverOut", (e) => { + * const entity = e.entity; + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "picked" + * + * Event fired when we left-click or tap on an Entity. + * + * ````javascript + * cameraControl.on("picked", (e) => { + * const entity = e.entity; + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "pickedSurface" + * + * Event fired when we left-click or tap on the surface of an Entity. + * + * ````javascript + * cameraControl.on("picked", (e) => { + * const entity = e.entity; + * const canvasPos = e.canvasPos; + * const worldPos = e.worldPos; // 3D World-space position + * const viewPos = e.viewPos; // 3D View-space position + * const worldNormal = e.worldNormal; // 3D World-space normal vector + * }); + * ```` + * + * ## "pickedNothing" + * + * Event fired when we left-click or tap on empty space. + * + * ````javascript + * cameraControl.on("pickedNothing", (e) => { + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "doublePicked" + * + * Event fired wwhen we left-double-click or double-tap on an Entity. + * + * ````javascript + * cameraControl.on("doublePicked", (e) => { + * const entity = e.entity; + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "doublePickedSurface" + * + * Event fired when we left-double-click or double-tap on the surface of an Entity. + * + * ````javascript + * cameraControl.on("doublePickedSurface", (e) => { + * const entity = e.entity; + * const canvasPos = e.canvasPos; + * const worldPos = e.worldPos; + * const viewPos = e.viewPos; + * const worldNormal = e.worldNormal; + * }); + * ```` + * + * ## "doublePickedNothing" + * + * Event fired when we left-double-click or double-tap on empty space. + * + * ````javascript + * cameraControl.on("doublePickedNothing", (e) => { + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## "rightClick" + * + * Event fired when we right-click on the canvas. + * + * ````javascript + * cameraControl.on("rightClick", (e) => { + * const event = e.event; // Mouse event + * const canvasPos = e.canvasPos; + * }); + * ```` + * + * ## Custom Keyboard Mappings + * + * We can customize````CameraControl```` key bindings as shown below. + * + * In this example, we'll just set the default bindings for a QWERTY keyboard. + * + * ````javascript + * const input = myViewer.scene.input; + * + * cameraControl.navMode = "orbit"; + * cameraControl.followPointer = true; + * + * const keyMap = {}; + * + * keyMap[cameraControl.PAN_LEFT] = [input.KEY_A]; + * keyMap[cameraControl.PAN_RIGHT] = [input.KEY_D]; + * keyMap[cameraControl.PAN_UP] = [input.KEY_Z]; + * keyMap[cameraControl.PAN_DOWN] = [input.KEY_X]; + * keyMap[cameraControl.DOLLY_FORWARDS] = [input.KEY_W, input.KEY_ADD]; + * keyMap[cameraControl.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT]; + * keyMap[cameraControl.ROTATE_X_POS] = [input.KEY_DOWN_ARROW]; + * keyMap[cameraControl.ROTATE_X_NEG] = [input.KEY_UP_ARROW]; + * keyMap[cameraControl.ROTATE_Y_POS] = [input.KEY_LEFT_ARROW]; + * keyMap[cameraControl.ROTATE_Y_NEG] = [input.KEY_RIGHT_ARROW]; + * keyMap[cameraControl.AXIS_VIEW_RIGHT] = [input.KEY_NUM_1]; + * keyMap[cameraControl.AXIS_VIEW_BACK] = [input.KEY_NUM_2]; + * keyMap[cameraControl.AXIS_VIEW_LEFT] = [input.KEY_NUM_3]; + * keyMap[cameraControl.AXIS_VIEW_FRONT] = [input.KEY_NUM_4]; + * keyMap[cameraControl.AXIS_VIEW_TOP] = [input.KEY_NUM_5]; + * keyMap[cameraControl.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6]; + * + * cameraControl.keyMap = keyMap; + * ```` + * + * We can also just configure default bindings for a specified keyboard layout, like this: + * + * ````javascript + * cameraControl.keyMap = "qwerty"; + * ```` + * + * Then, ````CameraControl```` will internally set {@link CameraControl#keyMap} to the default key map for the QWERTY + * layout (which is the same set of mappings we set in the previous example). In other words, if we subsequently + * read {@link CameraControl#keyMap}, it will now be a key map, instead of the "qwerty" string value we set it to. + * + * Supported layouts are, so far: + * + * * ````"qwerty"```` + * * ````"azerty"```` + */ +class CameraControl extends Component { - for (const node of json.nodes) { - this._convertNodeIds(node); - } + /** + * @private + * @constructor + */ + constructor(owner, cfg = {}) { - for (const node of json.scenes) { - this._convertSceneIds(node); - } - } + super(owner, cfg); - _convertTextureIds(texture) { - if (texture.source) { - texture.source = this._convertIdToIndex(texture.source, 'image'); - } - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.PAN_LEFT = 0; - _convertMeshIds(mesh) { - for (const primitive of mesh.primitives) { - const { - attributes, - indices, - material - } = primitive; + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.PAN_RIGHT = 1; - for (const attributeName in attributes) { - attributes[attributeName] = this._convertIdToIndex(attributes[attributeName], 'accessor'); - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.PAN_UP = 2; - if (indices) { - primitive.indices = this._convertIdToIndex(indices, 'accessor'); - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.PAN_DOWN = 3; - if (material) { - primitive.material = this._convertIdToIndex(material, 'material'); - } - } - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.PAN_FORWARDS = 4; - _convertNodeIds(node) { - if (node.children) { - node.children = node.children.map(child => this._convertIdToIndex(child, 'node')); - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.PAN_BACKWARDS = 5; - if (node.meshes) { - node.meshes = node.meshes.map(mesh => this._convertIdToIndex(mesh, 'mesh')); - } - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.ROTATE_X_POS = 6; - _convertSceneIds(scene) { - if (scene.nodes) { - scene.nodes = scene.nodes.map(node => this._convertIdToIndex(node, 'node')); - } - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.ROTATE_X_NEG = 7; - _convertIdsToIndices(json, topLevelArrayName) { - if (!json[topLevelArrayName]) { - console.warn("gltf v1: json doesn't contain attribute ".concat(topLevelArrayName)); - json[topLevelArrayName] = []; - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.ROTATE_Y_POS = 8; - for (const object of json[topLevelArrayName]) { - for (const key in object) { - const id = object[key]; + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.ROTATE_Y_NEG = 9; - const index = this._convertIdToIndex(id, key); + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.DOLLY_FORWARDS = 10; - object[key] = index; - } - } - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.DOLLY_BACKWARDS = 11; - _convertIdToIndex(id, key) { - const arrayName = GLTF_KEYS[key]; + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.AXIS_VIEW_RIGHT = 12; - if (arrayName in this.idToIndexMap) { - const index = this.idToIndexMap[arrayName][id]; + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.AXIS_VIEW_BACK = 13; - if (!Number.isFinite(index)) { - throw new Error("gltf v1: failed to resolve ".concat(key, " with id ").concat(id)); - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.AXIS_VIEW_LEFT = 14; - return index; - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.AXIS_VIEW_FRONT = 15; - return id; - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.AXIS_VIEW_TOP = 16; - _updateObjects(json) { - for (const buffer of this.json.buffers) { - delete buffer.type; - } - } + /** + * Identifies the XX action. + * @final + * @type {Number} + */ + this.AXIS_VIEW_BOTTOM = 17; - _updateMaterial(json) { - for (const material of json.materials) { - material.pbrMetallicRoughness = { - baseColorFactor: [1, 1, 1, 1], - metallicFactor: 1, - roughnessFactor: 1 - }; - const textureId = material.values && material.values.tex; - const textureIndex = json.textures.findIndex(texture => texture.id === textureId); + this._keyMap = {}; // Maps key codes to the above actions - if (textureIndex !== -1) { - material.pbrMetallicRoughness.baseColorTexture = { - index: textureIndex + this.scene.canvas.canvas.oncontextmenu = (e) => { + e.preventDefault(); }; - } - } - } -} + // User-settable CameraControl configurations -function normalizeGLTFV1(gltf, options = {}) { - return new GLTFV1Normalizer().normalize(gltf, options); -} + this._configs = { -const COMPONENTS = { - SCALAR: 1, - VEC2: 2, - VEC3: 3, - VEC4: 4, - MAT2: 4, - MAT3: 9, - MAT4: 16 -}; -const BYTES = { - 5120: 1, - 5121: 1, - 5122: 2, - 5123: 2, - 5125: 4, - 5126: 4 -}; -const GL_SAMPLER = { - TEXTURE_MAG_FILTER: 0x2800, - TEXTURE_MIN_FILTER: 0x2801, - TEXTURE_WRAP_S: 0x2802, - TEXTURE_WRAP_T: 0x2803, - REPEAT: 0x2901, - LINEAR: 0x2601, - NEAREST_MIPMAP_LINEAR: 0x2702 -}; -const SAMPLER_PARAMETER_GLTF_TO_GL = { - magFilter: GL_SAMPLER.TEXTURE_MAG_FILTER, - minFilter: GL_SAMPLER.TEXTURE_MIN_FILTER, - wrapS: GL_SAMPLER.TEXTURE_WRAP_S, - wrapT: GL_SAMPLER.TEXTURE_WRAP_T -}; -const DEFAULT_SAMPLER = { - [GL_SAMPLER.TEXTURE_MAG_FILTER]: GL_SAMPLER.LINEAR, - [GL_SAMPLER.TEXTURE_MIN_FILTER]: GL_SAMPLER.NEAREST_MIPMAP_LINEAR, - [GL_SAMPLER.TEXTURE_WRAP_S]: GL_SAMPLER.REPEAT, - [GL_SAMPLER.TEXTURE_WRAP_T]: GL_SAMPLER.REPEAT -}; + // Private -function getBytesFromComponentType(componentType) { - return BYTES[componentType]; -} + longTapTimeout: 600, // Millisecs + longTapRadius: 5, // Pixels -function getSizeFromAccessorType(type) { - return COMPONENTS[type]; -} + // General -class GLTFPostProcessor { - constructor() { - _defineProperty(this, "baseUri", ''); + active: true, + keyboardLayout: "qwerty", + navMode: "orbit", + planView: false, + firstPerson: false, + followPointer: true, + doublePickFlyTo: true, + panRightClick: true, + showPivot: false, + pointerEnabled: true, + constrainVertical: false, + smartPivot: false, + doubleClickTimeFrame: 250, - _defineProperty(this, "json", {}); + // Rotation - _defineProperty(this, "buffers", []); + dragRotationRate: 360.0, + keyboardRotationRate: 90.0, + rotationInertia: 0.0, - _defineProperty(this, "images", []); - } + // Panning - postProcess(gltf, options = {}) { - const { - json, - buffers = [], - images = [], - baseUri = '' - } = gltf; - assert$1(json); - this.baseUri = baseUri; - this.json = json; - this.buffers = buffers; - this.images = images; + keyboardPanRate: 1.0, + touchPanRate: 1.0, + panInertia: 0.5, - this._resolveTree(this.json, options); + // Dollying - return this.json; - } + keyboardDollyRate: 10, + mouseWheelDollyRate: 100, + touchDollyRate: 0.2, + dollyInertia: 0, + dollyProximityThreshold: 30.0, + dollyMinSpeed: 0.04 + }; - _resolveTree(json, options = {}) { - if (json.bufferViews) { - json.bufferViews = json.bufferViews.map((bufView, i) => this._resolveBufferView(bufView, i)); - } + // Current runtime state of the CameraControl - if (json.images) { - json.images = json.images.map((image, i) => this._resolveImage(image, i)); - } + this._states = { + pointerCanvasPos: math.vec2(), + mouseover: false, + followPointerDirty: true, + mouseDownClientX: 0, + mouseDownClientY: 0, + mouseDownCursorX: 0, + mouseDownCursorY: 0, + touchStartTime: null, + activeTouches: [], + tapStartPos: math.vec2(), + tapStartTime: -1, + lastTapTime: -1, + longTouchTimeout: null + }; - if (json.samplers) { - json.samplers = json.samplers.map((sampler, i) => this._resolveSampler(sampler, i)); - } + // Updates for CameraUpdater to process on next Scene "tick" event - if (json.textures) { - json.textures = json.textures.map((texture, i) => this._resolveTexture(texture, i)); - } + this._updates = { + rotateDeltaX: 0, + rotateDeltaY: 0, + panDeltaX: 0, + panDeltaY: 0, + panDeltaZ: 0, + dollyDelta: 0 + }; - if (json.accessors) { - json.accessors = json.accessors.map((accessor, i) => this._resolveAccessor(accessor, i)); - } + // Controllers to assist input event handlers with controlling the Camera - if (json.materials) { - json.materials = json.materials.map((material, i) => this._resolveMaterial(material, i)); - } + const scene = this.scene; - if (json.meshes) { - json.meshes = json.meshes.map((mesh, i) => this._resolveMesh(mesh, i)); - } + this._controllers = { + cameraControl: this, + pickController: new PickController(this, this._configs), + pivotController: new PivotController(scene, this._configs), + panController: new PanController(scene), + cameraFlight: new CameraFlightAnimation(this, { + duration: 0.5 + }) + }; - if (json.nodes) { - json.nodes = json.nodes.map((node, i) => this._resolveNode(node, i)); - } + // Input event handlers - if (json.skins) { - json.skins = json.skins.map((skin, i) => this._resolveSkin(skin, i)); - } + this._handlers = [ + new MouseMiscHandler(this.scene, this._controllers, this._configs, this._states, this._updates), + new TouchPanRotateAndDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates), + new MousePanRotateDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates), + new KeyboardAxisViewHandler(this.scene, this._controllers, this._configs, this._states, this._updates), + new MousePickHandler(this.scene, this._controllers, this._configs, this._states, this._updates), + new TouchPickHandler(this.scene, this._controllers, this._configs, this._states, this._updates), + new KeyboardPanRotateDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates) + ]; - if (json.scenes) { - json.scenes = json.scenes.map((scene, i) => this._resolveScene(scene, i)); - } + // Applies scheduled updates to the Camera on each Scene "tick" event - if (json.scene !== undefined) { - json.scene = json.scenes[this.json.scene]; - } - } + this._cameraUpdater = new CameraUpdater(this.scene, this._controllers, this._configs, this._states, this._updates); - getScene(index) { - return this._get('scenes', index); - } + // Set initial user configurations - getNode(index) { - return this._get('nodes', index); - } + this.navMode = cfg.navMode; + if (cfg.planView) { + this.planView = cfg.planView; + } + this.constrainVertical = cfg.constrainVertical; + if (cfg.keyboardLayout) { + this.keyboardLayout = cfg.keyboardLayout; // Deprecated + } else { + this.keyMap = cfg.keyMap; + } + this.doublePickFlyTo = cfg.doublePickFlyTo; + this.panRightClick = cfg.panRightClick; + this.active = cfg.active; + this.followPointer = cfg.followPointer; + this.rotationInertia = cfg.rotationInertia; + this.keyboardPanRate = cfg.keyboardPanRate; + this.touchPanRate = cfg.touchPanRate; + this.keyboardRotationRate = cfg.keyboardRotationRate; + this.dragRotationRate = cfg.dragRotationRate; + this.touchDollyRate = cfg.touchDollyRate; + this.dollyInertia = cfg.dollyInertia; + this.dollyProximityThreshold = cfg.dollyProximityThreshold; + this.dollyMinSpeed = cfg.dollyMinSpeed; + this.panInertia = cfg.panInertia; + this.pointerEnabled = true; + this.keyboardDollyRate = cfg.keyboardDollyRate; + this.mouseWheelDollyRate = cfg.mouseWheelDollyRate; + } - getSkin(index) { - return this._get('skins', index); - } + /** + * Sets custom mappings of keys to ````CameraControl```` actions. + * + * See class docs for usage. + * + * @param {{Number:Number}|String} value Either a set of new key mappings, or a string to select a keyboard layout, + * which causes ````CameraControl```` to use the default key mappings for that layout. + */ + set keyMap(value) { + value = value || "qwerty"; + if (utils.isString(value)) { + const input = this.scene.input; + const keyMap = {}; - getMesh(index) { - return this._get('meshes', index); - } + switch (value) { - getMaterial(index) { - return this._get('materials', index); - } + default: + this.error("Unsupported value for 'keyMap': " + value + " defaulting to 'qwerty'"); + // Intentional fall-through to "qwerty" + case "qwerty": + keyMap[this.PAN_LEFT] = [input.KEY_A]; + keyMap[this.PAN_RIGHT] = [input.KEY_D]; + keyMap[this.PAN_UP] = [input.KEY_Z]; + keyMap[this.PAN_DOWN] = [input.KEY_X]; + keyMap[this.PAN_BACKWARDS] = []; + keyMap[this.PAN_FORWARDS] = []; + keyMap[this.DOLLY_FORWARDS] = [input.KEY_W, input.KEY_ADD]; + keyMap[this.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT]; + keyMap[this.ROTATE_X_POS] = [input.KEY_DOWN_ARROW]; + keyMap[this.ROTATE_X_NEG] = [input.KEY_UP_ARROW]; + keyMap[this.ROTATE_Y_POS] = [input.KEY_Q, input.KEY_LEFT_ARROW]; + keyMap[this.ROTATE_Y_NEG] = [input.KEY_E, input.KEY_RIGHT_ARROW]; + keyMap[this.AXIS_VIEW_RIGHT] = [input.KEY_NUM_1]; + keyMap[this.AXIS_VIEW_BACK] = [input.KEY_NUM_2]; + keyMap[this.AXIS_VIEW_LEFT] = [input.KEY_NUM_3]; + keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4]; + keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5]; + keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6]; + break; - getAccessor(index) { - return this._get('accessors', index); - } + case "azerty": + keyMap[this.PAN_LEFT] = [input.KEY_Q]; + keyMap[this.PAN_RIGHT] = [input.KEY_D]; + keyMap[this.PAN_UP] = [input.KEY_W]; + keyMap[this.PAN_DOWN] = [input.KEY_X]; + keyMap[this.PAN_BACKWARDS] = []; + keyMap[this.PAN_FORWARDS] = []; + keyMap[this.DOLLY_FORWARDS] = [input.KEY_Z, input.KEY_ADD]; + keyMap[this.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT]; + keyMap[this.ROTATE_X_POS] = [input.KEY_DOWN_ARROW]; + keyMap[this.ROTATE_X_NEG] = [input.KEY_UP_ARROW]; + keyMap[this.ROTATE_Y_POS] = [input.KEY_A, input.KEY_LEFT_ARROW]; + keyMap[this.ROTATE_Y_NEG] = [input.KEY_E, input.KEY_RIGHT_ARROW]; + keyMap[this.AXIS_VIEW_RIGHT] = [input.KEY_NUM_1]; + keyMap[this.AXIS_VIEW_BACK] = [input.KEY_NUM_2]; + keyMap[this.AXIS_VIEW_LEFT] = [input.KEY_NUM_3]; + keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4]; + keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5]; + keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6]; + break; + } - getCamera(index) { - return null; - } + this._keyMap = keyMap; + } else { + const keyMap = value; + this._keyMap = keyMap; + } + } - getTexture(index) { - return this._get('textures', index); - } + /** + * Gets custom mappings of keys to {@link CameraControl} actions. + * + * @returns {{Number:Number}} Current key mappings. + */ + get keyMap() { + return this._keyMap; + } - getSampler(index) { - return this._get('samplers', index); - } + /** + * Returns true if any keys configured for the given action are down. + * @param action + * @param keyDownMap + * @private + */ + _isKeyDownForAction(action, keyDownMap) { + const keys = this._keyMap[action]; + if (!keys) { + return false; + } + if (!keyDownMap) { + keyDownMap = this.scene.input.keyDown; + } + for (let i = 0, len = keys.length; i < len; i++) { + const key = keys[i]; + if (keyDownMap[key]) { + return true; + } + } + return false; + } - getImage(index) { - return this._get('images', index); - } + /** + * Sets the HTMl element to represent the pivot point when {@link CameraControl#followPointer} is true. + * + * See class comments for an example. + * + * @param {HTMLElement} element HTML element representing the pivot point. + */ + set pivotElement(element) { + this._controllers.pivotController.setPivotElement(element); + } - getBufferView(index) { - return this._get('bufferViews', index); - } + /** + * Sets if this ````CameraControl```` is active or not. + * + * When inactive, the ````CameraControl```` will not react to input. + * + * Default is ````true````. + * + * @param {Boolean} value Set ````true```` to activate this ````CameraControl````. + */ + set active(value) { + this._configs.active = value !== false; + } - getBuffer(index) { - return this._get('buffers', index); - } + /** + * Gets if this ````CameraControl```` is active or not. + * + * When inactive, the ````CameraControl```` will not react to input. + * + * Default is ````true````. + * + * @returns {Boolean} Returns ````true```` if this ````CameraControl```` is active. + */ + get active() { + return this._configs.active; + } - _get(array, index) { - if (typeof index === 'object') { - return index; + /** + * Sets the current navigation mode. + * + * Accepted values are: + * + * * "orbit" - rotation orbits about the current target or pivot point, + * * "firstPerson" - rotation is about the current eye position, + * * "planView" - rotation is disabled. + * + * See class comments for more info. + * + * @param {String} navMode The navigation mode: "orbit", "firstPerson" or "planView". + */ + set navMode(navMode) { + navMode = navMode || "orbit"; + if (navMode !== "firstPerson" && navMode !== "orbit" && navMode !== "planView") { + this.error("Unsupported value for navMode: " + navMode + " - supported values are 'orbit', 'firstPerson' and 'planView' - defaulting to 'orbit'"); + navMode = "orbit"; + } + this._configs.firstPerson = (navMode === "firstPerson"); + this._configs.planView = (navMode === "planView"); + if (this._configs.firstPerson || this._configs.planView) { + this._controllers.pivotController.hidePivot(); + this._controllers.pivotController.endPivot(); + } + this._configs.navMode = navMode; } - const object = this.json[array] && this.json[array][index]; + /** + * Gets the current navigation mode. + * + * @returns {String} The navigation mode: "orbit", "firstPerson" or "planView". + */ + get navMode() { + return this._configs.navMode; + } - if (!object) { - console.warn("glTF file error: Could not find ".concat(array, "[").concat(index, "]")); + /** + * Sets whether mouse and touch input is enabled. + * + * Default is ````true````. + * + * Disabling mouse and touch input on ````CameraControl```` is useful when we want to temporarily use mouse or + * touch input to interact with some other 3D control, without disturbing the {@link Camera}. + * + * @param {Boolean} value Set ````true```` to enable mouse and touch input. + */ + set pointerEnabled(value) { + this._reset(); + this._configs.pointerEnabled = !!value; } - return object; - } + _reset() { + for (let i = 0, len = this._handlers.length; i < len; i++) { + const handler = this._handlers[i]; + if (handler.reset) { + handler.reset(); + } + } - _resolveScene(scene, index) { - scene.id = scene.id || "scene-".concat(index); - scene.nodes = (scene.nodes || []).map(node => this.getNode(node)); - return scene; - } + this._updates.panDeltaX = 0; + this._updates.panDeltaY = 0; + this._updates.rotateDeltaX = 0; + this._updates.rotateDeltaY = 0; + this._updates.dolyDelta = 0; + } - _resolveNode(node, index) { - node.id = node.id || "node-".concat(index); + /** + * Gets whether mouse and touch input is enabled. + * + * Default is ````true````. + * + * Disabling mouse and touch input on ````CameraControl```` is desirable when we want to temporarily use mouse or + * touch input to interact with some other 3D control, without interfering with the {@link Camera}. + * + * @returns {Boolean} Returns ````true```` if mouse and touch input is enabled. + */ + get pointerEnabled() { + return this._configs.pointerEnabled; + } - if (node.children) { - node.children = node.children.map(child => this.getNode(child)); + /** + * Sets whether the {@link Camera} follows the mouse/touch pointer. + * + * In orbiting mode, the Camera will orbit about the pointer, and will dolly to and from the pointer. + * + * In fly-to mode, the Camera will dolly to and from the pointer, however the World will always rotate about the Camera position. + * + * In plan-view mode, the Camera will dolly to and from the pointer, however the Camera will not rotate. + * + * Default is ````true````. + * + * See class comments for more info. + * + * @param {Boolean} value Set ````true```` to enable the Camera to follow the pointer. + */ + set followPointer(value) { + this._configs.followPointer = (value !== false); } - if (node.mesh !== undefined) { - node.mesh = this.getMesh(node.mesh); - } else if (node.meshes !== undefined && node.meshes.length) { - node.mesh = node.meshes.reduce((accum, meshIndex) => { - const mesh = this.getMesh(meshIndex); - accum.id = mesh.id; - accum.primitives = accum.primitives.concat(mesh.primitives); - return accum; - }, { - primitives: [] - }); + /** + * Sets whether the {@link Camera} follows the mouse/touch pointer. + * + * In orbiting mode, the Camera will orbit about the pointer, and will dolly to and from the pointer. + * + * In fly-to mode, the Camera will dolly to and from the pointer, however the World will always rotate about the Camera position. + * + * In plan-view mode, the Camera will dolly to and from the pointer, however the Camera will not rotate. + * + * Default is ````true````. + * + * See class comments for more info. + * + * @returns {Boolean} Returns ````true```` if the Camera follows the pointer. + */ + get followPointer() { + return this._configs.followPointer; } - if (node.camera !== undefined) { - node.camera = this.getCamera(node.camera); + /** + * Sets the current World-space 3D target position. + * + * Only applies when {@link CameraControl#followPointer} is ````true````. + * + * @param {Number[]} worldPos The new World-space 3D target position. + */ + set pivotPos(worldPos) { + this._controllers.pivotController.setPivotPos(worldPos); } - if (node.skin !== undefined) { - node.skin = this.getSkin(node.skin); + /** + * Gets the current World-space 3D pivot position. + * + * Only applies when {@link CameraControl#followPointer} is ````true````. + * + * @return {Number[]} worldPos The current World-space 3D pivot position. + */ + get pivotPos() { + return this._controllers.pivotController.getPivotPos(); } - return node; - } + /** + * @deprecated + * @param {Boolean} value Set ````true```` to enable dolly-to-pointer behaviour. + */ + set dollyToPointer(value) { + this.warn("dollyToPointer property is deprecated - replaced with followPointer"); + this.followPointer = value; + } - _resolveSkin(skin, index) { - skin.id = skin.id || "skin-".concat(index); - skin.inverseBindMatrices = this.getAccessor(skin.inverseBindMatrices); - return skin; - } + /** + * @deprecated + * @returns {Boolean} Returns ````true```` if dolly-to-pointer behaviour is enabled. + */ + get dollyToPointer() { + this.warn("dollyToPointer property is deprecated - replaced with followPointer"); + return this.followPointer; + } - _resolveMesh(mesh, index) { - mesh.id = mesh.id || "mesh-".concat(index); + /** + * @deprecated + * @param {Boolean} value Set ````true```` to enable dolly-to-pointer behaviour. + */ + set panToPointer(value) { + this.warn("panToPointer property is deprecated - replaced with followPointer"); + } - if (mesh.primitives) { - mesh.primitives = mesh.primitives.map(primitive => { - primitive = { ...primitive - }; - const attributes = primitive.attributes; - primitive.attributes = {}; + /** + * @deprecated + * @returns {Boolean} Returns ````true```` if dolly-to-pointer behaviour is enabled. + */ + get panToPointer() { + this.warn("panToPointer property is deprecated - replaced with followPointer"); + return false; + } - for (const attribute in attributes) { - primitive.attributes[attribute] = this.getAccessor(attributes[attribute]); + /** + * Sets whether this ````CameraControl```` is in plan-view mode. + * + * When in plan-view mode, rotation is disabled. + * + * Default is ````false````. + * + * Deprecated - use {@link CameraControl#navMode} instead. + * + * @param {Boolean} value Set ````true```` to enable plan-view mode. + * @deprecated + */ + set planView(value) { + this._configs.planView = !!value; + this._configs.firstPerson = false; + if (this._configs.planView) { + this._controllers.pivotController.hidePivot(); + this._controllers.pivotController.endPivot(); } + this.warn("planView property is deprecated - replaced with navMode"); + } - if (primitive.indices !== undefined) { - primitive.indices = this.getAccessor(primitive.indices); - } + /** + * Gets whether this ````CameraControl```` is in plan-view mode. + * + * When in plan-view mode, rotation is disabled. + * + * Default is ````false````. + * + * Deprecated - use {@link CameraControl#navMode} instead. + * + * @returns {Boolean} Returns ````true```` if plan-view mode is enabled. + * @deprecated + */ + get planView() { + this.warn("planView property is deprecated - replaced with navMode"); + return this._configs.planView; + } - if (primitive.material !== undefined) { - primitive.material = this.getMaterial(primitive.material); + /** + * Sets whether this ````CameraControl```` is in first-person mode. + * + * In "first person" mode (disabled by default) the look position rotates about the eye position. Otherwise, {@link Camera#eye} rotates about {@link Camera#look}. + * + * Default is ````false````. + * + * Deprecated - use {@link CameraControl#navMode} instead. + * + * @param {Boolean} value Set ````true```` to enable first-person mode. + * @deprecated + */ + set firstPerson(value) { + this.warn("firstPerson property is deprecated - replaced with navMode"); + this._configs.firstPerson = !!value; + this._configs.planView = false; + if (this._configs.firstPerson) { + this._controllers.pivotController.hidePivot(); + this._controllers.pivotController.endPivot(); } - - return primitive; - }); } - return mesh; - } - - _resolveMaterial(material, index) { - material.id = material.id || "material-".concat(index); - - if (material.normalTexture) { - material.normalTexture = { ...material.normalTexture - }; - material.normalTexture.texture = this.getTexture(material.normalTexture.index); + /** + * Gets whether this ````CameraControl```` is in first-person mode. + * + * In "first person" mode (disabled by default) the look position rotates about the eye position. Otherwise, {@link Camera#eye} rotates about {@link Camera#look}. + * + * Default is ````false````. + * + * Deprecated - use {@link CameraControl#navMode} instead. + * + * @returns {Boolean} Returns ````true```` if first-person mode is enabled. + * @deprecated + */ + get firstPerson() { + this.warn("firstPerson property is deprecated - replaced with navMode"); + return this._configs.firstPerson; } - if (material.occlusionTexture) { - material.occlustionTexture = { ...material.occlustionTexture - }; - material.occlusionTexture.texture = this.getTexture(material.occlusionTexture.index); + /** + * Sets whether to vertically constrain the {@link Camera} position for first-person navigation. + * + * When set ````true````, this constrains {@link Camera#eye} to its current vertical position. + * + * Only applies when {@link CameraControl#navMode} is ````"firstPerson"````. + * + * Default is ````false````. + * + * @param {Boolean} value Set ````true```` to vertically constrain the Camera. + */ + set constrainVertical(value) { + this._configs.constrainVertical = !!value; } - if (material.emissiveTexture) { - material.emmisiveTexture = { ...material.emmisiveTexture - }; - material.emissiveTexture.texture = this.getTexture(material.emissiveTexture.index); + /** + * Gets whether to vertically constrain the {@link Camera} position for first-person navigation. + * + * When set ````true````, this constrains {@link Camera#eye} to its current vertical position. + * + * Only applies when {@link CameraControl#navMode} is ````"firstPerson"````. + * + * Default is ````false````. + * + * @returns {Boolean} ````true```` when Camera is vertically constrained. + */ + get constrainVertical() { + return this._configs.constrainVertical; } - if (!material.emissiveFactor) { - material.emissiveFactor = material.emmisiveTexture ? [1, 1, 1] : [0, 0, 0]; + /** + * Sets whether double-picking an {@link Entity} causes the {@link Camera} to fly to its boundary. + * + * Default is ````false````. + * + * @param {Boolean} value Set ````true```` to enable double-pick-fly-to mode. + */ + set doublePickFlyTo(value) { + this._configs.doublePickFlyTo = value !== false; } - if (material.pbrMetallicRoughness) { - material.pbrMetallicRoughness = { ...material.pbrMetallicRoughness - }; - const mr = material.pbrMetallicRoughness; - - if (mr.baseColorTexture) { - mr.baseColorTexture = { ...mr.baseColorTexture - }; - mr.baseColorTexture.texture = this.getTexture(mr.baseColorTexture.index); - } - - if (mr.metallicRoughnessTexture) { - mr.metallicRoughnessTexture = { ...mr.metallicRoughnessTexture - }; - mr.metallicRoughnessTexture.texture = this.getTexture(mr.metallicRoughnessTexture.index); - } + /** + * Gets whether double-picking an {@link Entity} causes the {@link Camera} to fly to its boundary. + * + * Default is ````false````. + * + * @returns {Boolean} Returns ````true```` when double-pick-fly-to mode is enabled. + */ + get doublePickFlyTo() { + return this._configs.doublePickFlyTo; } - return material; - } - - _resolveAccessor(accessor, index) { - accessor.id = accessor.id || "accessor-".concat(index); - - if (accessor.bufferView !== undefined) { - accessor.bufferView = this.getBufferView(accessor.bufferView); + /** + * Sets whether either right-clicking (true) or middle-clicking (false) pans the {@link Camera}. + * + * Default is ````true````. + * + * @param {Boolean} value Set ````false```` to disable pan on right-click. + */ + set panRightClick(value) { + this._configs.panRightClick = value !== false; } - accessor.bytesPerComponent = getBytesFromComponentType(accessor.componentType); - accessor.components = getSizeFromAccessorType(accessor.type); - accessor.bytesPerElement = accessor.bytesPerComponent * accessor.components; - - if (accessor.bufferView) { - const buffer = accessor.bufferView.buffer; - const { - ArrayType, - byteLength - } = getAccessorArrayTypeAndLength(accessor, accessor.bufferView); - const byteOffset = (accessor.bufferView.byteOffset || 0) + (accessor.byteOffset || 0) + buffer.byteOffset; - let cutBuffer = buffer.arrayBuffer.slice(byteOffset, byteOffset + byteLength); - - if (accessor.bufferView.byteStride) { - cutBuffer = this._getValueFromInterleavedBuffer(buffer, byteOffset, accessor.bufferView.byteStride, accessor.bytesPerElement, accessor.count); - } - - accessor.value = new ArrayType(cutBuffer); + /** + * Gets whether right-clicking pans the {@link Camera}. + * + * Default is ````true````. + * + * @returns {Boolean} Returns ````false```` when pan on right-click is disabled. + */ + get panRightClick() { + return this._configs.panRightClick; } - return accessor; - } - - _getValueFromInterleavedBuffer(buffer, byteOffset, byteStride, bytesPerElement, count) { - const result = new Uint8Array(count * bytesPerElement); + /** + * Sets a factor in range ````[0..1]```` indicating how much the {@link Camera} keeps moving after you finish rotating it. + * + * A value of ````0.0```` causes it to immediately stop, ````0.5```` causes its movement to decay 50% on each tick, + * while ````1.0```` causes no decay, allowing it continue moving, by the current rate of rotation. + * + * You may choose an inertia of zero when you want be able to precisely rotate the Camera, + * without interference from inertia. Zero inertia can also mean that less frames are rendered while + * you are rotating the Camera. + * + * Default is ````0.0````. + * + * Does not apply when {@link CameraControl#navMode} is ````"planView"````, which disallows rotation. + * + * @param {Number} rotationInertia New inertial factor. + */ + set rotationInertia(rotationInertia) { + this._configs.rotationInertia = (rotationInertia !== undefined && rotationInertia !== null) ? rotationInertia : 0.0; + } - for (let i = 0; i < count; i++) { - const elementOffset = byteOffset + i * byteStride; - result.set(new Uint8Array(buffer.arrayBuffer.slice(elementOffset, elementOffset + bytesPerElement)), i * bytesPerElement); + /** + * Gets the rotation inertia factor. + * + * Default is ````0.0````. + * + * Does not apply when {@link CameraControl#navMode} is ````"planView"````, which disallows rotation. + * + * @returns {Number} The inertia factor. + */ + get rotationInertia() { + return this._configs.rotationInertia; } - return result.buffer; - } + /** + * Sets how much the {@link Camera} pans each second with keyboard input. + * + * Default is ````5.0````, to pan the Camera ````5.0```` World-space units every second that + * a panning key is depressed. See the ````CameraControl```` class documentation for which keys control + * panning. + * + * Panning direction is aligned to our Camera's orientation. When we pan horizontally, we pan + * to our left and right, when we pan vertically, we pan upwards and downwards, and when we pan forwards + * and backwards, we pan along the direction the Camera is pointing. + * + * Unlike dollying when {@link followPointer} is ````true````, panning does not follow the pointer. + * + * @param {Number} keyboardPanRate The new keyboard pan rate. + */ + set keyboardPanRate(keyboardPanRate) { + this._configs.keyboardPanRate = (keyboardPanRate !== null && keyboardPanRate !== undefined) ? keyboardPanRate : 5.0; + } - _resolveTexture(texture, index) { - texture.id = texture.id || "texture-".concat(index); - texture.sampler = 'sampler' in texture ? this.getSampler(texture.sampler) : DEFAULT_SAMPLER; - texture.source = this.getImage(texture.source); - return texture; - } - _resolveSampler(sampler, index) { - sampler.id = sampler.id || "sampler-".concat(index); - sampler.parameters = {}; + /** + * Sets how fast the camera pans on touch panning + * + * @param {Number} touchPanRate The new touch pan rate. + */ + set touchPanRate(touchPanRate) { + this._configs.touchPanRate = (touchPanRate !== null && touchPanRate !== undefined) ? touchPanRate : 1.0; + } - for (const key in sampler) { - const glEnum = this._enumSamplerParameter(key); + /** + * Gets how fast the {@link Camera} pans on touch panning + * + * Default is ````1.0````. + * + * @returns {Number} The current touch pan rate. + */ + get touchPanRate() { + return this._configs.touchPanRate; + } - if (glEnum !== undefined) { - sampler.parameters[glEnum] = sampler[key]; - } + /** + * Gets how much the {@link Camera} pans each second with keyboard input. + * + * Default is ````5.0````. + * + * @returns {Number} The current keyboard pan rate. + */ + get keyboardPanRate() { + return this._configs.keyboardPanRate; } - return sampler; - } + /** + * Sets how many degrees per second the {@link Camera} rotates/orbits with keyboard input. + * + * Default is ````90.0````, to rotate/orbit the Camera ````90.0```` degrees every second that + * a rotation key is depressed. See the ````CameraControl```` class documentation for which keys control + * rotation/orbit. + * + * @param {Number} keyboardRotationRate The new keyboard rotation rate. + */ + set keyboardRotationRate(keyboardRotationRate) { + this._configs.keyboardRotationRate = (keyboardRotationRate !== null && keyboardRotationRate !== undefined) ? keyboardRotationRate : 90.0; + } - _enumSamplerParameter(key) { - return SAMPLER_PARAMETER_GLTF_TO_GL[key]; - } + /** + * Sets how many degrees per second the {@link Camera} rotates/orbits with keyboard input. + * + * Default is ````90.0````. + * + * @returns {Number} The current keyboard rotation rate. + */ + get keyboardRotationRate() { + return this._configs.keyboardRotationRate; + } - _resolveImage(image, index) { - image.id = image.id || "image-".concat(index); + /** + * Sets the current drag rotation rate. + * + * This configures how many degrees the {@link Camera} rotates/orbits for a full sweep of the canvas by mouse or touch dragging. + * + * For example, a value of ````360.0```` indicates that the ````Camera```` rotates/orbits ````360.0```` degrees horizontally + * when we sweep the entire width of the canvas. + * + * ````CameraControl```` makes vertical rotation half as sensitive as horizontal rotation, so that we don't tend to + * flip upside-down. Therefore, a value of ````360.0```` rotates/orbits the ````Camera```` through ````180.0```` degrees + * vertically when we sweep the entire height of the canvas. + * + * Default is ````360.0````. + * + * @param {Number} dragRotationRate The new drag rotation rate. + */ + set dragRotationRate(dragRotationRate) { + this._configs.dragRotationRate = (dragRotationRate !== null && dragRotationRate !== undefined) ? dragRotationRate : 360.0; + } - if (image.bufferView !== undefined) { - image.bufferView = this.getBufferView(image.bufferView); + /** + * Gets the current drag rotation rate. + * + * Default is ````360.0````. + * + * @returns {Number} The current drag rotation rate. + */ + get dragRotationRate() { + return this._configs.dragRotationRate; } - const preloadedImage = this.images[index]; + /** + * Sets how much the {@link Camera} dollys each second with keyboard input. + * + * Default is ````15.0````, to dolly the {@link Camera} ````15.0```` World-space units per second while we hold down + * the ````+```` and ````-```` keys. + * + * @param {Number} keyboardDollyRate The new keyboard dolly rate. + */ + set keyboardDollyRate(keyboardDollyRate) { + this._configs.keyboardDollyRate = (keyboardDollyRate !== null && keyboardDollyRate !== undefined) ? keyboardDollyRate : 15.0; + } - if (preloadedImage) { - image.image = preloadedImage; + /** + * Gets how much the {@link Camera} dollys each second with keyboard input. + * + * Default is ````15.0````. + * + * @returns {Number} The current keyboard dolly rate. + */ + get keyboardDollyRate() { + return this._configs.keyboardDollyRate; } - return image; - } - - _resolveBufferView(bufferView, index) { - const bufferIndex = bufferView.buffer; - const result = { - id: "bufferView-".concat(index), - ...bufferView, - buffer: this.buffers[bufferIndex] - }; - const arrayBuffer = this.buffers[bufferIndex].arrayBuffer; - let byteOffset = this.buffers[bufferIndex].byteOffset || 0; - - if ('byteOffset' in bufferView) { - byteOffset += bufferView.byteOffset; + /** + * Sets how much the {@link Camera} dollys with touch input. + * + * Default is ````0.2```` + * + * @param {Number} touchDollyRate The new touch dolly rate. + */ + set touchDollyRate(touchDollyRate) { + this._configs.touchDollyRate = (touchDollyRate !== null && touchDollyRate !== undefined) ? touchDollyRate : 0.2; } - result.data = new Uint8Array(arrayBuffer, byteOffset, bufferView.byteLength); - return result; - } + /** + * Gets how much the {@link Camera} dollys each second with touch input. + * + * Default is ````0.2````. + * + * @returns {Number} The current touch dolly rate. + */ + get touchDollyRate() { + return this._configs.touchDollyRate; + } - _resolveCamera(camera, index) { - camera.id = camera.id || "camera-".concat(index); + /** + * Sets how much the {@link Camera} dollys each second while the mouse wheel is spinning. + * + * Default is ````100.0````, to dolly the {@link Camera} ````10.0```` World-space units per second as we spin + * the mouse wheel. + * + * @param {Number} mouseWheelDollyRate The new mouse wheel dolly rate. + */ + set mouseWheelDollyRate(mouseWheelDollyRate) { + this._configs.mouseWheelDollyRate = (mouseWheelDollyRate !== null && mouseWheelDollyRate !== undefined) ? mouseWheelDollyRate : 100.0; + } - if (camera.perspective) ; + /** + * Gets how much the {@link Camera} dollys each second while the mouse wheel is spinning. + * + * Default is ````100.0````. + * + * @returns {Number} The current mouseWheel dolly rate. + */ + get mouseWheelDollyRate() { + return this._configs.mouseWheelDollyRate; + } - if (camera.orthographic) ; + /** + * Sets the dolly inertia factor. + * + * This factor configures how much the {@link Camera} keeps moving after you finish dollying it. + * + * This factor is a value in range ````[0..1]````. A value of ````0.0```` causes dollying to immediately stop, + * ````0.5```` causes dollying to decay 50% on each animation frame, while ````1.0```` causes no decay, which allows dollying + * to continue until further input stops it. + * + * You might set ````dollyInertia```` to zero when you want be able to precisely position or rotate the Camera, + * without interference from inertia. This also means that xeokit renders less frames while dollying the Camera, + * which can improve rendering performance. + * + * Default is ````0````. + * + * @param {Number} dollyInertia New dolly inertia factor. + */ + set dollyInertia(dollyInertia) { + this._configs.dollyInertia = (dollyInertia !== undefined && dollyInertia !== null) ? dollyInertia : 0; + } - return camera; - } + /** + * Gets the dolly inertia factor. + * + * Default is ````0````. + * + * @returns {Number} The current dolly inertia factor. + */ + get dollyInertia() { + return this._configs.dollyInertia; + } -} + /** + * Sets the proximity to the closest object below which dolly speed decreases, and above which dolly speed increases. + * + * Default is ````35.0````. + * + * @param {Number} dollyProximityThreshold New dolly proximity threshold. + */ + set dollyProximityThreshold(dollyProximityThreshold) { + this._configs.dollyProximityThreshold = (dollyProximityThreshold !== undefined && dollyProximityThreshold !== null) ? dollyProximityThreshold : 35.0; + } -function postProcessGLTF(gltf, options) { - return new GLTFPostProcessor().postProcess(gltf, options); -} + /** + * Gets the proximity to the closest object below which dolly speed decreases, and above which dolly speed increases. + * + * Default is ````35.0````. + * + * @returns {Number} The current dolly proximity threshold. + */ + get dollyProximityThreshold() { + return this._configs.dollyProximityThreshold; + } -const MAGIC_glTF = 0x676c5446; -const GLB_FILE_HEADER_SIZE = 12; -const GLB_CHUNK_HEADER_SIZE = 8; -const GLB_CHUNK_TYPE_JSON = 0x4e4f534a; -const GLB_CHUNK_TYPE_BIN = 0x004e4942; -const GLB_CHUNK_TYPE_JSON_XVIZ_DEPRECATED = 0; -const GLB_CHUNK_TYPE_BIX_XVIZ_DEPRECATED = 1; -const GLB_V1_CONTENT_FORMAT_JSON = 0x0; -const LE = true; + /** + * Sets the minimum dolly speed. + * + * Default is ````0.04````. + * + * @param {Number} dollyMinSpeed New dolly minimum speed. + */ + set dollyMinSpeed(dollyMinSpeed) { + this._configs.dollyMinSpeed = (dollyMinSpeed !== undefined && dollyMinSpeed !== null) ? dollyMinSpeed : 0.04; + } -function getMagicString(dataView, byteOffset = 0) { - return "".concat(String.fromCharCode(dataView.getUint8(byteOffset + 0))).concat(String.fromCharCode(dataView.getUint8(byteOffset + 1))).concat(String.fromCharCode(dataView.getUint8(byteOffset + 2))).concat(String.fromCharCode(dataView.getUint8(byteOffset + 3))); -} + /** + * Gets the minimum dolly speed. + * + * Default is ````0.04````. + * + * @returns {Number} The current minimum dolly speed. + */ + get dollyMinSpeed() { + return this._configs.dollyMinSpeed; + } -function isGLB(arrayBuffer, byteOffset = 0, options = {}) { - const dataView = new DataView(arrayBuffer); - const { - magic = MAGIC_glTF - } = options; - const magic1 = dataView.getUint32(byteOffset, false); - return magic1 === magic || magic1 === MAGIC_glTF; -} -function parseGLBSync(glb, arrayBuffer, byteOffset = 0, options = {}) { - const dataView = new DataView(arrayBuffer); - const type = getMagicString(dataView, byteOffset + 0); - const version = dataView.getUint32(byteOffset + 4, LE); - const byteLength = dataView.getUint32(byteOffset + 8, LE); - Object.assign(glb, { - header: { - byteOffset, - byteLength, - hasBinChunk: false - }, - type, - version, - json: {}, - binChunks: [] - }); - byteOffset += GLB_FILE_HEADER_SIZE; + /** + * Sets the pan inertia factor. + * + * This factor configures how much the {@link Camera} keeps moving after you finish panning it. + * + * This factor is a value in range ````[0..1]````. A value of ````0.0```` causes panning to immediately stop, + * ````0.5```` causes panning to decay 50% on each animation frame, while ````1.0```` causes no decay, which allows panning + * to continue until further input stops it. + * + * You might set ````panInertia```` to zero when you want be able to precisely position or rotate the Camera, + * without interference from inertia. This also means that xeokit renders less frames while panning the Camera, + * wich can improve rendering performance. + * + * Default is ````0.5````. + * + * @param {Number} panInertia New pan inertia factor. + */ + set panInertia(panInertia) { + this._configs.panInertia = (panInertia !== undefined && panInertia !== null) ? panInertia : 0.5; + } - switch (glb.version) { - case 1: - return parseGLBV1(glb, dataView, byteOffset); + /** + * Gets the pan inertia factor. + * + * Default is ````0.5````. + * + * @returns {Number} The current pan inertia factor. + */ + get panInertia() { + return this._configs.panInertia; + } - case 2: - return parseGLBV2(glb, dataView, byteOffset, options = {}); + /** + * Sets the keyboard layout. + * + * Supported layouts are: + * + * * ````"qwerty"```` (default) + * * ````"azerty"```` + * + * @deprecated + * @param {String} value Selects the keyboard layout. + */ + set keyboardLayout(value) { + // this.warn("keyboardLayout property is deprecated - use keyMap property instead"); + value = value || "qwerty"; + if (value !== "qwerty" && value !== "azerty") { + this.error("Unsupported value for keyboardLayout - defaulting to 'qwerty'"); + value = "qwerty"; + } + this._configs.keyboardLayout = value; + this.keyMap = this._configs.keyboardLayout; + } - default: - throw new Error("Invalid GLB version ".concat(glb.version, ". Only supports v1 and v2.")); - } -} + /** + * Gets the keyboard layout. + * + * Supported layouts are: + * + * * ````"qwerty"```` (default) + * * ````"azerty"```` + * + * @deprecated + * @returns {String} The current keyboard layout. + */ + get keyboardLayout() { + return this._configs.keyboardLayout; + } -function parseGLBV1(glb, dataView, byteOffset) { - assert$5(glb.header.byteLength > GLB_FILE_HEADER_SIZE + GLB_CHUNK_HEADER_SIZE); - const contentLength = dataView.getUint32(byteOffset + 0, LE); - const contentFormat = dataView.getUint32(byteOffset + 4, LE); - byteOffset += GLB_CHUNK_HEADER_SIZE; - assert$5(contentFormat === GLB_V1_CONTENT_FORMAT_JSON); - parseJSONChunk(glb, dataView, byteOffset, contentLength); - byteOffset += contentLength; - byteOffset += parseBINChunk(glb, dataView, byteOffset, glb.header.byteLength); - return byteOffset; -} + /** + * Sets whether smart default pivoting is enabled. + * + * When ````true````, we'll pivot by default about the 3D position of the mouse/touch pointer on an + * imaginary sphere that's centered at {@link Camera#eye} and sized to the {@link Scene} boundary. + * + * When ````false````, we'll pivot by default about {@link Camera#look}. + * + * Default is ````false````. + * + * @param {Boolean} enabled Set ````true```` to pivot by default about the selected point on the virtual sphere, or ````false```` to pivot by default about {@link Camera#look}. + */ + set smartPivot(enabled) { + this._configs.smartPivot = (enabled !== false); + } -function parseGLBV2(glb, dataView, byteOffset, options) { - assert$5(glb.header.byteLength > GLB_FILE_HEADER_SIZE + GLB_CHUNK_HEADER_SIZE); - parseGLBChunksSync(glb, dataView, byteOffset, options); - return byteOffset + glb.header.byteLength; -} + /** + * Gets whether smart default pivoting is enabled. + * + * When ````true````, we'll pivot by default about the 3D position of the mouse/touch pointer on an + * imaginary sphere that's centered at {@link Camera#eye} and sized to the {@link Scene} boundary. + * + * When ````false````, we'll pivot by default about {@link Camera#look}. + * + * Default is ````false````. + * + * @returns {Boolean} Returns ````true```` when pivoting by default about the selected point on the virtual sphere, or ````false```` when pivoting by default about {@link Camera#look}. + */ + get smartPivot() { + return this._configs.smartPivot; + } -function parseGLBChunksSync(glb, dataView, byteOffset, options) { - while (byteOffset + 8 <= glb.header.byteLength) { - const chunkLength = dataView.getUint32(byteOffset + 0, LE); - const chunkFormat = dataView.getUint32(byteOffset + 4, LE); - byteOffset += GLB_CHUNK_HEADER_SIZE; + /** + * Sets the double click time frame length in milliseconds. + * + * If two mouse click events occur within this time frame, it is considered a double click. + * + * Default is ````250```` + * + * @param {Number} value New double click time frame. + */ + set doubleClickTimeFrame(value) { + this._configs.doubleClickTimeFrame = (value !== undefined && value !== null) ? value : 250; + } - switch (chunkFormat) { - case GLB_CHUNK_TYPE_JSON: - parseJSONChunk(glb, dataView, byteOffset, chunkLength); - break; + /** + * Gets the double click time frame length in milliseconds. + * + * Default is ````250```` + * + * @param {Number} value Current double click time frame. + */ + get doubleClickTimeFrame() { + return this._configs.doubleClickTimeFrame; + } - case GLB_CHUNK_TYPE_BIN: - parseBINChunk(glb, dataView, byteOffset, chunkLength); - break; + /** + * Destroys this ````CameraControl````. + * @private + */ + destroy() { + this._destroyHandlers(); + this._destroyControllers(); + this._cameraUpdater.destroy(); + super.destroy(); + } - case GLB_CHUNK_TYPE_JSON_XVIZ_DEPRECATED: - if (!options.strict) { - parseJSONChunk(glb, dataView, byteOffset, chunkLength); + _destroyHandlers() { + for (let i = 0, len = this._handlers.length; i < len; i++) { + const handler = this._handlers[i]; + if (handler.destroy) { + handler.destroy(); + } } + } - break; - - case GLB_CHUNK_TYPE_BIX_XVIZ_DEPRECATED: - if (!options.strict) { - parseBINChunk(glb, dataView, byteOffset, chunkLength); + _destroyControllers() { + for (let i = 0, len = this._controllers.length; i < len; i++) { + const controller = this._controllers[i]; + if (controller.destroy) { + controller.destroy(); + } } - - break; } - - byteOffset += padToNBytes(chunkLength, 4); - } - - return byteOffset; } -function parseJSONChunk(glb, dataView, byteOffset, chunkLength) { - const jsonChunk = new Uint8Array(dataView.buffer, byteOffset, chunkLength); - const textDecoder = new TextDecoder('utf8'); - const jsonText = textDecoder.decode(jsonChunk); - glb.json = JSON.parse(jsonText); - return padToNBytes(chunkLength, 4); -} +/** + * @desc Metadata corresponding to an {@link Entity} that represents a model. + * + * An {@link Entity} represents a model when {@link Entity#isModel} is ````true```` + * + * A MetaModel corresponds to an {@link Entity} by having the same {@link MetaModel#id} as the {@link Entity#id}. + * + * A MetaModel is created by {@link MetaScene#createMetaModel} and belongs to a {@link MetaScene}. + * + * Each MetaModel is registered by {@link MetaModel#id} in {@link MetaScene#metaModels}. + * + * A {@link MetaModel} represents its object structure with a tree of {@link MetaObject}s, with {@link MetaModel#rootMetaObject} referencing the root {@link MetaObject}. + * + * @class MetaModel + */ +class MetaModel { -function parseBINChunk(glb, dataView, byteOffset, chunkLength) { - glb.header.hasBinChunk = true; - glb.binChunks.push({ - byteOffset, - byteLength: chunkLength, - arrayBuffer: dataView.buffer - }); - return padToNBytes(chunkLength, 4); -} + /** + * @private + */ + constructor(metaScene, id, projectId, revisionId, author, createdAt, creatingApplication, schema, propertySets, rootMetaObject) { -async function parseGLTF$1(gltf, arrayBufferOrString, byteOffset = 0, options, context) { - var _options$gltf, _options$gltf2, _options$gltf3, _options$gltf4; + /** + * Globally-unique ID. + * + * MetaModels are registered by ID in {@link MetaScene#metaModels}. + * + * When this MetaModel corresponds to an {@link Entity} then this ID will match the {@link Entity#id}. + * + * @property id + * @type {String|Number} + */ + this.id = id; - parseGLTFContainerSync(gltf, arrayBufferOrString, byteOffset, options); - normalizeGLTFV1(gltf, { - normalize: options === null || options === void 0 ? void 0 : (_options$gltf = options.gltf) === null || _options$gltf === void 0 ? void 0 : _options$gltf.normalize - }); - preprocessExtensions(gltf, options, context); - const promises = []; + /** + * The project ID + * @property projectId + * @type {String|Number} + */ + this.projectId = projectId; - if (options !== null && options !== void 0 && (_options$gltf2 = options.gltf) !== null && _options$gltf2 !== void 0 && _options$gltf2.loadBuffers && gltf.json.buffers) { - await loadBuffers(gltf, options, context); - } + /** + * The revision ID, if available. + * + * Will be undefined if not available. + * + * @property revisionId + * @type {String|Number} + */ + this.revisionId = revisionId; - if (options !== null && options !== void 0 && (_options$gltf3 = options.gltf) !== null && _options$gltf3 !== void 0 && _options$gltf3.loadImages) { - const promise = loadImages(gltf, options, context); - promises.push(promise); - } + /** + * The model author, if available. + * + * Will be undefined if not available. + * + * @property author + * @type {String} + */ + this.author = author; - const promise = decodeExtensions(gltf, options, context); - promises.push(promise); - await Promise.all(promises); - return options !== null && options !== void 0 && (_options$gltf4 = options.gltf) !== null && _options$gltf4 !== void 0 && _options$gltf4.postProcess ? postProcessGLTF(gltf, options) : gltf; -} + /** + * The date the model was created, if available. + * + * Will be undefined if not available. + * + * @property createdAt + * @type {String} + */ + this.createdAt = createdAt; -function parseGLTFContainerSync(gltf, data, byteOffset, options) { - if (options.uri) { - gltf.baseUri = options.uri; - } + /** + * The application that created the model, if available. + * + * Will be undefined if not available. + * + * @property creatingApplication + * @type {String} + */ + this.creatingApplication = creatingApplication; - if (data instanceof ArrayBuffer && !isGLB(data, byteOffset, options)) { - const textDecoder = new TextDecoder(); - data = textDecoder.decode(data); - } + /** + * The model schema version, if available. + * + * Will be undefined if not available. + * + * @property schema + * @type {String} + */ + this.schema = schema; - if (typeof data === 'string') { - gltf.json = parseJSON(data); - } else if (data instanceof ArrayBuffer) { - const glb = {}; - byteOffset = parseGLBSync(glb, data, byteOffset, options.glb); - assert$1(glb.type === 'glTF', "Invalid GLB magic string ".concat(glb.type)); - gltf._glb = glb; - gltf.json = glb.json; - } else { - assert$1(false, 'GLTF: must be ArrayBuffer or string'); - } + /** + * Metadata on the {@link Scene}. + * + * @property metaScene + * @type {MetaScene} + */ + this.metaScene = metaScene; - const buffers = gltf.json.buffers || []; - gltf.buffers = new Array(buffers.length).fill(null); + /** + * The {@link PropertySet}s in this MetaModel. + * + * @property propertySets + * @type {{String:PropertySet}} + */ + this.propertySets = propertySets; - if (gltf._glb && gltf._glb.header.hasBinChunk) { - const { - binChunks - } = gltf._glb; - gltf.buffers[0] = { - arrayBuffer: binChunks[0].arrayBuffer, - byteOffset: binChunks[0].byteOffset, - byteLength: binChunks[0].byteLength - }; - } + /** + * The root {@link MetaObject} in this MetaModel's composition structure hierarchy. + * + * @property rootMetaObject + * @type {MetaObject} + */ + this.rootMetaObject = rootMetaObject; + } - const images = gltf.json.images || []; - gltf.images = new Array(images.length).fill({}); -} + getJSON() { -async function loadBuffers(gltf, options, context) { - const buffers = gltf.json.buffers || []; + const metaObjects = []; - for (let i = 0; i < buffers.length; ++i) { - const buffer = buffers[i]; + function visit(metaObject) { + const metaObjectCfg = { + id: metaObject.id, + extId: metaObject.extId, + type: metaObject.type, + name: metaObject.name + }; + if (metaObject.parent) { + metaObjectCfg.parent = metaObject.parent.id; + } + metaObjects.push(metaObjectCfg); + const children = metaObject.children; + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + visit(children[i]); + } + } + } - if (buffer.uri) { - var _context$fetch, _response$arrayBuffer; + visit(this.rootMetaObject); - const { - fetch - } = context; - assert$1(fetch); - const uri = resolveUrl(buffer.uri, options); - const response = await (context === null || context === void 0 ? void 0 : (_context$fetch = context.fetch) === null || _context$fetch === void 0 ? void 0 : _context$fetch.call(context, uri)); - const arrayBuffer = await (response === null || response === void 0 ? void 0 : (_response$arrayBuffer = response.arrayBuffer) === null || _response$arrayBuffer === void 0 ? void 0 : _response$arrayBuffer.call(response)); - gltf.buffers[i] = { - arrayBuffer, - byteOffset: 0, - byteLength: arrayBuffer.byteLength - }; - delete buffer.uri; + const json = { + id: this.id, + projectId: this.projectId, + revisionId: this.revisionId, + metaObjects: metaObjects + }; + return json; } - } } -async function loadImages(gltf, options, context) { - const imageIndices = getReferencesImageIndices(gltf); - const images = gltf.json.images || []; - const promises = []; - - for (const imageIndex of imageIndices) { - promises.push(loadImage(gltf, images[imageIndex], imageIndex, options, context)); - } +/** + * @desc Metadata corresponding to an {@link Entity} that represents an object. + * + * An {@link Entity} represents an object when {@link Entity#isObject} is ````true```` + * + * A MetaObject corresponds to an {@link Entity} by having the same {@link MetaObject#id} as the {@link Entity#id}. + * + * A MetaObject is created within {@link MetaScene#createMetaModel} and belongs to a {@link MetaModel}. + * + * Each MetaObject is registered by {@link MetaObject#id} in {@link MetaScene#metaObjects}. + * + * A {@link MetaModel} represents its object structure with a tree of MetaObjects, with {@link MetaModel#rootMetaObject} referencing + * the root MetaObject. + * + * @class MetaObject + */ +class MetaObject { - return await Promise.all(promises); -} + /** + * @private + */ + constructor(metaModel, id, originalSystemId, name, type, propertySets, parent, children, external) { -function getReferencesImageIndices(gltf) { - const imageIndices = new Set(); - const textures = gltf.json.textures || []; + /** + * Model metadata. + * + * @property metaModel + * @type {MetaModel} + */ + this.metaModel = metaModel; - for (const texture of textures) { - if (texture.source !== undefined) { - imageIndices.add(texture.source); - } - } + /** + * Globally-unique ID. + * + * MetaObject instances are registered by this ID in {@link MetaScene#metaObjects}. + * + * @property id + * @type {String|Number} + */ + this.id = id; - return Array.from(imageIndices).sort(); -} + /** + * ID of the corresponding object within the originating system, if any. + * + * @type {String} + * @abstract + */ + this.originalSystemId = originalSystemId; -async function loadImage(gltf, image, index, options, context) { - const { - fetch, - parse - } = context; - let arrayBuffer; + /** + * Human-readable name. + * + * @property name + * @type {String} + */ + this.name = name; - if (image.uri) { - const uri = resolveUrl(image.uri, options); - const response = await fetch(uri); - arrayBuffer = await response.arrayBuffer(); - } + /** + * Type - often an IFC product type. + * + * @property type + * @type {String} + */ + this.type = type; - if (Number.isFinite(image.bufferView)) { - const array = getTypedArrayForBufferView(gltf.json, gltf.buffers, image.bufferView); - arrayBuffer = sliceArrayBuffer(array.buffer, array.byteOffset, array.byteLength); - } + /** + * Optional {@link PropertySet}s used by this MetaObject. + * + * @property propertySets + * @type {PropertySet[]} + */ + this.propertySets = propertySets; - assert$1(arrayBuffer, 'glTF image has no data'); - let parsedImage = await parse(arrayBuffer, [ImageLoader, BasisLoader], { - mimeType: image.mimeType, - basis: options.basis || { - format: selectSupportedBasisFormat() - } - }, context); + if (parent !== undefined && parent !== null) { - if (parsedImage && parsedImage[0]) { - parsedImage = { - compressed: true, - mipmaps: false, - width: parsedImage[0].width, - height: parsedImage[0].height, - data: parsedImage - }; - } + /** + * The parent MetaObject within the structure hierarchy. + * + * Undefined when this is the root of its structure. + * + * @property parent + * @type {MetaObject} + */ + this.parent = parent; + } - gltf.images = gltf.images || []; - gltf.images[index] = parsedImage; -} + if (children !== undefined && children !== null) { -const GLTFLoader = { - name: 'glTF', - id: 'gltf', - module: 'gltf', - version: VERSION$5, - extensions: ['gltf', 'glb'], - mimeTypes: ['model/gltf+json', 'model/gltf-binary'], - text: true, - binary: true, - tests: ['glTF'], - parse: parse$1, - options: { - gltf: { - normalize: true, - loadBuffers: true, - loadImages: true, - decompressMeshes: true, - postProcess: true - }, - log: console - }, - deprecatedOptions: { - fetchImages: 'gltf.loadImages', - createImages: 'gltf.loadImages', - decompress: 'gltf.decompressMeshes', - postProcess: 'gltf.postProcess', - gltf: { - decompress: 'gltf.decompressMeshes' - } - } -}; -async function parse$1(arrayBuffer, options = {}, context) { - options = { ...GLTFLoader.options, - ...options - }; - options.gltf = { ...GLTFLoader.options.gltf, - ...options.gltf - }; - const { - byteOffset = 0 - } = options; - const gltf = {}; - return await parseGLTF$1(gltf, arrayBuffer, byteOffset, options, context); -} + /** + * Child ObjectMeta instances within the structure hierarchy. + * + * Undefined when there are no children. + * + * @property children + * @type {Array} + */ + this.children = children; + } -/** - * @private - */ -class GLTFPerformanceModelLoader { + if (external !== undefined && external !== null) { - constructor(cfg) { + /** + * External application-specific metadata + * + * Undefined when there are is no external application-specific metadata. + * + * @property external + * @type {*} + */ + this.external = external; + } } - load(plugin, sceneModel, src, options, ok, error) { - options = options || {}; - loadGLTF(plugin, sceneModel, src, options, function () { - core.scheduleTask(function () { - sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events - sceneModel.fire("loaded", true, false); - }); - if (ok) { - ok(); - } - }, - function (msg) { - plugin.error(msg); - if (error) { - error(msg); - } - sceneModel.fire("error", msg); - }); - } + /** + * Gets the {@link MetaObject#id}s of the {@link MetaObject}s within the subtree. + * + * @returns {String[]} Array of {@link MetaObject#id}s. + */ + getObjectIDsInSubtree() { + const objectIds = []; - parse(plugin, sceneModel, gltf, options, ok, error) { - options = options || {}; - parseGLTF(plugin, gltf, "", options, sceneModel, function () { - sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events - sceneModel.fire("loaded", true, false); - if (ok) { - ok(); + function visit(metaObject) { + if (!metaObject) { + return; + } + objectIds.push(metaObject.id); + const children = metaObject.children; + if (children) { + for (var i = 0, len = children.length; i < len; i++) { + visit(children[i]); } - }); - } -} + } + } -function loadGLTF(plugin, sceneModel, src, options, ok, error) { - const spinner = plugin.viewer.scene.canvas.spinner; - spinner.processes++; - const isGLB = (src.split('.').pop() === "glb"); - if (isGLB) { - plugin.dataSource.getGLB(src, (arrayBuffer) => { // OK - options.basePath = getBasePath(src); - parseGLTF(plugin, arrayBuffer, src, options, sceneModel, ok); - spinner.processes--; - }, - (err) => { - spinner.processes--; - error(err); - }); - } else { - plugin.dataSource.getGLTF(src, (json) => { // OK - options.basePath = getBasePath(src); - parseGLTF(plugin, json, src, options, sceneModel, ok); - spinner.processes--; - }, - (err) => { - spinner.processes--; - error(err); - }); + visit(this); + return objectIds; } -} -function getBasePath(src) { - const i = src.lastIndexOf("/"); - return (i !== 0) ? src.substring(0, i + 1) : ""; -} -function parseGLTF(plugin, gltf, src, options, sceneModel, ok) { - const spinner = plugin.viewer.scene.canvas.spinner; - spinner.processes++; - const gl = sceneModel.scene.canvas.gl; - parse$3(gltf, GLTFLoader, { - baseUri: options.basePath, - gl - }).then((gltfData) => { - const ctx = { - src: src, - loadBuffer: options.loadBuffer, - basePath: options.basePath, - handlenode: options.handlenode, - gltfData: gltfData, - scene: sceneModel.scene, - plugin: plugin, - sceneModel: sceneModel, - //geometryCreated: {}, - numObjects: 0, - nodes: [], - nextId: 0 - }; - loadTextures(ctx); - loadMaterials(ctx); - loadDefaultScene(ctx); - sceneModel.finalize(); - spinner.processes--; - ok(); - }); -} + /** + * Iterates over the {@link MetaObject}s within the subtree. + * + * @param {Function} callback Callback fired at each {@link MetaObject}. + */ + withMetaObjectsInSubtree(callback) { -function loadTextures(ctx) { - const gltfData = ctx.gltfData; - const textures = gltfData.textures; - if (textures) { - for (let i = 0, len = textures.length; i < len; i++) { - loadTexture(ctx, textures[i]); + function visit(metaObject) { + if (!metaObject) { + return; + } + callback(metaObject); + const children = metaObject.children; + if (children) { + for (var i = 0, len = children.length; i < len; i++) { + visit(children[i]); + } + } } - } -} -function loadTexture(ctx, texture) { - if (!texture.source || !texture.source.image) { - return; + visit(this); } - const textureId = `texture-${ctx.nextId++}`; - ctx.sceneModel.createTexture({ - id: textureId, - image: texture.source.image, - flipY: !!texture.flipY, - // encoding: sRGBEncoding - }); - texture._textureId = textureId; -} -function loadMaterials(ctx) { - const gltfData = ctx.gltfData; - const materials = gltfData.materials; - if (materials) { - for (let i = 0, len = materials.length; i < len; i++) { - const material = materials[i]; - material._textureSetId = loadTextureSet(ctx, material); - material._attributes = loadMaterialAttributes(ctx, material); + /** + * Gets the {@link MetaObject#id}s of the {@link MetaObject}s within the subtree that have the given {@link MetaObject#type}s. + * + * @param {String[]} types {@link MetaObject#type} values. + * @returns {String[]} Array of {@link MetaObject#id}s. + */ + getObjectIDsInSubtreeByType(types) { + const mask = {}; + for (var i = 0, len = types.length; i < len; i++) { + mask[types[i]] = types[i]; } - } -} + const objectIds = []; -function loadTextureSet(ctx, material) { - const textureSetCfg = {}; - if (material.normalTexture) { - textureSetCfg.normalTextureId = material.normalTexture.texture._textureId; - } - if (material.occlusionTexture) { - textureSetCfg.occlusionTextureId = material.occlusionTexture.texture._textureId; - } - if (material.emissiveTexture) { - textureSetCfg.emissiveTextureId = material.emissiveTexture.texture._textureId; - } - // const alphaMode = material.alphaMode; - // switch (alphaMode) { - // case "NORMAL_OPAQUE": - // materialCfg.alphaMode = "opaque"; - // break; - // case "MASK": - // materialCfg.alphaMode = "mask"; - // break; - // case "BLEND": - // materialCfg.alphaMode = "blend"; - // break; - // default: - // } - // const alphaCutoff = material.alphaCutoff; - // if (alphaCutoff !== undefined) { - // materialCfg.alphaCutoff = alphaCutoff; - // } - const metallicPBR = material.pbrMetallicRoughness; - if (material.pbrMetallicRoughness) { - const pbrMetallicRoughness = material.pbrMetallicRoughness; - const baseColorTexture = pbrMetallicRoughness.baseColorTexture || pbrMetallicRoughness.colorTexture; - if (baseColorTexture) { - if (baseColorTexture.texture) { - textureSetCfg.colorTextureId = baseColorTexture.texture._textureId; - } else { - textureSetCfg.colorTextureId = ctx.gltfData.textures[baseColorTexture.index]._textureId; + function visit(metaObject) { + if (!metaObject) { + return; + } + if (mask[metaObject.type]) { + objectIds.push(metaObject.id); + } + const children = metaObject.children; + if (children) { + for (var i = 0, len = children.length; i < len; i++) { + visit(children[i]); + } } } - if (metallicPBR.metallicRoughnessTexture) { - textureSetCfg.metallicRoughnessTextureId = metallicPBR.metallicRoughnessTexture.texture._textureId; - } - } - if (textureSetCfg.normalTextureId !== undefined || - textureSetCfg.occlusionTextureId !== undefined || - textureSetCfg.emissiveTextureId !== undefined || - textureSetCfg.colorTextureId !== undefined || - textureSetCfg.metallicRoughnessTextureId !== undefined) { - textureSetCfg.id = `textureSet-${ctx.nextId++};`; - ctx.sceneModel.createTextureSet(textureSetCfg); - return textureSetCfg.id; + + visit(this); + return objectIds; } - return null; -} -function loadMaterialAttributes(ctx, material) { // Substitute RGBA for material, to use fast flat shading instead - const extensions = material.extensions; - const materialAttributes = { - color: new Float32Array([1, 1, 1, 1]), - opacity: 1, - metallic: 0, - roughness: 1 - }; - if (extensions) { - const specularPBR = extensions["KHR_materials_pbrSpecularGlossiness"]; - if (specularPBR) { - const diffuseFactor = specularPBR.diffuseFactor; - if (diffuseFactor !== null && diffuseFactor !== undefined) { - materialAttributes.color.set(diffuseFactor); - } - } - const common = extensions["KHR_materials_common"]; - if (common) { - const technique = common.technique; - const values = common.values || {}; - const blinn = technique === "BLINN"; - const phong = technique === "PHONG"; - const lambert = technique === "LAMBERT"; - const diffuse = values.diffuse; - if (diffuse && (blinn || phong || lambert)) { - if (!utils.isString(diffuse)) { - materialAttributes.color.set(diffuse); - } - } - const transparency = values.transparency; - if (transparency !== null && transparency !== undefined) { - materialAttributes.opacity = transparency; - } - const transparent = values.transparent; - if (transparent !== null && transparent !== undefined) { - materialAttributes.opacity = transparent; - } - } - } - const metallicPBR = material.pbrMetallicRoughness; - if (metallicPBR) { - const baseColorFactor = metallicPBR.baseColorFactor; - if (baseColorFactor) { - materialAttributes.color[0] = baseColorFactor[0]; - materialAttributes.color[1] = baseColorFactor[1]; - materialAttributes.color[2] = baseColorFactor[2]; - materialAttributes.opacity = baseColorFactor[3]; - } - const metallicFactor = metallicPBR.metallicFactor; - if (metallicFactor !== null && metallicFactor !== undefined) { - materialAttributes.metallic = metallicFactor; - } - const roughnessFactor = metallicPBR.roughnessFactor; - if (roughnessFactor !== null && roughnessFactor !== undefined) { - materialAttributes.roughness = roughnessFactor; + /** + * Returns properties of this MeteObject as JSON. + * + * @returns {{id: (String|Number), type: String, name: String, parent: (String|Number|Undefined)}} + */ + getJSON() { + var json = { + id: this.id, + type: this.type, + name: this.name + }; + if (this.parent) { + json.parent = this.parent.id; } - } - return materialAttributes; -} - -function loadDefaultScene(ctx) { - const gltfData = ctx.gltfData; - const scene = gltfData.scene || gltfData.scenes[0]; - if (!scene) { - error(ctx, "glTF has no default scene"); - return; - } - loadScene(ctx, scene); -} - -function loadScene(ctx, scene) { - const nodes = scene.nodes; - if (!nodes) { - return; - } - for (let i = 0, len = nodes.length; i < len; i++) { - const node = nodes[i]; - countMeshUsage(ctx, node); - } - for (let i = 0, len = nodes.length; i < len; i++) { - const node = nodes[i]; - loadNode(ctx, node, null); + return json; } } -function countMeshUsage(ctx, node) { - const mesh = node.mesh; - if (mesh) { - mesh.instances = mesh.instances ? mesh.instances + 1 : 1; - } - if (node.children) { - const children = node.children; - for (let i = 0, len = children.length; i < len; i++) { - const childNode = children[i]; - if (!childNode) { - error(ctx, "Node not found: " + i); - continue; - } - countMeshUsage(ctx, childNode); - } - } -} +/** + * @desc A property within a {@link PropertySet}. + * + * @class Property + */ +class Property { -function loadNode(ctx, node, matrix) { - ctx.gltfData; - let localMatrix; - if (node.matrix) { - localMatrix = node.matrix; - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, math.mat4()); - } else { - matrix = localMatrix; - } - } - if (node.translation) { - localMatrix = math.translationMat4v(node.translation); - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, math.mat4()); - } else { - matrix = localMatrix; - } - } - if (node.rotation) { - localMatrix = math.quaternionToMat4(node.rotation); - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, math.mat4()); - } else { - matrix = localMatrix; - } - } - if (node.scale) { - localMatrix = math.scalingMat4v(node.scale); - if (matrix) { - matrix = math.mulMat4(matrix, localMatrix, math.mat4()); - } else { - matrix = localMatrix; - } - } - if (node.mesh) { - const mesh = node.mesh; - let createEntity; - if (ctx.handlenode) { - const actions = {}; - if (!ctx.handlenode(ctx.sceneModel.id, node, actions)) { - return; - } - if (actions.createEntity) { - createEntity = actions.createEntity; - } - } - const sceneModel = ctx.sceneModel; - const worldMatrix = matrix ? matrix.slice() : math.identityMat4(); - const numPrimitives = mesh.primitives.length; + /** + * @private + */ + constructor(name, value, type, valueType, description) { - if (numPrimitives > 0) { + /** + * The name of this property. + * + * @property name + * @type {String} + */ + this.name = name; - const meshIds = []; + /** + * The type of this property. + * + * @property type + * @type {Number|String} + */ + this.type = type; - for (let i = 0; i < numPrimitives; i++) { + /** + * The value of this property. + * + * @property value + * @type {*} + */ + this.value = value; - const primitive = mesh.primitives[i]; - if (primitive.mode < 4) { - continue; - } + /** + * The type of this property's value. + * + * @property valueType + * @type {Number|String} + */ + this.valueType = valueType; - const meshCfg = { - id: sceneModel.id + "." + ctx.numObjects++ - }; + /** + * Informative text to explain the property. + * + * @property name + * @type {String} + */ + this.description = description; + } +} - switch (primitive.mode) { - case 0: // POINTS - meshCfg.primitive = "points"; - break; - case 1: // LINES - meshCfg.primitive = "lines"; - break; - case 2: // LINE_LOOP - meshCfg.primitive = "lines"; - break; - case 3: // LINE_STRIP - meshCfg.primitive = "lines"; - break; - case 4: // TRIANGLES - meshCfg.primitive = "triangles"; - break; - case 5: // TRIANGLE_STRIP - meshCfg.primitive = "triangles"; - break; - case 6: // TRIANGLE_FAN - meshCfg.primitive = "triangles"; - break; - default: - meshCfg.primitive = "triangles"; - } +/** + * @desc A set of properties associated with one or more {@link MetaObject}s. + * + * A PropertySet is created within {@link MetaScene#createMetaModel} and belongs to a {@link MetaModel}. + * + * Each PropertySet is registered by {@link PropertySet#id} in {@link MetaScene#propertySets} and {@link MetaModel#propertySets}. + * + * @class PropertySet + */ +class PropertySet { - const POSITION = primitive.attributes.POSITION; - if (!POSITION) { - continue; - } - meshCfg.localPositions = POSITION.value; - meshCfg.positions = new Float64Array(meshCfg.localPositions.length); + /** + * @private + */ + constructor(id, originalSystemId, name, type, properties) { - if (primitive.attributes.NORMAL) { - meshCfg.normals = primitive.attributes.NORMAL.value; - } + /** + * Globally-unique ID for this PropertySet. + * + * PropertySet instances are registered by this ID in {@link MetaScene#propertySets} and {@link MetaModel#propertySets}. + * + * @property id + * @type {String} + */ + this.id = id; - if (primitive.attributes.TEXCOORD_0) { - meshCfg.uv = primitive.attributes.TEXCOORD_0.value; - } + /** + * ID of the corresponding object within the originating system, if any. + * + * @type {String} + * @abstract + */ + this.originalSystemId = originalSystemId; - if (primitive.indices) { - meshCfg.indices = primitive.indices.value; - } + /** + * Human-readable name of this PropertySet. + * + * @property name + * @type {String} + */ + this.name = name; - math.transformPositions3(worldMatrix, meshCfg.localPositions, meshCfg.positions); - const origin = math.vec3(); - const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy - if (rtcNeeded) { - meshCfg.origin = origin; - } + /** + * Type of this PropertySet. + * + * @property type + * @type {String} + */ + this.type = type; - const material = primitive.material; - if (material) { - meshCfg.textureSetId = material._textureSetId; - meshCfg.color = material._attributes.color; - meshCfg.opacity = material._attributes.opacity; - meshCfg.metallic = material._attributes.metallic; - meshCfg.roughness = material._attributes.roughness; - } else { - meshCfg.color = new Float32Array([1.0, 1.0, 1.0]); - meshCfg.opacity = 1.0; - } - if (createEntity) { - if (createEntity.colorize) { - meshCfg.color = createEntity.colorize; - } - if (createEntity.opacity !== undefined && createEntity.opacity !== null) { - meshCfg.opacity = createEntity.opacity; - } - } + /** + * Properties within this PropertySet. + * + * @property properties + * @type {Property[]} + */ + this.properties = []; - sceneModel.createMesh(meshCfg); - meshIds.push(meshCfg.id); - } - if (createEntity) { - sceneModel.createEntity(utils.apply(createEntity, { - meshIds: meshIds - })); - } else { - sceneModel.createEntity({ - meshIds: meshIds - }); + if (properties) { + for (let i = 0, len = properties.length; i < len; i++) { + const property = properties[i]; + this.properties.push(new Property(property.name, property.value, property.type, property.valueType, property.description)); } } } - - if (node.children) { - const children = node.children; - for (let i = 0, len = children.length; i < len; i++) { - const childNode = children[i]; - loadNode(ctx, childNode, matrix); - } - } -} - -function error(ctx, msg) { - ctx.plugin.error(msg); } /** - * @desc Default initial properties for {@link Entity}s loaded from models accompanied by metadata. - * - * When loading a model, plugins such as {@link XKTLoaderPlugin} create - * a tree of {@link Entity}s that represent the model. These loaders can optionally load metadata, to create - * a {@link MetaModel} corresponding to the root {@link Entity}, with a {@link MetaObject} corresponding to each - * object {@link Entity} within the tree. + * @desc Metadata corresponding to a {@link Scene}. * - * @type {{String:Object}} + * * Located in {@link Viewer#metaScene}. + * * Contains {@link MetaModel}s and {@link MetaObject}s. + * * [Scene graph example with metadata](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_SceneGraph_metadata) */ -const IFCObjectDefaults = { - - IfcOpeningElement: { - pickable: false, - visible: false - }, +class MetaScene { - IfcSpace: { - colorize: [0.137255, 0.403922, 0.870588], - pickable: false, - visible: false, - opacity: 0.4 - }, + /** + * @private + */ + constructor(viewer, scene) { - IfcWindow: { - colorize: [0.137255, 0.403922, 0.870588], - opacity: 0.3 - }, + /** + * The {@link Viewer}. + * @property viewer + * @type {Viewer} + */ + this.viewer = viewer; - IfcPlate: { - colorize: [0.8470588235, 0.427450980392, 0, 0.5], - opacity: 0.3 - }, + /** + * The {@link Scene}. + * @property scene + * @type {Scene} + */ + this.scene = scene; - DEFAULT: { - } -}; + /** + * The {@link MetaModel}s belonging to this MetaScene, each mapped to its {@link MetaModel#modelId}. + * + * @type {{String:MetaModel}} + */ + this.metaModels = {}; -/** - * {@link Viewer} plugin that loads models from [glTF](https://www.khronos.org/gltf/). - * - * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. - * * Creates an {@link Entity} for each object within the model, which is indicated by each glTF ````node```` that has a ````name```` attribute. Those Entities will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. - * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. - * - * ## Metadata - * - * GLTFLoaderPlugin can also load an accompanying JSON metadata file with each model, which creates a {@link MetaModel} corresponding - * to the model {@link Entity} and a {@link MetaObject} corresponding to each object {@link Entity}. - * - * Each {@link MetaObject} has a {@link MetaObject#type}, which indicates the classification of its corresponding {@link Entity}. When loading - * metadata, we can also provide GLTFLoaderPlugin with a custom lookup table of initial values to set on the properties of each type of {@link Entity}. By default, GLTFLoaderPlugin - * uses its own map of default colors and visibilities for IFC element types. - * - * ## Quality Setting - * - * By default, GLTFLoaderPlugin will load a high-performance scene representation that's optimized for low memory usage and - * optimal rendering. The high-performance representation renders large numbers of objects efficiently, using geometry - * batching and instancing, with simple Lambertian shading that ignores any textures and realistic materials in the glTF. - * - * Specifying ````performance:false```` to {@link GLTFLoaderPlugin#load} will internally load a heavier scene - * representation comprised of {@link Node}, {@link Mesh}, {@link Geometry}, {@link Material} and {@link Texture} components, - * that will exactly preserve the materials specified in the glTF. Use this when you want to load a model for a realistic preview, - * maybe using PBR etc. - * - * We tend to use the default ````performance:true```` setting for CAD and BIM models, where structure is more important that - * surface appearance. - * - * Publically, GLTFLoaderPlugin creates the same {@link Entity}s for both levels of performance. Privately, however, it implements - * {@link Entity}s using two different sets of concrete subtypes, for its two different internally-managed scene representations. - * - * ## Usage - * - * In the example below we'll load the Schependomlaan model from a [glTF file](http://xeokit.github.io/xeokit-sdk/examples/models/gltf/schependomlaan/), along - * with an accompanying JSON [IFC metadata file](http://xeokit.github.io/xeokit-sdk/examples/metaModels/schependomlaan/). - * - * This will create a bunch of {@link Entity}s that represents the model and its objects, along with a {@link MetaModel} and {@link MetaObject}s - * that hold their metadata. - * - * Since this model contains IFC types, the GLTFLoaderPlugin will set the initial colors of object {@link Entity}s according - * to the standard IFC element colors in the GLTFModel's current map. Override that with your own map via property {@link GLTFLoaderPlugin#objectDefaults}. - * - * Read more about this example in the user guide on [Viewing BIM Models Offline](https://www.notion.so/xeokit/Viewing-an-IFC-Model-with-xeokit-c373e48bc4094ff5b6e5c5700ff580ee). - * - * We're leaving ````performance: true```` since our model has many objects and we're not interested in realistic rendering. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_glTF_OTCConferenceCenter)] - * - * ````javascript - * import {Viewer, GLTFLoaderPlugin} from "xeokit-sdk.es.js"; - * - * //------------------------------------------------------------------------------------------------------------------ - * // 1. Create a Viewer, - * // 2. Arrange the camera, - * // 3. Tweak the selection material (tone it down a bit) - * //------------------------------------------------------------------------------------------------------------------ - * - * // 1 - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * // 2 - * viewer.camera.orbitPitch(20); - * viewer.camera.orbitYaw(-45); - * - * // 3 - * viewer.scene.selectedMaterial.fillAlpha = 0.1; - * - * //------------------------------------------------------------------------------------------------------------------ - * // 1. Create a glTF loader plugin, - * // 2. Load a glTF building model and JSON IFC metadata - * // 3. Emphasis the edges to make it look nice - * //------------------------------------------------------------------------------------------------------------------ - * - * // 1 - * const gltfLoader = new GLTFLoaderPlugin(viewer); - * - * // 2 - * var model = gltfLoader.load({ // Returns an Entity that represents the model - * id: "myModel", - * src: "./models/gltf/OTCConferenceCenter/scene.gltf", - * metaModelSrc: "./models/gltf/OTCConferenceCenter/metaModel.json", // Creates a MetaModel (see below) - * edges: true, - * performance: true // Load high-performance scene representation (default is false) - * }); - * - * model.on("loaded", () => { - * - * //-------------------------------------------------------------------------------------------------------------- - * // 1. Find metadata on the third storey - * // 2. Select all the objects in the building's third storey - * // 3. Fit the camera to all the objects on the third storey - * //-------------------------------------------------------------------------------------------------------------- - * - * // 1 - * const metaModel = viewer.metaScene.metaModels["myModel"]; // MetaModel with ID "myModel" - * const metaObject - * = viewer.metaScene.metaObjects["0u4wgLe6n0ABVaiXyikbkA"]; // MetaObject with ID "0u4wgLe6n0ABVaiXyikbkA" - * - * const name = metaObject.name; // "01 eerste verdieping" - * const type = metaObject.type; // "IfcBuildingStorey" - * const parent = metaObject.parent; // MetaObject with type "IfcBuilding" - * const children = metaObject.children; // Array of child MetaObjects - * const objectId = metaObject.id; // "0u4wgLe6n0ABVaiXyikbkA" - * const objectIds = viewer.metaScene.getObjectIDsInSubtree(objectId); // IDs of leaf sub-objects - * const aabb = viewer.scene.getAABB(objectIds); // Axis-aligned boundary of the leaf sub-objects - * - * // 2 - * viewer.scene.setObjectsSelected(objectIds, true); - * - * // 3 - * viewer.cameraFlight.flyTo(aabb); - * }); - * - * // Find the model Entity by ID - * model = viewer.scene.models["myModel"]; - * - * // Destroy the model - * model.destroy(); - * ```` - * - * ## Transforming - * - * We have the option to rotate, scale and translate each *````.glTF````* model as we load it. - * - * This lets us load multiple models, or even multiple copies of the same model, and position them apart from each other. - * - * In the example below, we'll scale our model to half its size, rotate it 90 degrees about its local X-axis, then - * translate it 100 units along its X axis. - * - * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_glTF_Duplex_transform)] - * - * ````javascript - * const model = gltfLoader.load({ - * src: "./models/gltf/Duplex/scene.gltf", - * metaModelSrc: "./models/gltf/Duplex/Duplex.json", - * rotation: [90,0,0], - * scale: [0.5, 0.5, 0.5], - * position: [100, 0, 0] - * }); - * ```` - * - * ## Including and excluding IFC types - * - * We can also load only those objects that have the specified IFC types. In the example below, we'll load only the - * objects that represent walls. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_glTF_includeTypes_PlanView)] - * - * ````javascript - * const model = gltfLoader.load({ - * id: "myModel", - * src: "./models/gltf/OTCConferenceCenter/scene.gltf", - * metaModelSrc: "./models/gltf/OTCConferenceCenter/metaModel.json", - * includeTypes: ["IfcWallStandardCase"] - * }); - * ```` - * - * We can also load only those objects that **don't** have the specified IFC types. In the example below, we'll load only the - * objects that do not represent empty space. - * - * ````javascript - * const model = gltfLoader.load({ - * id: "myModel", - * src: "./models/gltf/OTCConferenceCenter/scene.gltf", - * metaModelSrc: "./models/gltf/OTCConferenceCenter/metaModel.json", - * excludeTypes: ["IfcSpace"] - * }); - * ```` - * @class GLTFLoaderPlugin - */ -class GLTFLoaderPlugin extends Plugin { + /** + * The {@link PropertySet}s belonging to this MetaScene, each mapped to its {@link PropertySet#id}. + * + * @type {{String:PropertySet}} + */ + this.propertySets = {}; - /** - * @constructor - * - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="GLTFLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Object} [cfg.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. - * @param {Object} [cfg.dataSource] A custom data source through which the GLTFLoaderPlugin can load metadata, glTF and binary attachments. Defaults to an instance of {@link GLTFDefaultDataSource}, which loads over HTTP. - */ - constructor(viewer, cfg = {}) { + /** + * The {@link MetaObject}s belonging to this MetaScene, each mapped to its {@link MetaObject#id}. + * + * @type {{String:MetaObject}} + */ + this.metaObjects = {}; - super("GLTFLoader", viewer, cfg); + /** + * The {@link MetaObject}s belonging to this MetaScene, each mapped to its {@link MetaObject#type}. + * + * @type {{String:MetaObject}} + */ + this.metaObjectsByType = {}; /** + * Tracks number of MetaObjects of each type. * @private */ - this._sceneGraphLoader = new GLTFSceneGraphLoader(this, cfg); + this._typeCounts = {}; /** + * Subscriptions to events sent with {@link fire}. * @private */ - this._performanceModelLoader = new GLTFPerformanceModelLoader(this, cfg); - - this.dataSource = cfg.dataSource; - this.objectDefaults = cfg.objectDefaults; + this._eventSubs = {}; } /** - * Sets a custom data source through which the GLTFLoaderPlugin can load metadata, glTF and binary attachments. - * - * Default value is {@link GLTFDefaultDataSource}, which loads via an XMLHttpRequest. + * Subscribes to an event fired at this Viewer. * - * @type {Object} + * @param {String} event The event + * @param {Function} callback Callback fired on the event */ - set dataSource(value) { - this._dataSource = value || new GLTFDefaultDataSource(); + on(event, callback) { + let subs = this._eventSubs[event]; + if (!subs) { + subs = []; + this._eventSubs[event] = subs; + } + subs.push(callback); } /** - * Gets the custom data source through which the GLTFLoaderPlugin can load metadata, glTF and binary attachments. - * - * Default value is {@link GLTFDefaultDataSource}, which loads via an XMLHttpRequest. + * Fires an event at this Viewer. * - * @type {Object} + * @param {String} event Event name + * @param {Object} value Event parameters */ - get dataSource() { - return this._dataSource; + fire(event, value) { + const subs = this._eventSubs[event]; + if (subs) { + for (let i = 0, len = subs.length; i < len; i++) { + subs[i](value); + } + } } /** - * Sets map of initial default states for each loaded {@link Entity} that represents an object. - * - * Default value is {@link IFCObjectDefaults}. - * - * @type {{String: Object}} + * Unsubscribes from an event fired at this Viewer. + * @param event */ - set objectDefaults(value) { - this._objectDefaults = value || IFCObjectDefaults; + off(event) { // TODO + } /** - * Gets map of initial default states for each loaded {@link Entity} that represents an object. + * Creates a {@link MetaModel} in this MetaScene. * - * Default value is {@link IFCObjectDefaults}. + * The MetaModel will contain a hierarchy of {@link MetaObject}s, created from the + * meta objects in ````metaModelData````. * - * @type {{String: Object}} - */ - get objectDefaults() { - return this._objectDefaults; - } - - /** - * Loads a glTF model from a file into this GLTFLoaderPlugin's {@link Viewer}. + * The meta object hierarchy in ````metaModelData```` is expected to be non-cyclic, with a single root. If the meta + * objects are cyclic, then this method will log an error and attempt to recover by creating a dummy root MetaObject + * of type "Model" and connecting all other MetaObjects as its direct children. If the meta objects contain multiple + * roots, then this method similarly attempts to recover by creating a dummy root MetaObject of type "Model" and + * connecting all the root MetaObjects as its children. * - * @param {*} params Loading parameters. - * @param {String} [params.id] ID to assign to the root {@link Entity#id}, unique among all components in the Viewer's {@link Scene}, generated automatically by default. - * @param {String} [params.src] Path to a glTF file, as an alternative to the ````gltf```` parameter. - * @param {*} [params.gltf] glTF JSON, as an alternative to the ````src```` parameter. - * @param {String} [params.metaModelSrc] Path to an optional metadata file, as an alternative to the ````metaModelData```` parameter. - * @param {*} [params.metaModelData] JSON model metadata, as an alternative to the ````metaModelSrc```` parameter. - * @param {{String:Object}} [params.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. - * @param {String[]} [params.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. - * @param {String[]} [params.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. - * @param {Boolean} [params.edges=false] Whether or not xeokit renders the model with edges emphasized. - * @param {Number[]} [params.origin=[0,0,0]] The double-precision World-space origin of the model's coordinates. - * @param {Number[]} [params.position=[0,0,0]] The single-precision position, relative to ````origin````. - * @param {Number[]} [params.scale=[1,1,1]] The model's scale. - * @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. Relative to ````origin````. - * @param {Boolean} [params.saoEnabled=true] Indicates if Scalable Ambient Obscurance (SAO) is enabled for the model. SAO is configured by the Scene's {@link SAO} component. Only works when {@link SAO#enabled} is also ````true```` - * @param {Boolean} [params.pbrEnabled=true] Indicates if physically-based rendering (PBR) is enabled for the model. Overrides ````colorTextureEnabled````. Only works when {@link Scene#pbrEnabled} is also ````true````. - * @param {Boolean} [params.colorTextureEnabled=true] Indicates if base color texture rendering is enabled for the model. Overridden by ````pbrEnabled````. Only works when {@link Scene#colorTextureEnabled} is also ````true````. - * @param {Boolean} [params.backfaces=false] When true, allows visible backfaces, wherever specified in the glTF. When false, ignores backfaces. - * @param {Number} [params.edgeThreshold=10] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. - * @param {Boolean} [params.performance=true] Set ````false```` to load all the materials and textures provided by the glTF file, otherwise leave ````true```` to load the default high-performance representation optimized for low memory usage and efficient rendering. - * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} + * @param {String} modelId ID for the new {@link MetaModel}, which will have {@link MetaModel#id} set to this value. + * @param {Object} metaModelData Data for the {@link MetaModel}. + * @param {Object} [options] Options for creating the {@link MetaModel}. + * @param {Object} [options.includeTypes] When provided, only create {@link MetaObject}s with types in this list. + * @param {Object} [options.excludeTypes] When provided, never create {@link MetaObject}s with types in this list. + * @param {Boolean} [options.globalizeObjectIds=false] Whether to globalize each {@link MetaObject#id}. Set this ````true```` when you need to load multiple instances of the same meta model, to avoid ID clashes between the meta objects in the different instances. + * @returns {MetaModel} The new MetaModel. */ - load(params = {}) { - - if (params.id && this.viewer.scene.components[params.id]) { - this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); - delete params.id; - } - - const performance = params.performance !== false; - - const sceneModel = performance - - // VBOSceneModel provides performance-oriented scene representation - // converting glTF materials to simple flat-shading without textures - - ? new VBOSceneModel(this.viewer.scene, utils.apply(params, { - isModel: true - })) + createMetaModel(modelId, metaModelData, options = {}) { - // Scene Node graph supports original glTF materials + const projectId = metaModelData.projectId || "none"; + const revisionId = metaModelData.revisionId || "none"; + const newPropertySets = metaModelData.propertySets || []; + const newObjects = metaModelData.metaObjects || []; + const author = metaModelData.author; + const createdAt = metaModelData.createdAt; + const creatingApplication = metaModelData.creatingApplication; + const schema = metaModelData.schema; + // if (options.excludeTypes) { + // excludeTypes = {}; + // for (let i = 0, len = options.excludeTypes.length; i < len; i++) { + // includeTypes[options.excludeTypes[i]] = true; + // } + // } - : new Node$1(this.viewer.scene, utils.apply(params, { - isModel: true - })); + const metaModel = new MetaModel(this, modelId, projectId, revisionId, author, createdAt, creatingApplication, schema, [], null); - const modelId = sceneModel.id; // In case ID was auto-generated + this.metaModels[modelId] = metaModel; - if (!params.src && !params.gltf) { - this.error("load() param expected: src or gltf"); - return sceneModel; // Return new empty model + for (let i = 0, len = newPropertySets.length; i < len; i++) { + const propertySetCfg = newPropertySets[i]; + const propertySetId = propertySetCfg.id; + const propertySet = new PropertySet(propertySetId, propertySetCfg.originalSystemId, propertySetCfg.name, propertySetCfg.type, propertySetCfg.properties); + metaModel.propertySets[propertySetId] = propertySet; + this.propertySets[propertySetId] = propertySet; } - const loader = performance ? this._performanceModelLoader : this._sceneGraphLoader; - - if (params.metaModelSrc || params.metaModelData) { - - const objectDefaults = params.objectDefaults || this._objectDefaults || IFCObjectDefaults; + const rootMetaObjects = []; - const processMetaModelData = (metaModelData) => { + for (let i = 0, len = newObjects.length; i < len; i++) { + const newObject = newObjects[i]; + if (newObject.parent === undefined || newObject.parent === null) { + rootMetaObjects.push(newObject); + } + } - this.viewer.metaScene.createMetaModel(modelId, metaModelData, { - includeTypes: params.includeTypes, - excludeTypes: params.excludeTypes - }); + if (rootMetaObjects.length === 0) { + this.scene.error("Cyclic containment hierarchy found in metamodel - will flatten the hierarchy and insert fake 'Model' root"); + const fakeRoot = { + "id": modelId + ".fakeRoot", + "name": modelId, + "type": "Model", + "parent": null + }; + for (let i = 0, len = newObjects.length; i < len; i++) { + newObjects[i].parent = fakeRoot.id; + } + newObjects.push(fakeRoot); + } - this.viewer.scene.canvas.spinner.processes--; + if (rootMetaObjects.length > 1) { + this.scene.error("Multiple containment hierarchy root found in metamodel - will insert fake 'Model' root"); + const fakeRoot = { + "id": modelId + ".fakeRoot", + "name": modelId, + "type": "Model", + "parent": null + }; + newObjects.push(fakeRoot); + for (let i = 0, len = rootMetaObjects.length; i < len; i++) { + rootMetaObjects[i].parent = fakeRoot.id; + } + } - let includeTypes; - if (params.includeTypes) { - includeTypes = {}; - for (let i = 0, len = params.includeTypes.length; i < len; i++) { - includeTypes[params.includeTypes[i]] = true; - } - } - if (params.excludeTypes) { - if (!includeTypes) { - includeTypes = {}; - } - for (let i = 0, len = params.excludeTypes.length; i < len; i++) { - includeTypes[params.excludeTypes[i]] = true; + for (let i = 0, len = newObjects.length; i < len; i++) { + const newObject = newObjects[i]; + const type = newObject.type; + const objectId = options.globalizeObjectIds ? math.globalizeObjectId(modelId, newObject.id) : newObject.id; + const originalSystemId = newObject.id; + const name = newObject.name; + const propertySets = []; + if (newObject.propertySetIds && newObject.propertySetIds.length > 0) { + for (let j = 0, lenj = newObject.propertySetIds.length; j < lenj; j++) { + const propertySetId = newObject.propertySetIds[j]; + const propertySet = metaModel.propertySets[propertySetId]; + if (propertySet) { + propertySets.push(propertySet); } } + } + const parent = null; + const children = null; + const external = newObject.external; + const metaObject = new MetaObject(metaModel, objectId, originalSystemId, name, type, propertySets, parent, children, external); + this.metaObjects[objectId] = metaObject; + (this.metaObjectsByType[type] || (this.metaObjectsByType[type] = {}))[objectId] = metaObject; + if (this._typeCounts[type] === undefined) { + this._typeCounts[type] = 1; + } else { + this._typeCounts[type]++; + } + } - params.readableGeometry = false; - - params.handleGLTFNode = (modelId, glTFNode, actions) => { - - const name = glTFNode.name; - - if (!name) { - return true; // Continue descending this node subtree - } - - const nodeId = name; - const metaObject = this.viewer.metaScene.metaObjects[nodeId]; - const type = (metaObject ? metaObject.type : "DEFAULT") || "DEFAULT"; - - actions.createEntity = { - id: nodeId, - isObject: true // Registers the Entity in Scene#objects - }; - - const props = objectDefaults[type]; - - if (props) { // Set Entity's initial rendering state for recognized type - - if (props.visible === false) { - actions.createEntity.visible = false; - } - - if (props.colorize) { - actions.createEntity.colorize = props.colorize; - } - - if (props.pickable === false) { - actions.createEntity.pickable = false; - } - - if (props.opacity !== undefined && props.opacity !== null) { - actions.createEntity.opacity = props.opacity; - } - } - - return true; // Continue descending this glTF node subtree - }; - - if (params.src) { - loader.load(this, sceneModel, params.src, params); - } else { - loader.parse(this, sceneModel, params.gltf, params); + for (let i = 0, len = newObjects.length; i < len; i++) { + const newObject = newObjects[i]; + const objectId = options.globalizeObjectIds ? math.globalizeObjectId(modelId, newObject.id) : newObject.id; + const metaObject = this.metaObjects[objectId]; + if (!metaObject) { + continue; + } + if (newObject.parent === undefined || newObject.parent === null) { + metaModel.rootMetaObject = metaObject; + } else if (newObject.parent) { + const parentId = options.globalizeObjectIds ? math.globalizeObjectId(modelId, newObject.parent) : newObject.parent; + let parentMetaObject = this.metaObjects[parentId]; + if (parentMetaObject) { + metaObject.parent = parentMetaObject; + parentMetaObject.children = parentMetaObject.children || []; + parentMetaObject.children.push(metaObject); } - }; - - if (params.metaModelSrc) { - - const metaModelSrc = params.metaModelSrc; - - this.viewer.scene.canvas.spinner.processes++; - - this._dataSource.getMetaModel(metaModelSrc, (metaModelData) => { - - this.viewer.scene.canvas.spinner.processes--; - - processMetaModelData(metaModelData); - - }, (errMsg) => { - this.error(`load(): Failed to load model metadata for model '${modelId} from '${metaModelSrc}' - ${errMsg}`); - this.viewer.scene.canvas.spinner.processes--; - }); - - } else if (params.metaModelData) { - - processMetaModelData(params.metaModelData); } + } - } else { - - params.handleGLTFNode = (modelId, glTFNode, actions) => { + this.fire("metaModelCreated", modelId); + return metaModel; + } - const name = glTFNode.name; + /** + * Removes a {@link MetaModel} from this MetaScene. + * + * Fires a "metaModelDestroyed" event with the value of the {@link MetaModel#id}. + * + * @param {String} id ID of the target {@link MetaModel}. + */ + destroyMetaModel(id) { + const metaModel = this.metaModels[id]; + if (!metaModel) { + return; + } + this._removeMetaModel(metaModel); + this.fire("metaModelDestroyed", id); + } - if (!name) { - return true; // Continue descending this node subtree + _removeMetaModel(metaModel) { + const metaObjects = this.metaObjects; + const metaObjectsByType = this.metaObjectsByType; + let visit = (metaObject) => { + delete metaObjects[metaObject.id]; + const types = metaObjectsByType[metaObject.type]; + if (types && types[metaObject.id]) { + delete types[metaObject.id]; + if (--this._typeCounts[metaObject.type] === 0) { + delete this._typeCounts[metaObject.type]; + delete metaObjectsByType[metaObject.type]; } - - const id = name; - - actions.createEntity = { // Create an Entity for this glTF scene node - id: id, - isObject: true // Registers the Entity in Scene#objects - }; - - return true; // Continue descending this glTF node subtree - }; - - if (params.src) { - loader.load(this, sceneModel, params.src, params); - } else { - loader.parse(this, sceneModel, params.gltf, params); + } + const children = metaObject.children; + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + const childMetaObject = children[i]; + visit(childMetaObject); + } + } + }; + visit(metaModel.rootMetaObject); + for (let propertySetId in metaModel.propertySets) { + if (metaModel.propertySets.hasOwnProperty(propertySetId)) { + delete this.propertySets[propertySetId]; } } - - sceneModel.once("destroyed", () => { - this.viewer.metaScene.destroyMetaModel(modelId); - }); - - return sceneModel; + delete this.metaModels[metaModel.id]; } /** - * Destroys this GLTFLoaderPlugin. + * Gets the {@link MetaObject#id}s of the {@link MetaObject}s that have the given {@link MetaObject#type}. + * + * @param {String} type The type. + * @returns {String[]} Array of {@link MetaObject#id}s. */ - destroy() { - super.destroy(); + getObjectIDsByType(type) { + const metaObjects = this.metaObjectsByType[type]; + return metaObjects ? Object.keys(metaObjects) : []; } -} -/** - * @private - */ -function CubeTextureCanvas(viewer, cfg = {}) { + /** + * Gets the {@link MetaObject#id}s of the {@link MetaObject}s within the given subtree. + * + * @param {String} id ID of the root {@link MetaObject} of the given subtree. + * @param {String[]} [includeTypes] Optional list of types to include. + * @param {String[]} [excludeTypes] Optional list of types to exclude. + * @returns {String[]} Array of {@link MetaObject#id}s. + */ + getObjectIDsInSubtree(id, includeTypes, excludeTypes) { + const list = []; + const metaObject = this.metaObjects[id]; + const includeMask = (includeTypes && includeTypes.length > 0) ? arrayToMap(includeTypes) : null; + const excludeMask = (excludeTypes && excludeTypes.length > 0) ? arrayToMap(excludeTypes) : null; - const cubeColor = "lightgrey"; - const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)"; + function visit(metaObject) { + if (!metaObject) { + return; + } + var include = true; + if (excludeMask && excludeMask[metaObject.type]) { + include = false; + } else if (includeMask && (!includeMask[metaObject.type])) { + include = false; + } + if (include) { + list.push(metaObject.id); + } + const children = metaObject.children; + if (children) { + for (var i = 0, len = children.length; i < len; i++) { + visit(children[i]); + } + } + } - const height = 500; - const width = height + (height / 3); - const scale = width / 24; + visit(metaObject); + return list; + } - const facesZUp = [ - {boundary: [6, 6, 6, 6], color: cfg.frontColor || cfg.color || "#55FF55"}, - {boundary: [18, 6, 6, 6], color: cfg.backColor || cfg.color || "#55FF55"}, - {boundary: [12, 6, 6, 6], color: cfg.leftColor || cfg.color || "#FF5555"}, - {boundary: [0, 6, 6, 6], color: cfg.rightColor || cfg.color || "#FF5555"}, - {boundary: [6, 0, 6, 6], color: cfg.topColor || cfg.color || "#7777FF"}, - {boundary: [6, 12, 6, 6], color: cfg.bottomColor || cfg.color || "#7777FF"} - ]; + /** + * Iterates over the {@link MetaObject}s within the subtree. + * + * @param {String} id ID of root {@link MetaObject}. + * @param {Function} callback Callback fired at each {@link MetaObject}. + */ + withMetaObjectsInSubtree(id, callback) { + const metaObject = this.metaObjects[id]; + if (!metaObject) { + return; + } + metaObject.withMetaObjectsInSubtree(callback); + } +} - const areasZUp = [ - {label: "NavCube.front", boundaries: [[7, 7, 4, 4]], dir: [0, 1, 0], up: [0, 0, 1]}, - {label: "NavCube.back", boundaries: [[19, 7, 4, 4]], dir: [0, -1, 0], up: [0, 0, 1]}, - {label: "NavCube.right", boundaries: [[13, 7, 4, 4]], dir: [-1, 0, 0], up: [0, 0, 1]}, - {label: "NavCube.left", boundaries: [[1, 7, 4, 4]], dir: [1, 0, 0], up: [0, 0, 1]}, - {label: "NavCube.top", boundaries: [[7, 1, 4, 4]], dir: [0, 0, -1], up: [0, 1, 0]}, - {label: "NavCube.bottom", boundaries: [[7, 13, 4, 4]], dir: [0, 0, 1], up: [0, -1, 0]}, - {boundaries: [[7, 5, 4, 2]], dir: [0, 1, -1], up: [0, 1, 1]}, - {boundaries: [[1, 6, 4, 1], [6, 1, 1, 4]], dir: [1, 0, -1], up: [1, 0, 1]}, - {boundaries: [[7, 0, 4, 1], [19, 6, 4, 1]], dir: [0, -1, -1], up: [0, -1, 1]}, - {boundaries: [[13, 6, 4, 1], [11, 1, 1, 4]], dir: [-1, 0, -1], up: [-1, 0, 1]}, - {boundaries: [[7, 11, 4, 2]], dir: [0, 1, 1], up: [0, -1, 1]}, - {boundaries: [[1, 11, 4, 1], [6, 13, 1, 4]], dir: [1, 0, 1], up: [-1, 0, 1]}, - {boundaries: [[7, 17, 4, 1], [19, 11, 4, 1]], dir: [0, -1, 1], up: [0, 1, 1]}, - {boundaries: [[13, 11, 4, 1], [11, 13, 1, 4]], dir: [-1, 0, 1], up: [1, 0, 1]}, - {boundaries: [[5, 7, 2, 4]], dir: [1, 1, 0], up: [0, 0, 1]}, - {boundaries: [[11, 7, 2, 4]], dir: [-1, 1, 0], up: [0, 0, 1]}, - {boundaries: [[17, 7, 2, 4]], dir: [-1, -1, 0], up: [0, 0, 1]}, - {boundaries: [[0, 7, 1, 4], [23, 7, 1, 4]], dir: [1, -1, 0], up: [0, 0, 1]}, - {boundaries: [[5, 11, 2, 2]], dir: [1, 1, 1], up: [-1, -1, 1]}, - {boundaries: [[23, 11, 1, 1], [6, 17, 1, 1], [0, 11, 1, 1]], dir: [1, -1, 1], up: [-1, 1, 1]}, - {boundaries: [[5, 5, 2, 2]], dir: [1, 1, -1], up: [1, 1, 1]}, - {boundaries: [[11, 17, 1, 1], [17, 11, 2, 1]], dir: [-1, -1, 1], up: [1, 1, 1]}, - {boundaries: [[17, 6, 2, 1], [11, 0, 1, 1]], dir: [-1, -1, -1], up: [-1, -1, 1]}, - {boundaries: [[11, 11, 2, 2]], dir: [-1, 1, 1], up: [1, -1, 1]}, - {boundaries: [[0, 6, 1, 1], [6, 0, 1, 1], [23, 6, 1, 1]], dir: [1, -1, -1], up: [1, -1, 1]}, - {boundaries: [[11, 5, 2, 2]], dir: [-1, 1, -1], up: [-1, 1, 1]} - ]; +function arrayToMap(array) { + const map = {}; + for (var i = 0, len = array.length; i < len; i++) { + map[array[i]] = true; + } + return map; +} - [ - {boundary: [6, 6, 6, 6], color: cfg.frontColor || cfg.color || "#55FF55"}, - {boundary: [18, 6, 6, 6], color: cfg.backColor || cfg.color || "#55FF55"}, - {boundary: [12, 6, 6, 6], color: cfg.leftColor || cfg.color || "#FF5555"}, - {boundary: [0, 6, 6, 6], color: cfg.rightColor || cfg.color || "#FF5555"}, - {boundary: [6, 0, 6, 6], color: cfg.topColor || cfg.color || "#7777FF"}, - {boundary: [6, 12, 6, 6], color: cfg.bottomColor || cfg.color || "#7777FF"} - ]; +/** + * The 3D Viewer at the heart of the xeokit SDK. + * + * * A Viewer wraps a single {@link Scene} + * * Add {@link Plugin}s to a Viewer to extend its functionality. + * * {@link Viewer#metaScene} holds metadata about models in the + * Viewer's {@link MetaScene}. + * * Use {@link Viewer#cameraFlight} to fly or jump the {@link Scene}'s + * {@link Camera} to target positions, boundaries or {@link Entity}s. + * + * @public + */ +class Viewer { - const areasYUp = [ + /** + * @constructor + * @param {Object} cfg Viewer configuration. + * @param {String} [cfg.id] Optional ID for this Viewer, defaults to the ID of {@link Viewer#scene}, which xeokit automatically generates. + * @param {String} [cfg.canvasId] ID of an existing HTML canvas for the {@link Viewer#scene} - either this or canvasElement is mandatory. When both values are given, the element reference is always preferred to the ID. + * @param {HTMLCanvasElement} [cfg.canvasElement] Reference of an existing HTML canvas for the {@link Viewer#scene} - either this or canvasId is mandatory. When both values are given, the element reference is always preferred to the ID. + * @param {HTMLElement} [cfg.keyboardEventsElement] Optional reference to HTML element on which key events should be handled. Defaults to the HTML Document. + * @param {String} [cfg.spinnerElementId] ID of existing HTML element to show the {@link Spinner} - internally creates a default element automatically if this is omitted. + * @param {Number} [cfg.passes=1] The number of times the {@link Viewer#scene} renders per frame. + * @param {Boolean} [cfg.clearEachPass=false] When doing multiple passes per frame, specifies if to clear the canvas before each pass (true) or just before the first pass (false). + * @param {Boolean} [cfg.preserveDrawingBuffer=true] Whether or not to preserve the WebGL drawing buffer. This needs to be ````true```` for {@link Viewer#getSnapshot} to work. + * @param {Boolean} [cfg.transparent=true] Whether or not the canvas is transparent. + * @param {Boolean} [cfg.premultipliedAlpha=false] Whether or not you want alpha composition with premultiplied alpha. Highlighting and selection works best when this is ````false````. + * @param {Boolean} [cfg.gammaInput=true] When true, expects that all textures and colors are premultiplied gamma. + * @param {Boolean} [cfg.gammaOutput=false] Whether or not to render with pre-multiplied gama. + * @param {Number} [cfg.gammaFactor=2.2] The gamma factor to use when rendering with pre-multiplied gamma. + * @param {Number[]} [cfg.backgroundColor=[1,1,1]] Sets the canvas background color to use when ````transparent```` is false. + * @param {Boolean} [cfg.backgroundColorFromAmbientLight=true] When ````transparent```` is false, set this ````true```` + * to derive the canvas background color from {@link AmbientLight#color}, or ````false```` to set the canvas background to ````backgroundColor````. + * @param {String} [cfg.units="meters"] The measurement unit type. Accepted values are ````"meters"````, ````"metres"````, , ````"centimeters"````, ````"centimetres"````, ````"millimeters"````, ````"millimetres"````, ````"yards"````, ````"feet"```` and ````"inches"````. + * @param {Number} [cfg.scale=1] The number of Real-space units in each World-space coordinate system unit. + * @param {Number[]} [cfg.origin=[0,0,0]] The Real-space 3D origin, in current measurement units, at which the World-space coordinate origin ````[0,0,0]```` sits. + * @param {Boolean} [cfg.saoEnabled=false] Whether to enable Scalable Ambient Obscurance (SAO) effect. See {@link SAO} for more info. + * @param {Boolean} [cfg.antialias=true] Whether to enable anti-aliasing. + * @throws {String} Throws an exception when both canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement. + * @param {Boolean} [cfg.alphaDepthMask=true] Whether writing into the depth buffer is enabled or disabled when rendering transparent objects. + * @param {Boolean} [cfg.entityOffsetsEnabled=false] Whether to enable {@link Entity#offset}. For best performance, only set this ````true```` when you need to use {@link Entity#offset}. + * @param {Boolean} [cfg.pickSurfacePrecisionEnabled=false] Whether to enable full-precision accuracy when surface picking with {@link Scene#pick}. Note that when ````true````, this configuration will increase the amount of browser memory used by the Viewer. The ````pickSurfacePrecision```` option for ````Scene#pick```` only works if this is set ````true````. + * @param {Boolean} [cfg.logarithmicDepthBufferEnabled=false] Whether to enable logarithmic depth buffer. When this is true, + * you can set huge values for {@link Perspective#far} and {@link Ortho#far}, to push the far clipping plane back so + * that it does not clip huge models. + * @param {Boolean} [cfg.colorTextureEnabled=true] Whether to enable base color texture rendering. + * @param {Boolean} [cfg.pbrEnabled=false] Whether to enable physically-based rendering. + * @param {LocaleService} [cfg.localeService=null] Optional locale-based translation service. + */ + constructor(cfg) { - // Faces + /** + * The Viewer's current language setting. + * @property language + * @deprecated + * @type {String} + */ + this.language = "en"; - {yUp: "", label: "NavCube.front", boundaries: [[7, 7, 4, 4]], dir: [0, 0, -1], up: [0, 1, 0]}, - {label: "NavCube.back", boundaries: [[19, 7, 4, 4]], dir: [0, 0, 1], up: [0, 1, 0]}, - {label: "NavCube.right", boundaries: [[13, 7, 4, 4]], dir: [-1, 0, 0], up: [0, 1, 0]}, - {label: "NavCube.left", boundaries: [[1, 7, 4, 4]], dir: [1, 0, 0], up: [0, 1, 0]}, - {label: "NavCube.top", boundaries: [[7, 1, 4, 4]], dir: [0, -1, 0], up: [0, 0, -1]}, - {label: "NavCube.bottom", boundaries: [[7, 13, 4, 4]], dir: [0, 1, 0], up: [0, 0, 1]}, - {boundaries: [[7, 5, 4, 2]], dir: [0, -0.7071, -0.7071], up: [0, 0.7071, -0.7071]}, // Top-front edge - {boundaries: [[1, 6, 4, 1], [6, 1, 1, 4]], dir: [1, -1, 0], up: [1, 1, 0]}, // Top-left edge - {boundaries: [[7, 0, 4, 1], [19, 6, 4, 1]], dir: [0, -0.7071, 0.7071], up: [0, 0.7071, 0.7071]}, // Top-back edge - {boundaries: [[13, 6, 4, 1], [11, 1, 1, 4]], dir: [-1, -1, 0], up: [-1, 1, 0]}, // Top-right edge - {boundaries: [[7, 11, 4, 2]], dir: [0, 1, -1], up: [0, 1, 1]}, // Bottom-front edge - {boundaries: [[1, 11, 4, 1], [6, 13, 1, 4]], dir: [1, 1, 0], up: [-1, 1, 0]}, // Bottom-left edge - {boundaries: [[7, 17, 4, 1], [19, 11, 4, 1]], dir: [0, 1, 1], up: [0, 1, -1]}, // Bottom-back edge - {boundaries: [[13, 11, 4, 1], [11, 13, 1, 4]], dir: [-1, 1, 0], up: [1, 1, 0]}, // Bottom-right edge - {boundaries: [[5, 7, 2, 4]], dir: [1, 0, -1], up: [0, 1, 0]},// Front-left edge - {boundaries: [[11, 7, 2, 4]], dir: [-1, 0, -1], up: [0, 1, 0]}, // Front-right edge - {boundaries: [[17, 7, 2, 4]], dir: [-1, 0, 1], up: [0, 1, 0]},// Back-right edge - {boundaries: [[0, 7, 1, 4], [23, 7, 1, 4]], dir: [1, 0, 1], up: [0, 1, 0]},// Back-left edge - {boundaries: [[5, 11, 2, 2]], "dir": [0.5, 0.7071, -0.5], "up": [-0.5, 0.7071, 0.5]}, // Bottom-left-front corner - {boundaries: [[23, 11, 1, 1], [6, 17, 1, 1], [0, 11, 1, 1]],"dir": [0.5, 0.7071, 0.5],"up": [-0.5, 0.7071, -0.5]},// Bottom-back-left corner - {boundaries: [[5, 5, 2, 2]], "dir": [0.5, -0.7071, -0.5], "up": [0.5, 0.7071, -0.5]}, // Left-front-top corner - {boundaries: [[11, 17, 1, 1], [17, 11, 2, 1]], "dir": [-0.5, 0.7071, 0.5], "up": [0.5, 0.7071, -0.5]}, // Bottom-back-right corner - {boundaries: [[17, 6, 2, 1], [11, 0, 1, 1]], "dir": [-0.5, -0.7071, 0.5], "up": [-0.5, 0.7071, 0.5]}, // Top-back-right corner - {boundaries: [[11, 11, 2, 2]], "dir": [-0.5, 0.7071, -0.5], "up": [0.5, 0.7071, 0.5]}, // Bottom-front-right corner - {boundaries: [[0, 6, 1, 1], [6, 0, 1, 1], [23, 6, 1, 1]], "dir": [0.5, -0.7071, 0.5], "up": [0.5, 0.7071, 0.5]},// Top-back-left corner - {boundaries: [[11, 5, 2, 2]], "dir": [-0.5, -0.7071, -0.5], "up": [-0.5, 0.7071, -0.5]}// Top-front-right corner - ]; + /** + * The viewer's locale service. + * + * This is configured via the Viewer's constructor. + * + * By default, this service will be an instance of {@link LocaleService}, which will just return + * null translations for all given strings and phrases. + * + * @property localeService + * @type {LocaleService} + * @since 2.0 + */ + this.localeService = cfg.localeService || new LocaleService(); - for (let i = 0, len = areasZUp.length; i < len; i++) { - math.normalizeVec3(areasZUp[i].dir, areasZUp[i].dir); - math.normalizeVec3(areasZUp[i].up, areasZUp[i].up); + /** + * The Viewer's {@link Scene}. + * @property scene + * @type {Scene} + */ + this.scene = new Scene(this, { + canvasId: cfg.canvasId, + canvasElement: cfg.canvasElement, + keyboardEventsElement: cfg.keyboardEventsElement, + contextAttr: { + preserveDrawingBuffer: cfg.preserveDrawingBuffer !== false, + premultipliedAlpha: (!!cfg.premultipliedAlpha), + antialias: (cfg.antialias !== false) + }, + spinnerElementId: cfg.spinnerElementId, + transparent: (cfg.transparent !== false), + gammaInput: true, + gammaOutput: false, + backgroundColor: cfg.backgroundColor, + backgroundColorFromAmbientLight: cfg.backgroundColorFromAmbientLight, + ticksPerRender: 1, + ticksPerOcclusionTest: 20, + units: cfg.units, + scale: cfg.scale, + origin: cfg.origin, + saoEnabled: cfg.saoEnabled, + alphaDepthMask: (cfg.alphaDepthMask !== false), + entityOffsetsEnabled: (!!cfg.entityOffsetsEnabled), + pickSurfacePrecisionEnabled: (!!cfg.pickSurfacePrecisionEnabled), + logarithmicDepthBufferEnabled: (!!cfg.logarithmicDepthBufferEnabled), + pbrEnabled: (!!cfg.pbrEnabled), + colorTextureEnabled: (cfg.colorTextureEnabled !== false) + }); + + /** + * Metadata about the {@link Scene} and the models and objects within it. + * @property metaScene + * @type {MetaScene} + * @readonly + */ + this.metaScene = new MetaScene(this, this.scene); + + /** + * The Viewer's ID. + * @property id + * + * @type {String|Number} + */ + this.id = cfg.id || this.scene.id; + + /** + * The Viewer's {@link Camera}. This is also found on {@link Scene#camera}. + * @property camera + * @type {Camera} + */ + this.camera = this.scene.camera; + + /** + * The Viewer's {@link CameraFlightAnimation}, which + * is used to fly the {@link Scene}'s {@link Camera} to given targets. + * @property cameraFlight + * @type {CameraFlightAnimation} + */ + this.cameraFlight = new CameraFlightAnimation(this.scene, { + duration: 0.5 + }); + + /** + * The Viewer's {@link CameraControl}, which + * controls the {@link Scene}'s {@link Camera} with mouse, touch and keyboard input. + * @property cameraControl + * @type {CameraControl} + */ + this.cameraControl = new CameraControl(this.scene, { + // panToPointer: true, + doublePickFlyTo: true + }); + + this._plugins = []; + + /** + * Subscriptions to events sent with {@link fire}. + * @private + */ + this._eventSubs = {}; } - for (let i = 0, len = areasYUp.length; i < len; i++) { - math.normalizeVec3(areasYUp[i].dir, areasYUp[i].dir); - math.normalizeVec3(areasYUp[i].up, areasYUp[i].up); + /** + * Returns the capabilities of this Viewer. + * + * @returns {{astcSupported: boolean, etc1Supported: boolean, pvrtcSupported: boolean, etc2Supported: boolean, dxtSupported: boolean, bptcSupported: boolean}} + */ + get capabilities() { + return this.scene.capabilities; } - var areas = areasYUp; - this._textureCanvas = document.createElement('canvas'); - this._textureCanvas.width = width; - this._textureCanvas.height = height; - this._textureCanvas.style.width = width + "px"; - this._textureCanvas.style.height = height + "px"; - this._textureCanvas.style.padding = "0"; - this._textureCanvas.style.margin = "0"; - this._textureCanvas.style.top = "0"; - this._textureCanvas.style.background = cubeColor; - this._textureCanvas.style.position = "absolute"; - this._textureCanvas.style.opacity = "1.0"; - this._textureCanvas.style.visibility = "hidden"; - this._textureCanvas.style["z-index"] = 2000000; + /** + * Subscribes to an event fired at this Viewer. + * + * @param {String} event The event + * @param {Function} callback Callback fired on the event + */ + on(event, callback) { + let subs = this._eventSubs[event]; + if (!subs) { + subs = []; + this._eventSubs[event] = subs; + } + subs.push(callback); + } - const body = document.getElementsByTagName("body")[0]; - body.appendChild(this._textureCanvas); + /** + * Fires an event at this Viewer. + * + * @param {String} event Event name + * @param {Object} value Event parameters + */ + fire(event, value) { + const subs = this._eventSubs[event]; + if (subs) { + for (let i = 0, len = subs.length; i < len; i++) { + subs[i](value); + } + } + } - const context = this._textureCanvas.getContext("2d"); + /** + * Unsubscribes from an event fired at this Viewer. + * @param event + */ + off(event) { // TODO - let zUp = false; + } - function paint() { + /** + * Logs a message to the JavaScript developer console, prefixed with the ID of this Viewer. + * + * @param {String} msg The message + */ + log(msg) { + console.log(`[xeokit viewer ${this.id}]: ${msg}`); + } - for (let i = 0, len = facesZUp.length; i < len; i++) { - const face = facesZUp[i]; - const boundary = face.boundary; - const xmin = Math.round(boundary[0] * scale); - const ymin = Math.round(boundary[1] * scale); - const width = Math.round(boundary[2] * scale); - const height = Math.round(boundary[3] * scale); - context.fillStyle = face.color; - context.fillRect(xmin, ymin, width, height); - } + /** + * Logs an error message to the JavaScript developer console, prefixed with the ID of this Viewer. + * + * @param {String} msg The error message + */ + error(msg) { + console.error(`[xeokit viewer ${this.id}]: ${msg}`); + } - for (let i = 0, len = areas.length; i < len; i++) { - let xmin; - let ymin; - let width; - let height; - const area = areas[i]; + /** + * Installs a Plugin. + * + * @private + */ + addPlugin(plugin) { + this._plugins.push(plugin); + } - const boundaries = area.boundaries; - for (var j = 0, lenj = boundaries.length; j < lenj; j++) { - const boundary = boundaries[j]; - xmin = Math.round(boundary[0] * scale); - ymin = Math.round(boundary[1] * scale); - width = Math.round(boundary[2] * scale); - height = Math.round(boundary[3] * scale); - if (area.highlighted) { - context.fillStyle = area.highlighted ? cubeHighlightColor : (area.color || cubeColor); - context.fillRect(xmin, ymin, width, height); + /** + * Uninstalls a Plugin, clearing content from it first. + * + * @private + */ + removePlugin(plugin) { + for (let i = 0, len = this._plugins.length; i < len; i++) { + const p = this._plugins[i]; + if (p === plugin) { + if (p.clear) { + p.clear(); } + this._plugins.splice(i, 1); + return; } - if (area.label) { - context.fillStyle = "black"; - context.font = '60px sans-serif'; - context.textAlign = "center"; - var xcenter = xmin + (width * 0.5); - var ycenter = ymin + (height * 0.7); - context.fillText(translateLabel(area.label), xcenter, ycenter, 80); + } + } + + /** + * Sends a message to installed Plugins. + * + * The message can optionally be accompanied by a value. + * @private + */ + sendToPlugins(name, value) { + for (let i = 0, len = this._plugins.length; i < len; i++) { + const p = this._plugins[i]; + if (p.send) { + p.send(name, value); } } + } - viewer.scene.glRedraw(); + /** + * @private + * @deprecated + */ + clear() { + throw "Viewer#clear() no longer implemented - use '#sendToPlugins(\"clear\") instead"; } - const translateLabel = (function () { + /** + * @private + * @deprecated + */ + resetView() { + throw "Viewer#resetView() no longer implemented - use CameraMemento & ObjectsMemento classes instead"; + } - const swizzleYUp = { - "NavCube.front": "NavCube.front", - "NavCube.back": "NavCube.back", - "NavCube.right": "NavCube.right", - "NavCube.left": "NavCube.left", - "NavCube.top": "NavCube.top", - "NavCube.bottom": "NavCube.bottom" - }; + /** + * Enter snapshot mode. + * + * Switches rendering to a hidden snapshot canvas. + * + * Exit snapshot mode using {@link Viewer#endSnapshot}. + */ + beginSnapshot() { + if (this._snapshotBegun) { + return; + } + this.scene._renderer.beginSnapshot(); + this._snapshotBegun = true; + } - const swizzleZUp = { - "NavCube.front": "NavCube.front", - "NavCube.back": "NavCube.back", - "NavCube.right": "NavCube.right", - "NavCube.left": "NavCube.left", - "NavCube.top": "NavCube.top", - "NavCube.bottom": "NavCube.bottom" - }; + /** + * Gets a snapshot of this Viewer's {@link Scene} as a Base64-encoded image. + * + * #### Usage: + * + * ````javascript + * const imageData = viewer.getSnapshot({ + * width: 500, + * height: 500, + * format: "png" + * }); + * ```` + * @param {*} [params] Capture options. + * @param {Number} [params.width] Desired width of result in pixels - defaults to width of canvas. + * @param {Number} [params.height] Desired height of result in pixels - defaults to height of canvas. + * @param {String} [params.format="jpeg"] Desired format; "jpeg", "png" or "bmp". + * @param {Boolean} [params.includeGizmos=false] When true, will include gizmos like {@link SectionPlane} in the snapshot. + * @returns {String} String-encoded image data URI. + */ + getSnapshot(params = {}) { - const defaultLabels = { - "NavCube.front": "FRONT", - "NavCube.back": "BACK", - "NavCube.right": "RIGHT", - "NavCube.left": "LEFT", - "NavCube.top": "TOP", - "NavCube.bottom": "BOTTOM" - }; + const needFinishSnapshot = (!this._snapshotBegun); - return function (key) { - const swizzle = zUp ? swizzleZUp : swizzleYUp; - const swizzledKey = swizzle ? swizzle[key] : null; - if (swizzledKey) { - return viewer.localeService.translate(swizzledKey) || defaultLabels[swizzledKey] || swizzledKey; - } - return key; - }; - })(); + if (!this._snapshotBegun) { + this.beginSnapshot(); + } - this.setZUp = function () { - zUp = true; - areas = areasZUp; - this.clear(); - }; + if (!params.includeGizmos) { + this.sendToPlugins("snapshotStarting"); // Tells plugins to hide things that shouldn't be in snapshot + } - this.setYUp = function () { - zUp = false; - areas = areasYUp; - this.clear(); - }; + const resize = (params.width !== undefined && params.height !== undefined); + const canvas = this.scene.canvas.canvas; + const saveWidth = canvas.clientWidth; + const saveHeight = canvas.clientHeight; + const saveCssWidth = canvas.style.width; + const saveCssHeight = canvas.style.height; - this.clear = function () { - context.fillStyle = cubeColor; - context.fillRect(0, 0, width, height); - for (var i = 0, len = areas.length; i < len; i++) { - const area = areas[i]; - area.highlighted = false; - } - paint(); - }; + const width = params.width ? Math.floor(params.width) : canvas.width; + const height = params.height ? Math.floor(params.height) : canvas.height; - this.getArea = function (uv) { - const s = uv[0] * width; - const t = height - (uv[1] * height); // Correct for our texture Y-flipping - for (var i = 0, len = areas.length; i < len; i++) { - const area = areas[i]; - const boundaries = area.boundaries; - for (var j = 0, lenj = boundaries.length; j < lenj; j++) { - const boundary = boundaries[j]; - if (s >= (boundary[0] * scale) && s <= ((boundary[0] + boundary[2]) * scale) && t >= (boundary[1] * scale) && t <= ((boundary[1] + boundary[3]) * scale)) { - return i; - } - } + if (resize) { + canvas.style.width = width + "px"; + canvas.style.height = height + "px"; } - return -1; - }; - this.setAreaHighlighted = function (areaId, highlighted) { - var area = areas[areaId]; - if (!area) { - throw "Area not found: " + areaId; + this.scene._renderer.renderSnapshot(); + + const imageDataURI = this.scene._renderer.readSnapshot(params); + + if (resize) { + canvas.style.width = saveCssWidth; + canvas.style.height = saveCssHeight; + canvas.width = saveWidth; + canvas.height = saveHeight; + + this.scene.glRedraw(); } - area.highlighted = !!highlighted; - paint(); - }; - this.getAreaDir = function (areaId) { - var area = areas[areaId]; - if (!area) { - throw "Unknown area: " + areaId; + if (!params.includeGizmos) { + this.sendToPlugins("snapshotFinished"); } - return area.dir; - }; - this.getAreaUp = function (areaId) { - var area = areas[areaId]; - if (!area) { - throw "Unknown area: " + areaId; + if (needFinishSnapshot) { + this.endSnapshot(); } - return area.up; - }; - this.getImage = function () { - return this._textureCanvas; - }; + return imageDataURI; + } - this.destroy = function () { - if (this._textureCanvas) { - this._textureCanvas.parentNode.removeChild(this._textureCanvas); - this._textureCanvas = null; + /** + * Exits snapshot mode. + * + * Switches rendering back to the main canvas. + * + */ + endSnapshot() { + if (!this._snapshotBegun) { + return; } - }; + this.scene._renderer.endSnapshot(); + this.scene._renderer.render({force: true}); + this._snapshotBegun = false; + } + + /** Destroys this Viewer. + */ + destroy() { + const plugins = this._plugins.slice(); // Array will modify as we delete plugins + for (let i = 0, len = plugins.length; i < len; i++) { + const plugin = plugins[i]; + plugin.destroy(); + } + this.scene.destroy(); + } } /** - * {@link Viewer} plugin that lets us look at the entire {@link Scene} from along a chosen axis or diagonal. + * Manages global configurations for all {@link Viewer}s. * - * [](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_NavCubePlugin) + * ## Example * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_NavCubePlugin)] + * In the example below, we'll disable xeokit's double-precision support, which gives a performance and memory boost + * on low-power devices, but also means that we can no longer render double-precision models without jittering. * - * ## Overview + * That's OK if we know that we're not going to view models that are geographically vast, or offset far from the World coordinate origin. * - * * Rotating the NavCube causes the Viewer's {@link Camera} to orbit its current - * point-of-interest. Conversely, orbiting the Camera causes the NavCube to rotate accordingly. - * * The faces of the NavCube are aligned with the Viewer's {@link Scene}'s World-space coordinate axis. Clicking on a face moves - * the Camera to look at the entire Scene along the corresponding axis. Clicking on an edge or a corner looks at - * the entire Scene along a diagonal. - * * The NavCube can be configured to either jump or fly the Camera to each new position. We can configure how tightly the - * NavCube fits the Scene to view, and when flying, we can configure how fast it flies. We can also configure whether the - * NavCube fits all objects to view, or just the currently visible objects. See below for a usage example. - * * Clicking the NavCube also sets {@link CameraControl#pivotPos} to the center of the fitted objects. + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#Configs_disableDoublePrecisionAndRAF)] * - * ## Usage + * ````javascript + * import {Configs, Viewer, XKTLoaderPlugin} from "../dist/xeokit-sdk.es.js"; * - * In the example below, we'll create a Viewer and add a NavCubePlugin, which will create a NavCube gizmo in the canvas - * with the given ID. Then we'll use the {@link XKTLoaderPlugin} to load a model into the Viewer's Scene. We can then - * use the NavCube to look at the model along each axis or diagonal. + * // Access xeoit-sdk global configs. + * // We typically set configs only before we create any Viewers. + * const configs = new Configs(); * - * ````JavaScript - * import {Viewer, XKTLoaderPlugin, NavCubePlugin} from "xeokit-sdk.es.js"; + * // Disable 64-bit precision for extra speed. + * // Only set this config once, before you create any Viewers. + * configs.doublePrecisionEnabled = false; * + * // Create a Viewer, to which our configs apply * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [-3.93, 2.85, 27.01]; - * viewer.camera.look = [4.40, 3.72, 8.89]; - * viewer.camera.up = [-0.01, 0.99, 0.03]; - * - * const navCube = new NavCubePlugin(viewer, { - * - * canvasID: "myNavCubeCanvas", - * - * visible: true, // Initially visible (default) - * - * cameraFly: true, // Fly camera to each selected axis/diagonal - * cameraFitFOV: 45, // How much field-of-view the scene takes once camera has fitted it to view - * cameraFlyDuration: 0.5,// How long (in seconds) camera takes to fly to each new axis/diagonal - * - * fitVisible: false, // Fit whole scene, including invisible objects (default) + * canvasId: "myCanvas" + * }); * - * synchProjection: false // Keep NavCube in perspective projection, even when camera switches to ortho (default) - * }); + * viewer.camera.eye = [-3.933, 2.855, 27.018]; + * viewer.camera.look = [4.400, 3.724, 8.899]; + * viewer.camera.up = [-0.018, 0.999, 0.039]; * * const xktLoader = new XKTLoaderPlugin(viewer); * * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/Duplex.ifc.xkt", - * edges: true + * src: "../assets/models/xkt/v8/ifc/Duplex.ifc.xkt" * }); * ```` */ -class NavCubePlugin extends Plugin { +class Configs { /** - * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg NavCubePlugin configuration. - * @param {String} [cfg.id="NavCube"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {String} [cfg.canvasId] ID of an existing HTML canvas to display the NavCube - either this or canvasElement is mandatory. When both values are given, the element reference is always preferred to the ID. - * @param {HTMLCanvasElement} [cfg.canvasElement] Reference of an existing HTML canvas to display the NavCube - either this or canvasId is mandatory. When both values are given, the element reference is always preferred to the ID. - * @param {Boolean} [cfg.visible=true] Initial visibility. - * @param {Boolean} [cfg.shadowVisible=true] Whether the shadow of the cube is visible. - * @param {String} [cfg.cameraFly=true] Whether the {@link Camera} flies or jumps to each selected axis or diagonal. - * @param {String} [cfg.cameraFitFOV=45] How much of the field-of-view, in degrees, that the 3D scene should fill the {@link Canvas} when the {@link Camera} moves to an axis or diagonal. - * @param {String} [cfg.cameraFlyDuration=0.5] When flying the {@link Camera} to each new axis or diagonal, how long, in seconds, that the Camera takes to get there. - * @param {String} [cfg.color="lightgrey] Custom uniform color for the faces of the NavCube. - * @param {String} [cfg.frontColor="#55FF55"] Custom color for the front face of the NavCube. Overrides ````color````. - * @param {String} [cfg.backColor="#55FF55"] Custom color for the back face of the NavCube. Overrides ````color````. - * @param {String} [cfg.leftColor="#FF5555"] Custom color for the left face of the NavCube. Overrides ````color````. - * @param {String} [cfg.rightColor="#FF5555"] Custom color for the right face of the NavCube. Overrides ````color````. - * @param {String} [cfg.topColor="#5555FF"] Custom color for the top face of the NavCube. Overrides ````color````. - * @param {String} [cfg.bottomColor="#5555FF"] Custom color for the bottom face of the NavCube. Overrides ````color````. - * @param {String} [cfg.hoverColor="rgba(0,0,0,0.4)"] Custom color for highlighting regions on the NavCube as we hover the pointer over them. - * @param {Boolean} [cfg.fitVisible=false] Sets whether the axis, corner and edge-aligned views will fit the - * view to the entire {@link Scene} or just to visible object-{@link Entity}s. Entitys are visible objects when {@link Entity#isObject} and {@link Entity#visible} are both ````true````. - * @param {Boolean} [cfg.synchProjection=false] Sets whether the NavCube switches between perspective and orthographic projections in synchrony with the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. + * Creates a Configs. */ - constructor(viewer, cfg = {}) { + constructor() { - super("NavCube", viewer, cfg); + } - viewer.navCube = this; + /** + * Sets whether double precision mode is enabled for Viewers. + * + * When double precision mode is enabled (default), Viewers will accurately render models that contain + * double-precision coordinates, without jittering. + * + * Internally, double precision incurs extra performance and memory overhead, so if we're certain that + * we're not going to render models that rely on double-precision coordinates, then it's a good idea to disable + * it, especially on low-power devices. + * + * This should only be set once, before creating any Viewers. + * + * @returns {Boolean} + */ + set doublePrecisionEnabled(doublePrecision) { + math.setDoublePrecisionEnabled(doublePrecision); + } - var visible = true; + /** + * Gets whether double precision mode is enabled for all Viewers. + * + * @returns {Boolean} + */ + get doublePrecisionEnabled() { + return math.getDoublePrecisionEnabled(); + } +} - try { - this._navCubeScene = new Scene(viewer, { - canvasId: cfg.canvasId, - canvasElement: cfg.canvasElement, - transparent: true - }); +/** + * Creates {@link DistanceMeasurement}s from mouse and touch input. + * + * Belongs to a {@link DistanceMeasurementsPlugin}. Located at {@link DistanceMeasurementsPlugin#control}. + * + * Once the DistanceMeasurementControl is activated, the first click on any {@link Entity} begins constructing a {@link DistanceMeasurement}, fixing its origin to that Entity. The next click on any Entity will complete the DistanceMeasurement, fixing its target to that second Entity. The DistanceMeasurementControl will then wait for the next click on any Entity, to begin constructing another DistanceMeasurement, and so on, until deactivated. + * + * See {@link DistanceMeasurementsPlugin} for more info. + */ +class DistanceMeasurementsControl extends Component { - this._navCubeCanvas = this._navCubeScene.canvas.canvas; + /** + * @private + */ + constructor(plugin) { - this._navCubeScene.input.keyboardEnabled = false; // Don't want keyboard input in the NavCube + super(plugin.viewer.scene); - } catch (error) { - this.error(error); - return; - } + /** + * The {@link DistanceMeasurementsPlugin} that owns this DistanceMeasurementsControl. + * @type {DistanceMeasurementsPlugin} + */ + this.plugin = plugin; - const navCubeScene = this._navCubeScene; + this._active = false; - navCubeScene.clearLights(); + // Mouse input uses a combo of events that requires us to track + // the current DistanceMeasurement under construction. This is not used for touch input. + this._currentDistanceMeasurementByMouse = null; - new DirLight(navCubeScene, {dir: [0.4, -0.4, 0.8], color: [0.8, 1.0, 1.0], intensity: 1.0, space: "view"}); - new DirLight(navCubeScene, {dir: [-0.8, -0.3, -0.4], color: [0.8, 0.8, 0.8], intensity: 1.0, space: "view"}); - new DirLight(navCubeScene, {dir: [0.8, -0.6, -0.8], color: [1.0, 1.0, 1.0], intensity: 1.0, space: "view"}); + this._currentDistanceMeasurementByMouseInittouchState = { + wireVisible: null, + axisVisible: null, + targetVisible: null, + }; - this._navCubeCamera = navCubeScene.camera; - this._navCubeCamera.ortho.scale = 7.0; - this._navCubeCamera.ortho.near = 0.1; - this._navCubeCamera.ortho.far = 2000; + // Shows 2D canvas pos of touch start + this._touchStartDot = new Dot(plugin._container, + { + fillColor: plugin.defaultColor, + zIndex: plugin.zIndex + 1, + visible: false + }); - navCubeScene.edgeMaterial.edgeColor = [0.2, 0.2, 0.2]; - navCubeScene.edgeMaterial.edgeAlpha = 0.6; + // Tracks 3D world pos of touch start, dynamically calculates 2D canvas pos + this._touchStartMarker = new Marker(this, { + id: "distanceMeasurementMarker" + }); - this._zUp = Boolean(viewer.camera.zUp); + // Routes 2D canvas pos from Marker to Dot + this._touchStartMarker.on("canvasPos", (canvasPos) => { + this._touchStartDot.setPos(canvasPos[0], canvasPos[1]); + }); - var self = this; + // Event handles from CameraControl + this._onMouseHoverSurface = null; + this._onMouseHoverOff = null; + this._onPickedNothing = null; - this._synchCamera = (function () { - var matrix = math.rotationMat4c(-90 * math.DEGTORAD, 1, 0, 0); - var eyeLookVec = math.vec3(); - var eyeLookVecCube = math.vec3(); - var upCube = math.vec3(); - return function () { - var eye = viewer.camera.eye; - var look = viewer.camera.look; - var up = viewer.camera.up; - eyeLookVec = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(eye, look, eyeLookVec)), 5); - if (self._zUp) { // +Z up - math.transformVec3(matrix, eyeLookVec, eyeLookVecCube); - math.transformVec3(matrix, up, upCube); - self._navCubeCamera.look = [0, 0, 0]; - self._navCubeCamera.eye = math.transformVec3(matrix, eyeLookVec, eyeLookVecCube); - self._navCubeCamera.up = math.transformPoint3(matrix, up, upCube); - } else { // +Y up - self._navCubeCamera.look = [0, 0, 0]; - self._navCubeCamera.eye = eyeLookVec; - self._navCubeCamera.up = up; - } - }; - }()); + // Event handles from Scene.input + this._onInputMouseDown = null; + this._onInputMouseUp = null; - this._cubeTextureCanvas = new CubeTextureCanvas(viewer, cfg); + // Event handles from Canvas element + this._onCanvasTouchStart = null; + this._onCanvasTouchEnd = null; + } - this._cubeSampler = new Texture(navCubeScene, { - image: this._cubeTextureCanvas.getImage(), - flipY: true, - wrapS: ClampToEdgeWrapping, - wrapT: ClampToEdgeWrapping - }); + /** Gets if this DistanceMeasurementsControl is currently active, where it is responding to input. + * + * @returns {Boolean} + */ + get active() { + return this._active; + } - this._cubeMesh = new Mesh(navCubeScene, { - geometry: new ReadableGeometry(navCubeScene, { - primitive: "triangles", - normals: [ - 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, - 0, 0, -1, 0, 0, -1, 0, 0, -1 - ], - positions: [ - 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, - 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, - 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 - ], - uv: [ - 0.5, 0.6666, 0.25, 0.6666, 0.25, 0.3333, 0.5, 0.3333, 0.5, 0.6666, 0.5, 0.3333, 0.75, 0.3333, 0.75, 0.6666, - 0.5, 0.6666, 0.5, 1, 0.25, 1, 0.25, 0.6666, 0.25, 0.6666, 0.0, 0.6666, 0.0, 0.3333, 0.25, 0.3333, - 0.25, 0, 0.50, 0, 0.50, 0.3333, 0.25, 0.3333, 0.75, 0.3333, 1.0, 0.3333, 1.0, 0.6666, 0.75, 0.6666 - ], - indices: [ - 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, - 18, 19, 20, 21, 22, 20, 22, 23 - ] - }), - material: new PhongMaterial(navCubeScene, { - diffuse: [0.4, 0.4, 0.4], - specular: [0.4, 0.4, 0.4], - emissive: [.6, .6, .6], - diffuseMap: this._cubeSampler, - emissiveMap: this._cubeSampler - }), - visible: !!visible, - edges: true + /** + * Activates this DistanceMeasurementsControl, ready to respond to input. + */ + activate() { + + if (this._active) { + return; + } + + const plugin = this.plugin; + const scene = this.scene; + const cameraControl = plugin.viewer.cameraControl; + const canvas = scene.canvas.canvas; + const input = scene.input; + const startDot = this._touchStartDot; + + const pickSurfacePrecisionEnabled = scene.pickSurfacePrecisionEnabled; + + let mouseHoverEntity = null; + const mouseWorldPos = math.vec3(); + const mouseCanvasPos = math.vec2(); + + let lastMouseCanvasX; + let lastMouseCanvasY; + const mouseCanvasClickTolerance = 5; + + const FIRST_TOUCH_EXPECTED = 0; + const SECOND_TOUCH_EXPECTED = 1; + let touchState = FIRST_TOUCH_EXPECTED; + const touchCanvasClickTolerance = 5; + + const touchStartCanvasPos = math.vec2(); + const touchEndCanvasPos = math.vec2(); + const touchStartWorldPos = math.vec3(); + + this._onMouseHoverSurface = cameraControl.on("hoverSurface", event => { + // This gets fired for both mouse and touch input, but we don't care when handling touch + mouseHoverEntity = event.entity; + mouseWorldPos.set(event.worldPos); + mouseCanvasPos.set(event.canvasPos); + canvas.style.cursor = "pointer"; + if (this._currentDistanceMeasurementByMouse) { + this._currentDistanceMeasurementByMouse.wireVisible = this._currentDistanceMeasurementByMouseInittouchState.wireVisible; + this._currentDistanceMeasurementByMouse.axisVisible = this._currentDistanceMeasurementByMouseInittouchState.axisVisible && this.plugin.defaultAxisVisible; + this._currentDistanceMeasurementByMouse.targetVisible = this._currentDistanceMeasurementByMouseInittouchState.targetVisible; + this._currentDistanceMeasurementByMouse.target.entity = mouseHoverEntity; + this._currentDistanceMeasurementByMouse.target.worldPos = mouseWorldPos; + } }); - this._shadow = cfg.shadowVisible === false ? null : new Mesh(navCubeScene, { - geometry: new ReadableGeometry(navCubeScene, buildCylinderGeometry({ - center: [0, 0, 0], - radiusTop: 0.001, - radiusBottom: 1.4, - height: 0.01, - radialSegments: 20, - heightSegments: 1, - openEnded: true - })), - material: new PhongMaterial(navCubeScene, { - diffuse: [0.0, 0.0, 0.0], specular: [0, 0, 0], emissive: [0.0, 0.0, 0.0], alpha: 0.5 - }), - position: [0, -1.5, 0], - visible: !!visible, - pickable: false, - backfaces: false + this._onInputMouseDown = input.on("mousedown", (coords) => { + lastMouseCanvasX = coords[0]; + lastMouseCanvasY = coords[1]; }); - this._onCameraMatrix = viewer.camera.on("matrix", this._synchCamera); - this._onCameraWorldAxis = viewer.camera.on("worldAxis", () => { - if (viewer.camera.zUp) { - this._zUp = true; - this._cubeTextureCanvas.setZUp(); - this._repaint(); - this._synchCamera(); - } else if (viewer.camera.yUp) { - this._zUp = false; - this._cubeTextureCanvas.setYUp(); - this._repaint(); - this._synchCamera(); + this._onInputMouseUp = input.on("mouseup", (coords) => { + if (coords[0] > lastMouseCanvasX + mouseCanvasClickTolerance || + coords[0] < lastMouseCanvasX - mouseCanvasClickTolerance || + coords[1] > lastMouseCanvasY + mouseCanvasClickTolerance || + coords[1] < lastMouseCanvasY - mouseCanvasClickTolerance) { + return; } - }); - this._onCameraFOV = viewer.camera.perspective.on("fov", (fov) => { - if (this._synchProjection) { - this._navCubeCamera.perspective.fov = fov; + if (this._currentDistanceMeasurementByMouse) { + if (mouseHoverEntity) { + if (pickSurfacePrecisionEnabled) { + const pickResult = scene.pick({ + canvasPos: mouseCanvasPos, + pickSurface: true, + pickSurfacePrecision: true + }); + if (pickResult && pickResult.worldPos) { + this._currentDistanceMeasurementByMouse.target.worldPos = pickResult.worldPos; + } + this._currentDistanceMeasurementByMouse.approximate = false; + } + + this.fire("measurementEnd", this._currentDistanceMeasurementByMouse); + this._currentDistanceMeasurementByMouse = null; + } else { + this._currentDistanceMeasurementByMouse.destroy(); + this.fire("measurementCancel", this._currentDistanceMeasurementByMouse); + this._currentDistanceMeasurementByMouse = null; + } + } else { + if (mouseHoverEntity) { + if (pickSurfacePrecisionEnabled) { + const pickResult = scene.pick({ + canvasPos: mouseCanvasPos, + pickSurface: true, + pickSurfacePrecision: true + }); + if (pickResult && pickResult.worldPos) { + mouseWorldPos.set(pickResult.worldPos); + } + } + this._currentDistanceMeasurementByMouse = plugin.createMeasurement({ + id: math.createUUID(), + origin: { + entity: mouseHoverEntity, + worldPos: mouseWorldPos + }, + target: { + entity: mouseHoverEntity, + worldPos: mouseWorldPos + }, + approximate: true + }); + this._currentDistanceMeasurementByMouseInittouchState.axisVisible = this._currentDistanceMeasurementByMouse.axisVisible && this.plugin.defaultAxisVisible; + this._currentDistanceMeasurementByMouseInittouchState.wireVisible = this._currentDistanceMeasurementByMouse.wireVisible; + this._currentDistanceMeasurementByMouseInittouchState.targetVisible = this._currentDistanceMeasurementByMouse.targetVisible; + this.fire("measurementStart", this._currentDistanceMeasurementByMouse); + } } }); - this._onCameraProjection = viewer.camera.on("projection", (projection) => { - if (this._synchProjection) { - this._navCubeCamera.projection = (projection === "ortho" || projection === "perspective") ? projection : "perspective"; + + this._onMouseHoverOff = cameraControl.on("hoverOff", event => { + mouseHoverEntity = null; + if (this._currentDistanceMeasurementByMouse) { + this._currentDistanceMeasurementByMouse.wireVisible = false; + this._currentDistanceMeasurementByMouse.targetVisible = false; + this._currentDistanceMeasurementByMouse.axisVisible = false; } + canvas.style.cursor = "default"; }); - var lastAreaId = -1; + this._onPickedNothing = cameraControl.on("pickedNothing", event => { + if (this._currentDistanceMeasurementByMouse) { + this._currentDistanceMeasurementByMouse.destroy(); + this._currentDistanceMeasurementByMouse = null; + } + startDot.setVisible(false); + touchState = FIRST_TOUCH_EXPECTED; + }); - function actionMove(posX, posY) { - var yawInc = (posX - lastX) * -sensitivity; - var pitchInc = (posY - lastY) * -sensitivity; - viewer.camera.orbitYaw(yawInc); - viewer.camera.orbitPitch(-pitchInc); - lastX = posX; - lastY = posY; - } + canvas.addEventListener("touchstart", this._onCanvasTouchStart = (event) => { + const touches = event.touches; + const changedTouches = event.changedTouches; + if (touches.length === 1 && changedTouches.length === 1) { + getCanvasPosFromEvent(touches[0], touchStartCanvasPos); + } + }, {passive: true}); - function getCoordsWithinElement(event) { - var coords = [0, 0]; - if (!event) { - event = window.event; - coords[0] = event.x; - coords[1] = event.y; - } else { - var element = event.target; - var totalOffsetLeft = 0; - var totalOffsetTop = 0; - while (element.offsetParent) { - totalOffsetLeft += element.offsetLeft; - totalOffsetTop += element.offsetTop; - element = element.offsetParent; + canvas.addEventListener("touchend", this._onCanvasTouchEnd = (event) => { + const touches = event.touches; + const changedTouches = event.changedTouches; + if (touches.length === 0 && changedTouches.length === 1) { + getCanvasPosFromEvent(changedTouches[0], touchEndCanvasPos); + if (touchEndCanvasPos[0] > touchStartCanvasPos[0] + touchCanvasClickTolerance || + touchEndCanvasPos[0] < touchStartCanvasPos[0] - touchCanvasClickTolerance || + touchEndCanvasPos[1] > touchStartCanvasPos[1] + touchCanvasClickTolerance || + touchEndCanvasPos[1] < touchStartCanvasPos[1] - touchCanvasClickTolerance) { + return; // User is repositioning the camera or model + } + const pickResult = scene.pick({ + canvasPos: touchEndCanvasPos, + pickSurface: true, + pickSurfacePrecision: pickSurfacePrecisionEnabled + }); + if (pickResult && pickResult.worldPos) { + switch (touchState) { + case FIRST_TOUCH_EXPECTED: + startDot.setVisible(true); + this._touchStartMarker.worldPos = pickResult.worldPos; + touchStartWorldPos.set(pickResult.worldPos); + touchState = SECOND_TOUCH_EXPECTED; + break; + case SECOND_TOUCH_EXPECTED: + startDot.setVisible(false); + this._touchStartMarker.worldPos = pickResult.worldPos; + plugin.createMeasurement({ + id: math.createUUID(), + origin: { + entity: mouseHoverEntity, + worldPos: touchStartWorldPos + }, + target: { + entity: mouseHoverEntity, + worldPos: pickResult.worldPos + }, + approximate: (!pickSurfacePrecisionEnabled) + }); + touchState = FIRST_TOUCH_EXPECTED; + break; + } + } else { + startDot.setVisible(false); + touchState = FIRST_TOUCH_EXPECTED; } - coords[0] = event.pageX - totalOffsetLeft; - coords[1] = event.pageY - totalOffsetTop; } - return coords; - } + // event.stopPropagation(); + }, {passive: true}); - { - var downX = null; - var downY = null; - var down = false; - var over = false; - var sensitivity = 0.5; + this._active = true; + } - var lastX; - var lastY; + /** + * Deactivates this DistanceMeasurementsControl, making it unresponsive to input. + * + * Destroys any {@link DistanceMeasurement} under construction. + */ + deactivate() { + if (!this._active) { + return; + } - self._navCubeCanvas.addEventListener("mouseenter", self._onMouseEnter = function (e) { - over = true; - }); + this._touchStartDot.setVisible(false); + this.reset(); - self._navCubeCanvas.addEventListener("mouseleave", self._onMouseLeave = function (e) { - over = false; - }); + const input = this.plugin.viewer.scene.input; + input.off(this._onInputMouseDown); + input.off(this._onInputMouseUp); - self._navCubeCanvas.addEventListener("mousedown", self._onMouseDown = function (e) { - if (e.which !== 1) { - return; - } - downX = e.x; - downY = e.y; - lastX = e.clientX; - lastY = e.clientY; - var canvasPos = getCoordsWithinElement(e); - var hit = navCubeScene.pick({ - canvasPos: canvasPos - }); - if (hit) { - down = true; + const cameraControl = this.plugin.viewer.cameraControl; + cameraControl.off(this._onMouseHoverSurface); + cameraControl.off(this._onMouseHoverOff); + cameraControl.off(this._onPickedNothing); - } else { - down = false; - } - }); + const canvas = this.plugin.viewer.scene.canvas.canvas; + canvas.removeEventListener("touchstart", this._onCanvasTouchStart); + canvas.removeEventListener("touchend", this._onCanvasTouchEnd); - document.addEventListener("mouseup", self._onMouseUp = function (e) { - if (e.which !== 1) {// Left button - return; - } - down = false; - if (downX === null) { - return; - } - var canvasPos = getCoordsWithinElement(e); - var hit = navCubeScene.pick({ - canvasPos: canvasPos, - pickSurface: true - }); - if (hit) { - if (hit.uv) { - var areaId = self._cubeTextureCanvas.getArea(hit.uv); - if (areaId >= 0) { - document.body.style.cursor = "pointer"; - if (lastAreaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); - self._repaint(); - lastAreaId = -1; - } - if (areaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(areaId, true); - lastAreaId = areaId; - self._repaint(); - if (e.x < (downX - 3) || e.x > (downX + 3) || e.y < (downY - 3) || e.y > (downY + 3)) { - return; - } - var dir = self._cubeTextureCanvas.getAreaDir(areaId); - if (dir) { - var up = self._cubeTextureCanvas.getAreaUp(areaId); - flyTo(dir, up, function () { - if (lastAreaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); - self._repaint(); - lastAreaId = -1; - } - document.body.style.cursor = "pointer"; - if (lastAreaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); - self._repaint(); - lastAreaId = -1; - } - if (areaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(areaId, false); - lastAreaId = -1; - self._repaint(); - } - }); - } - } - } - } - } - }); + this._currentDistanceMeasurementByMouse = null; - document.addEventListener("mousemove", self._onMouseMove = function (e) { - if (lastAreaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); - self._repaint(); - lastAreaId = -1; - } - if (e.buttons === 1 && !down) { - return; - } - if (down) { - var posX = e.clientX; - var posY = e.clientY; - document.body.style.cursor = "move"; - actionMove(posX, posY); - return; - } - if (!over) { - return; - } - var canvasPos = getCoordsWithinElement(e); - var hit = navCubeScene.pick({ - canvasPos: canvasPos, - pickSurface: true - }); - if (hit) { - if (hit.uv) { - document.body.style.cursor = "pointer"; - var areaId = self._cubeTextureCanvas.getArea(hit.uv); - if (areaId === lastAreaId) { - return; - } - if (lastAreaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); - } - if (areaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(areaId, true); - self._repaint(); - lastAreaId = areaId; - } - } - } else { - document.body.style.cursor = "default"; - if (lastAreaId >= 0) { - self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); - self._repaint(); - lastAreaId = -1; - } - } - }); + this._active = false; + } - var flyTo = (function () { - var center = math.vec3(); - return function (dir, up, ok) { - var aabb = self._fitVisible ? viewer.scene.getAABB(viewer.scene.visibleObjectIds) : viewer.scene.aabb; - var diag = math.getAABB3Diag(aabb); - math.getAABB3Center(aabb, center); - var dist = Math.abs(diag / Math.tan(self._cameraFitFOV * math.DEGTORAD)); - viewer.cameraControl.pivotPos = center; - if (self._cameraFly) { - viewer.cameraFlight.flyTo({ - look: center, - eye: [center[0] - (dist * dir[0]), center[1] - (dist * dir[1]), center[2] - (dist * dir[2])], - up: up || [0, 1, 0], - orthoScale: diag * 1.1, - fitFOV: self._cameraFitFOV, - duration: self._cameraFlyDuration - }, ok); - } else { - viewer.cameraFlight.jumpTo({ - look: center, - eye: [center[0] - (dist * dir[0]), center[1] - (dist * dir[1]), center[2] - (dist * dir[2])], - up: up || [0, 1, 0], - orthoScale: diag * 1.1, - fitFOV: self._cameraFitFOV - }, ok); - } - }; - })(); + /** + * Resets this DistanceMeasurementsControl. + * + * Destroys any {@link DistanceMeasurement} under construction. + * + * Does nothing if the DistanceMeasurementsControl is not active. + */ + reset() { + if (!this._active) { + return; } + if (this._currentDistanceMeasurementByMouse) { + this._currentDistanceMeasurementByMouse.destroy(); + this._currentDistanceMeasurementByMouse = null; + } + } - this._onUpdated = viewer.localeService.on("updated", () => { - this._cubeTextureCanvas.clear(); - this._repaint(); - }); + /** + * @private + */ + destroy() { + this._touchStartDot.destroy(); + this.deactivate(); + super.destroy(); + } +} - this.setVisible(cfg.visible); - this.setCameraFitFOV(cfg.cameraFitFOV); - this.setCameraFly(cfg.cameraFly); - this.setCameraFlyDuration(cfg.cameraFlyDuration); - this.setFitVisible(cfg.fitVisible); - this.setSynchProjection(cfg.synchProjection); +const getCanvasPosFromEvent = function (event, canvasPos) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + let element = event.target; + let totalOffsetLeft = 0; + let totalOffsetTop = 0; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + canvasPos[0] = event.pageX - totalOffsetLeft; + canvasPos[1] = event.pageY - totalOffsetTop; + } + return canvasPos; +}; + +/** + * {@link Viewer} plugin for measuring point-to-point distances. + * + * [](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_createWithMouse) + * + * * [[Example 1: Model with distance measurements](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_modelWithMeasurements)] + * * [[Example 2: Create distance measurements with mouse](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_createWithMouse)] + * * [[Example 3: Configuring units and scale](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_unitsAndScale)] + * + * ## Overview + * + * * A {@link DistanceMeasurement} represents a point-to-point measurement between two 3D points on one or two {@link Entity}s. + * * As shown on the screen capture above, a DistanceMeasurement has one wire (light blue) that shows the direct point-to-point measurement, + * and three more wires (red, green and blue) that show the distance on each of the World-space X, Y and Z axis. + * * Create DistanceMeasurements programmatically with {@link DistanceMeasurementsPlugin#createMeasurement}. + * * Create DistanceMeasurements interactively using the {@link DistanceMeasurementsControl}, located at {@link DistanceMeasurementsPlugin#control}. + * * Existing DistanceMeasurements are registered by ID in {@link DistanceMeasurementsPlugin#measurements}. + * * Destroy DistanceMeasurements using {@link DistanceMeasurementsPlugin#destroyMeasurement}. + * * Configure global measurement units and scale via {@link Metrics}, located at {@link Scene#metrics}. + * + * ## Example 1: Creating DistanceMeasurements Programmatically + * + * In our first example, we'll use an {@link XKTLoaderPlugin} to load a model, and then use a DistanceMeasurementsPlugin to programmatically create two {@link DistanceMeasurement}s. + * + * Note how each DistanceMeasurement has ````origin```` and ````target```` endpoints, which each indicate a 3D World-space + * position on the surface of an {@link Entity}. The endpoints can be attached to the same Entity, or to different Entitys. + * + * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_modelWithMeasurements)] + * + * ````JavaScript + * import {Viewer, XKTLoaderPlugin, DistanceMeasurementsPlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-2.37, 18.97, -26.12]; + * viewer.scene.camera.look = [10.97, 5.82, -11.22]; + * viewer.scene.camera.up = [0.36, 0.83, 0.40]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const distanceMeasurements = new DistanceMeasurementsPlugin(viewer); + * + * const model = xktLoader.load({ + * src: "./models/xkt/duplex/duplex.xkt" + * }); + * + * model.on("loaded", () => { + * + * const myMeasurement1 = distanceMeasurements.createMeasurement({ + * id: "distanceMeasurement1", + * origin: { + * entity: viewer.scene.objects["2O2Fr$t4X7Zf8NOew3FLOH"], + * worldPos: [0.044, 5.998, 17.767] + * }, + * target: { + * entity: viewer.scene.objects["2O2Fr$t4X7Zf8NOew3FLOH"], + * worldPos: [4.738, 3.172, 17.768] + * }, + * visible: true, + * wireVisible: true + * }); + * + * const myMeasurement2 = distanceMeasurements.createMeasurement({ + * id: "distanceMeasurement2", + * origin: { + * entity: viewer.scene.objects["2O2Fr$t4X7Zf8NOew3FNr2"], + * worldPos: [0.457, 2.532, 17.766] + * }, + * target: { + * entity: viewer.scene.objects["1CZILmCaHETO8tf3SgGEXu"], + * worldPos: [0.436, 0.001, 22.135] + * }, + * visible: true, + * wireVisible: true + * }); + * }); + * ```` + * + * ## Example 2: Creating DistanceMeasurements Interactively + * + * In our second example, we'll use an {@link XKTLoaderPlugin} to load a model, then we'll use the DistanceMeasurementPlugin's {@link DistanceMeasurementsControl} to interactively create {@link DistanceMeasurement}s with mouse or touch input. + * + * After we've activated the DistanceMeasurementsControl, the first click on any {@link Entity} begins constructing a DistanceMeasurement, fixing its + * origin to that Entity. The next click on any Entity will complete the DistanceMeasurement, fixing its target to that second Entity. + * + * The DistanceMeasurementControl will then wait for the next click on any Entity, to begin constructing + * another DistanceMeasurement, and so on, until deactivated again. + * + * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_createWithMouse)] + * + * ````JavaScript + * import {Viewer, XKTLoaderPlugin, DistanceMeasurementsPlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.scene.camera.eye = [-2.37, 18.97, -26.12]; + * viewer.scene.camera.look = [10.97, 5.82, -11.22]; + * viewer.scene.camera.up = [0.36, 0.83, 0.40]; + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const distanceMeasurements = new DistanceMeasurementsPlugin(viewer); + * + * const model = xktLoader.load({ + * src: "./models/xkt/duplex/duplex.xkt" + * }); + * + * distanceMeasurements.control.activate(); // <------------ Activate the DistanceMeasurementsControl + * ```` + * + * ## Example 3: Configuring Measurement Units and Scale + * + * In our third example, we'll use the {@link Scene}'s {@link Metrics} to set the global unit of measurement to ````"meters"````. We'll also specify that a unit within the World-space coordinate system represents ten meters. + * + * The wires belonging to our DistanceMeasurements show their lengths in Real-space coordinates, in the current unit of measurement. They will dynamically update as we set these configurations. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#measurements_distance_unitsAndScale)] + * + * ````JavaScript + * const metrics = viewer.scene.metrics; + + * metrics.units = "meters"; + * metrics.scale = 10.0; + * ```` + */ +class DistanceMeasurementsPlugin extends Plugin { + + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} [cfg] Plugin configuration. + * @param {String} [cfg.id="DistanceMeasurements"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Number} [cfg.labelMinAxisLength=25] The minimum length, in pixels, of an axis wire beyond which its label is shown. + * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````. + * @param {boolean} [cfg.defaultVisible=true] The default value of the DistanceMeasurements `visible` property. + * @param {boolean} [cfg.defaultOriginVisible=true] The default value of the DistanceMeasurements `originVisible` property. + * @param {boolean} [cfg.defaultTargetVisible=true] The default value of the DistanceMeasurements `targetVisible` property. + * @param {boolean} [cfg.defaultWireVisible=true] The default value of the DistanceMeasurements `wireVisible` property. + * @param {boolean} [cfg.defaultAxisVisible=true] The default value of the DistanceMeasurements `axisVisible` property. + * @param {boolean} [cfg.defaultAxisEnabled=true] The default value of the DistanceMeasurements `axisVisible` property. + * @param {string} [cfg.defaultColor=#00BBFF] The default color of the length dots, wire and label. + * @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels). + */ + constructor(viewer, cfg = {}) { + + super("DistanceMeasurements", viewer); + + this._container = cfg.container || document.body; + + this._control = new DistanceMeasurementsControl(this); + + this._measurements = {}; + + this.labelMinAxisLength = cfg.labelMinAxisLength; + + this.defaultVisible = cfg.defaultVisible !== false; + this.defaultOriginVisible = cfg.defaultOriginVisible !== false; + this.defaultTargetVisible = cfg.defaultTargetVisible !== false; + this.defaultWireVisible = cfg.defaultWireVisible !== false; + this.defaultAxisVisible = cfg.defaultAxisVisible !== false; + this.defaultColor = cfg.defaultColor !== undefined ? cfg.defaultColor : "#00BBFF"; + this.zIndex = cfg.zIndex || 10000; } + /** + * @private + */ send(name, value) { - switch (name) { - case "language": - this._cubeTextureCanvas.clear(); - this._repaint(); // CubeTextureCanvas gets language from Viewer - break; + + } + + /** + * Gets the {@link DistanceMeasurementsControl}, which creates {@link DistanceMeasurement}s from user input. + * + * @type {DistanceMeasurementsControl} + */ + get control() { + return this._control; + } + + /** + * Gets the existing {@link DistanceMeasurement}s, each mapped to its {@link DistanceMeasurement#id}. + * + * @type {{String:DistanceMeasurement}} + */ + get measurements() { + return this._measurements; + } + + /** + * Sets the minimum length, in pixels, of an axis wire beyond which its label is shown. + * + * The axis wire's label is not shown when its length is less than this value. + * + * This is ````25```` pixels by default. + * + * Must not be less than ````1````. + * + * @type {number} + */ + set labelMinAxisLength(labelMinAxisLength) { + if (labelMinAxisLength < 1) { + this.error("labelMinAxisLength must be >= 1; defaulting to 25"); + labelMinAxisLength = 25; } + this._labelMinAxisLength = labelMinAxisLength || 25; } - _repaint() { - const image = this._cubeTextureCanvas.getImage(); - this._cubeMesh.material.diffuseMap.image = image; - this._cubeMesh.material.emissiveMap.image = image; + /** + * Gets the minimum length, in pixels, of an axis wire beyond which its label is shown. + * @returns {number} + */ + get labelMinAxisLength() { + return this._labelMinAxisLength; } /** - * Sets if the NavCube is visible. + * Creates a {@link DistanceMeasurement}. * - * @param {Boolean} visible Whether or not the NavCube is visible. + * The DistanceMeasurement is then registered by {@link DistanceMeasurement#id} in {@link DistanceMeasurementsPlugin#measurements}. + * + * @param {Object} params {@link DistanceMeasurement} configuration. + * @param {String} params.id Unique ID to assign to {@link DistanceMeasurement#id}. The DistanceMeasurement will be registered by this in {@link DistanceMeasurementsPlugin#measurements} and {@link Scene.components}. Must be unique among all components in the {@link Viewer}. + * @param {Number[]} params.origin.worldPos Origin World-space 3D position. + * @param {Entity} params.origin.entity Origin Entity. + * @param {Number[]} params.target.worldPos Target World-space 3D position. + * @param {Entity} params.target.entity Target Entity. + * @param {Boolean} [params.visible=true] Whether to initially show the {@link DistanceMeasurement}. + * @param {Boolean} [params.originVisible=true] Whether to initially show the {@link DistanceMeasurement} origin. + * @param {Boolean} [params.targetVisible=true] Whether to initially show the {@link DistanceMeasurement} target. + * @param {Boolean} [params.wireVisible=true] Whether to initially show the direct point-to-point wire between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target}. + * @param {Boolean} [params.axisVisible=true] Whether to initially show the axis-aligned wires between {@link DistanceMeasurement#origin} and {@link DistanceMeasurement#target}. + * @param {string} [params.color] The color of the length dot, wire and label. + * @returns {DistanceMeasurement} The new {@link DistanceMeasurement}. */ - setVisible(visible = true) { - if (!this._navCubeCanvas) { + createMeasurement(params = {}) { + if (this.viewer.scene.components[params.id]) { + this.error("Viewer scene component with this ID already exists: " + params.id); + delete params.id; + } + const origin = params.origin; + const target = params.target; + const measurement = new DistanceMeasurement(this, { + id: params.id, + plugin: this, + container: this._container, + origin: { + entity: origin.entity, + worldPos: origin.worldPos + }, + target: { + entity: target.entity, + worldPos: target.worldPos + }, + visible: params.visible, + wireVisible: params.wireVisible, + axisVisible: params.axisVisible !== false && this.defaultAxisVisible !== false, + originVisible: params.originVisible, + targetVisible: params.targetVisible, + color: params.color + }); + this._measurements[measurement.id] = measurement; + measurement.on("destroyed", () => { + delete this._measurements[measurement.id]; + }); + this.fire("measurementCreated", measurement); + return measurement; + } + + /** + * Destroys a {@link DistanceMeasurement}. + * + * @param {String} id ID of DistanceMeasurement to destroy. + */ + destroyMeasurement(id) { + const measurement = this._measurements[id]; + if (!measurement) { + this.log("DistanceMeasurement not found: " + id); return; } - this._cubeMesh.visible = visible; - if (this._shadow) { - this._shadow.visible = visible; + measurement.destroy(); + this.fire("measurementDestroyed", measurement); + } + + /** + * Destroys all {@link DistanceMeasurement}s. + */ + clear() { + const ids = Object.keys(this._measurements); + for (var i = 0, len = ids.length; i < len; i++) { + this.destroyMeasurement(ids[i]); } - this._navCubeCanvas.style.visibility = visible ? "visible" : "hidden"; } /** - * Gets if the NavCube is visible. + * Destroys this DistanceMeasurementsPlugin. * - * @return {Boolean} True when the NavCube is visible. + * Destroys all {@link DistanceMeasurement}s first. */ - getVisible() { - if (!this._navCubeCanvas) { - return false; - } - return this._cubeMesh.visible; + destroy() { + this.clear(); + super.destroy(); } +} + +/** + * {@link Viewer} plugin that makes interaction smoother with large models, by temporarily switching + * the Viewer to faster, lower-quality rendering modes whenever we interact. + * + * [](https://xeokit.github.io/xeokit-sdk/examples/#performance_FastNavPlugin) + * + * FastNavPlugin works by hiding specified Viewer rendering features, and optionally scaling the Viewer's canvas + * resolution, whenever we interact with the Viewer. Then, once we've finished interacting, FastNavPlugin restores those + * rendering features and the original canvas scale, after a configured delay. + * + * Depending on how we configure FastNavPlugin, we essentially switch to a smooth-rendering low-quality view while + * interacting, then return to the normal higher-quality view after we stop, following an optional delay. + * + * Down-scaling the canvas resolution gives particularly good results. For example, scaling by ````0.5```` means that + * we're rendering a quarter of the pixels while interacting, which can make the Viewer noticeably smoother with big models. + * + * The screen capture above shows FastNavPlugin in action. In this example, whenever we move the Camera or resize the Canvas, + * FastNavPlugin switches off enhanced edges and ambient shadows (SAO), and down-scales the canvas, making it slightly + * blurry. When ````0.5```` seconds passes with no interaction, the plugin shows edges and SAO again, and restores the + * original canvas scale. + * + * # Usage + * + * In the example below, we'll create a {@link Viewer}, add a {@link FastNavPlugin}, then use an {@link XKTLoaderPlugin} to load a model. + * + * Whenever we interact with the Viewer, our FastNavPlugin will: + * + * * hide edges, + * * hide ambient shadows (SAO), + * * hide physically-based materials (switching to non-PBR), + * * hide transparent objects, and + * * scale the canvas resolution by 0.5, causing the GPU to render 75% less pixels. + *
+ * + * We'll also configure a 0.5 second delay before we transition back to high-quality each time we stop ineracting, so that we're + * not continually flipping between low and high quality as we interact. Since we're only rendering ambient shadows when not interacting, we'll also treat ourselves + * to expensive, high-quality SAO settings, that we wouldn't normally configure for an interactive SAO effect. + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#performance_FastNavPlugin)] + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, FastNavPlugin} from "xeokit-sdk.es.js"; + * + * // Create a Viewer with PBR and SAO enabled + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true, + * pbr: true, // Enable physically-based rendering for Viewer + * sao: true // Enable ambient shadows for Viewer + * }); + * + * viewer.scene.camera.eye = [-66.26, 105.84, -281.92]; + * viewer.scene.camera.look = [42.45, 49.62, -43.59]; + * viewer.scene.camera.up = [0.05, 0.95, 0.15]; + * + * // Higher-quality SAO settings + * + * viewer.scene.sao.enabled = true; + * viewer.scene.sao.numSamples = 60; + * viewer.scene.sao.kernelRadius = 170; + * + * // Install a FastNavPlugin + * + * new FastNavPlugin(viewer, { + * hideEdges: true, // Don't show edges while we interact (default is true) + * hideSAO: true, // Don't show ambient shadows while we interact (default is true) + * hideColorTexture: true, // No color textures while we interact (default is true) + * hidePBR: true, // No physically-based rendering while we interact (default is true) + * hideTransparentObjects: true, // Hide transparent objects while we interact (default is false) + * scaleCanvasResolution: true, // Scale canvas resolution while we interact (default is false) + * scaleCanvasResolutionFactor: 0.5, // Factor by which we scale canvas resolution when we interact (default is 0.6) + * delayBeforeRestore: true, // When we stop interacting, delay before restoring normal render (default is true) + * delayBeforeRestoreSeconds: 0.5 // The delay duration, in seconds (default is 0.5) + * }); + * + * // Load a BIM model from XKT + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/HolterTower.xkt", + * sao: true, // Enable ambient shadows for this model + * pbr: true // Enable physically-based rendering for this model + * }); + * ```` + * + * @class FastNavPlugin + */ +class FastNavPlugin extends Plugin { + + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg FastNavPlugin configuration. + * @param {String} [cfg.id="FastNav"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Boolean} [cfg.hideColorTexture=true] Whether to temporarily hide color textures whenever we interact with the Viewer. + * @param {Boolean} [cfg.hidePBR=true] Whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. + * @param {Boolean} [cfg.hideSAO=true] Whether to temporarily hide scalable ambient occlusion (SAO) whenever we interact with the Viewer. + * @param {Boolean} [cfg.hideEdges=true] Whether to temporarily hide edges whenever we interact with the Viewer. + * @param {Boolean} [cfg.hideTransparentObjects=false] Whether to temporarily hide transparent objects whenever we interact with the Viewer. + * @param {Number} [cfg.scaleCanvasResolution=false] Whether to temporarily down-scale the canvas resolution whenever we interact with the Viewer. + * @param {Number} [cfg.scaleCanvasResolutionFactor=0.6] The factor by which we downscale the canvas resolution whenever we interact with the Viewer. + * @param {Boolean} [cfg.delayBeforeRestore=true] Whether to temporarily have a delay before restoring normal rendering after we stop interacting with the Viewer. + * @param {Number} [cfg.delayBeforeRestoreSeconds=0.5] Delay in seconds before restoring normal rendering after we stop interacting with the Viewer. + */ + constructor(viewer, cfg = {}) { + + super("FastNav", viewer); + + this._hideColorTexture = cfg.hideColorTexture !== false; + this._hidePBR = cfg.hidePBR !== false; + this._hideSAO = cfg.hideSAO !== false; + this._hideEdges = cfg.hideEdges !== false; + this._hideTransparentObjects = !!cfg.hideTransparentObjects; + this._scaleCanvasResolution = !!cfg.scaleCanvasResolution; + this._scaleCanvasResolutionFactor = cfg.scaleCanvasResolutionFactor || 0.6; + this._delayBeforeRestore = (cfg.delayBeforeRestore !== false); + this._delayBeforeRestoreSeconds = cfg.delayBeforeRestoreSeconds || 0.5; + + let timer = this._delayBeforeRestoreSeconds * 1000; + let fastMode = false; + + const switchToLowQuality = () => { + timer = (this._delayBeforeRestoreSeconds * 1000); + if (!fastMode) { + viewer.scene._renderer.setColorTextureEnabled(!this._hideColorTexture); + viewer.scene._renderer.setPBREnabled(!this._hidePBR); + viewer.scene._renderer.setSAOEnabled(!this._hideSAO); + viewer.scene._renderer.setTransparentEnabled(!this._hideTransparentObjects); + viewer.scene._renderer.setEdgesEnabled(!this._hideEdges); + if (this._scaleCanvasResolution) { + viewer.scene.canvas.resolutionScale = this._scaleCanvasResolutionFactor; + } else { + viewer.scene.canvas.resolutionScale = 1; + } + fastMode = true; + } + }; + + const switchToHighQuality = () => { + viewer.scene.canvas.resolutionScale = 1; + viewer.scene._renderer.setEdgesEnabled(true); + viewer.scene._renderer.setColorTextureEnabled(true); + viewer.scene._renderer.setPBREnabled(true); + viewer.scene._renderer.setSAOEnabled(true); + viewer.scene._renderer.setTransparentEnabled(true); + fastMode = false; + }; + + this._onCanvasBoundary = viewer.scene.canvas.on("boundary", switchToLowQuality); + this._onCameraMatrix = viewer.scene.camera.on("matrix", switchToLowQuality); + + this._onSceneTick = viewer.scene.on("tick", (tickEvent) => { + if (!fastMode) { + return; + } + timer -= tickEvent.deltaTime; + if ((!this._delayBeforeRestore) || timer <= 0) { + switchToHighQuality(); + } + }); + + let down = false; + + this._onSceneMouseDown = viewer.scene.input.on("mousedown", () => { + down = true; + }); + + this._onSceneMouseUp = viewer.scene.input.on("mouseup", () => { + down = false; + }); + this._onSceneMouseMove = viewer.scene.input.on("mousemove", () => { + if (!down) { + return; + } + switchToLowQuality(); + }); + } /** - * Sets whether the axis, corner and edge-aligned views will fit the - * view to the entire {@link Scene} or just to visible object-{@link Entity}s. + * Gets whether to temporarily hide color textures whenever we interact with the Viewer. * - * Entitys are visible objects when {@link Entity#isObject} and {@link Entity#visible} are both ````true````. + * Default is ````true````. * - * @param {Boolean} fitVisible Set ````true```` to fit only visible object-Entitys. + * @return {Boolean} ````true```` if hiding color textures. */ - setFitVisible(fitVisible = false) { - this._fitVisible = fitVisible; + get hideColorTexture() { + return this._hideColorTexture; } /** - * Gets whether the axis, corner and edge-aligned views will fit the - * view to the entire {@link Scene} or just to visible object-{@link Entity}s. + * Sets whether to temporarily hide color textures whenever we interact with the Viewer. * - * Entitys are visible objects when {@link Entity#isObject} and {@link Entity#visible} are both ````true````. + * Default is ````true````. * - * @return {Boolean} True when fitting only visible object-Entitys. + * @param {Boolean} hideColorTexture ````true```` to hide color textures. */ - getFitVisible() { - return this._fitVisible; + set hideColorTexture(hideColorTexture) { + this._hideColorTexture = hideColorTexture; + } + + /** + * Gets whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. + * + * Default is ````true````. + * + * @return {Boolean} ````true```` if hiding PBR. + */ + get hidePBR() { + return this._hidePBR; } /** - * Sets whether the {@link Camera} flies or jumps to each selected axis or diagonal. + * Sets whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. * - * Default is ````true````, to fly. + * Default is ````true````. * - * @param {Boolean} cameraFly Set ````true```` to fly, else ````false```` to jump. + * @param {Boolean} hidePBR ````true```` to hide PBR. */ - setCameraFly(cameraFly = true) { - this._cameraFly = cameraFly; + set hidePBR(hidePBR) { + this._hidePBR = hidePBR; } /** - * Gets whether the {@link Camera} flies or jumps to each selected axis or diagonal. + * Gets whether to temporarily hide scalable ambient shadows (SAO) whenever we interact with the Viewer. * - * Default is ````true````, to fly. + * Default is ````true````. * - * @returns {Boolean} Returns ````true```` to fly, else ````false```` to jump. + * @return {Boolean} ````true```` if hiding SAO. */ - getCameraFly() { - return this._cameraFly; + get hideSAO() { + return this._hideSAO; } /** - * Sets how much of the field-of-view, in degrees, that the {@link Scene} should - * fill the canvas when flying or jumping the {@link Camera} to each selected axis or diagonal. + * Sets whether to temporarily hide scalable ambient shadows (SAO) whenever we interact with the Viewer. * - * Default value is ````45````. + * Default is ````true````. * - * @param {Number} cameraFitFOV New FOV value. + * @param {Boolean} hideSAO ````true```` to hide SAO. */ - setCameraFitFOV(cameraFitFOV = 45) { - this._cameraFitFOV = cameraFitFOV; + set hideSAO(hideSAO) { + this._hideSAO = hideSAO; } /** - * Gets how much of the field-of-view, in degrees, that the {@link Scene} should - * fill the canvas when flying or jumping the {@link Camera} to each selected axis or diagonal. + * Gets whether to temporarily hide edges whenever we interact with the Viewer. * - * Default value is ````45````. + * Default is ````true````. * - * @returns {Number} Current FOV value. + * @return {Boolean} ````true```` if hiding edges. */ - getCameraFitFOV() { - return this._cameraFitFOV; + get hideEdges() { + return this._hideEdges; } /** - * When flying the {@link Camera} to each new axis or diagonal, sets how long, in seconds, that the Camera takes to get there. + * Sets whether to temporarily hide edges whenever we interact with the Viewer. * - * Default is ````0.5````. + * Default is ````true````. * - * @param {Boolean} cameraFlyDuration Camera flight duration in seconds. + * @param {Boolean} hideEdges ````true```` to hide edges. */ - setCameraFlyDuration(cameraFlyDuration = 0.5) { - this._cameraFlyDuration = cameraFlyDuration; + set hideEdges(hideEdges) { + this._hideEdges = hideEdges; } /** - * When flying the {@link Camera} to each new axis or diagonal, gets how long, in seconds, that the Camera takes to get there. + * Gets whether to temporarily hide transparent objects whenever we interact with the Viewer. * - * Default is ````0.5````. + * Does not hide X-rayed, selected, highlighted objects. * - * @returns {Boolean} Camera flight duration in seconds. + * Default is ````false````. + * + * @return {Boolean} ````true```` if hiding transparent objects. */ - getCameraFlyDuration() { - return this._cameraFlyDuration; + get hideTransparentObjects() { + return this._hideTransparentObjects } /** - * Sets whether the NavCube switches between perspective and orthographic projections in synchrony with - * the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. + * Sets whether to temporarily hide transparent objects whenever we interact with the Viewer. * - * @param {Boolean} synchProjection Set ````true```` to keep NavCube projection synchronized with {@link Camera#projection}. + * Does not hide X-rayed, selected, highlighted objects. + * + * Default is ````false````. + * + * @param {Boolean} hideTransparentObjects ````true```` to hide transparent objects. */ - setSynchProjection(synchProjection = false) { - this._synchProjection = synchProjection; + set hideTransparentObjects(hideTransparentObjects) { + this._hideTransparentObjects = (hideTransparentObjects !== false); } /** - * Gets whether the NavCube switches between perspective and orthographic projections in synchrony with - * the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. + * Gets whether to temporarily scale the canvas resolution whenever we interact with the Viewer. * - * @return {Boolean} True when NavCube projection is synchronized with {@link Camera#projection}. + * Default is ````false````. + * + * The scaling factor is configured via {@link FastNavPlugin#scaleCanvasResolutionFactor}. + * + * @return {Boolean} ````true```` if scaling the canvas resolution. */ - getSynchProjection() { - return this._synchProjection; + get scaleCanvasResolution() { + return this._scaleCanvasResolution; } /** - * Destroys this NavCubePlugin. + * Sets whether to temporarily scale the canvas resolution whenever we interact with the Viewer. * - * Does not destroy the canvas the NavCubePlugin was configured with. + * Default is ````false````. + * + * The scaling factor is configured via {@link FastNavPlugin#scaleCanvasResolutionFactor}. + * + * @param {Boolean} scaleCanvasResolution ````true```` to scale the canvas resolution. */ - destroy() { + set scaleCanvasResolution(scaleCanvasResolution) { + this._scaleCanvasResolution = scaleCanvasResolution; + } - if (this._navCubeCanvas) { + /** + * Gets the factor by which we temporarily scale the canvas resolution when we interact with the viewer. + * + * Default is ````0.6````. + * + * Enable canvas resolution scaling by setting {@link FastNavPlugin#scaleCanvasResolution} ````true````. + * + * @return {Number} Factor by which we scale the canvas resolution. + */ + get scaleCanvasResolutionFactor() { + return this._scaleCanvasResolutionFactor; + } - this.viewer.localeService.off(this._onUpdated); - this.viewer.camera.off(this._onCameraMatrix); - this.viewer.camera.off(this._onCameraWorldAxis); - this.viewer.camera.perspective.off(this._onCameraFOV); - this.viewer.camera.off(this._onCameraProjection); + /** + * Sets the factor by which we temporarily scale the canvas resolution when we interact with the viewer. + * + * Accepted range is ````[0.0 .. 1.0]````. + * + * Default is ````0.6````. + * + * Enable canvas resolution scaling by setting {@link FastNavPlugin#scaleCanvasResolution} ````true````. + * + * @param {Number} scaleCanvasResolutionFactor Factor by which we scale the canvas resolution. + */ + set scaleCanvasResolutionFactor(scaleCanvasResolutionFactor) { + this._scaleCanvasResolutionFactor = scaleCanvasResolutionFactor || 0.6; + } - this._navCubeCanvas.removeEventListener("mouseenter", this._onMouseEnter); - this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave); - this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown); + /** + * Gets whether to have a delay before restoring normal rendering after we stop interacting with the Viewer. + * + * The delay duration is configured via {@link FastNavPlugin#delayBeforeRestoreSeconds}. + * + * Default is ````true````. + * + * @return {Boolean} Whether to have a delay. + */ + get delayBeforeRestore() { + return this._delayBeforeRestore; + } - document.removeEventListener("mousemove", this._onMouseMove); - document.removeEventListener("mouseup", this._onMouseUp); + /** + * Sets whether to have a delay before restoring normal rendering after we stop interacting with the Viewer. + * + * The delay duration is configured via {@link FastNavPlugin#delayBeforeRestoreSeconds}. + * + * Default is ````true````. + * + * @param {Boolean} delayBeforeRestore Whether to have a delay. + */ + set delayBeforeRestore(delayBeforeRestore) { + this._delayBeforeRestore = delayBeforeRestore; + } - this._navCubeCanvas = null; - this._cubeTextureCanvas.destroy(); - this._cubeTextureCanvas = null; + /** + * Gets the delay before restoring normal rendering after we stop interacting with the Viewer. + * + * The delay is enabled when {@link FastNavPlugin#delayBeforeRestore} is ````true````. + * + * Default is ````0.5```` seconds. + * + * @return {Number} Delay in seconds. + */ + get delayBeforeRestoreSeconds() { + return this._delayBeforeRestoreSeconds; + } - this._onMouseEnter = null; - this._onMouseLeave = null; - this._onMouseDown = null; - this._onMouseMove = null; - this._onMouseUp = null; - } + /** + * Sets the delay before restoring normal rendering after we stop interacting with the Viewer. + * + * The delay is enabled when {@link FastNavPlugin#delayBeforeRestore} is ````true````. + * + * Default is ````0.5```` seconds. + * + * @param {Number} delayBeforeRestoreSeconds Delay in seconds. + */ + set delayBeforeRestoreSeconds(delayBeforeRestoreSeconds) { + this._delayBeforeRestoreSeconds = delayBeforeRestoreSeconds !== null && delayBeforeRestoreSeconds !== undefined ? delayBeforeRestoreSeconds : 0.5; + } - this._navCubeScene.destroy(); - this._navCubeScene = null; - this._cubeMesh = null; - this._shadow = null; + /** + * @private + */ + send(name, value) { + } + /** + * Destroys this plugin. + */ + destroy() { + this.viewer.scene.camera.off(this._onCameraMatrix); + this.viewer.scene.canvas.off(this._onCanvasBoundary); + this.viewer.scene.input.off(this._onSceneMouseDown); + this.viewer.scene.input.off(this._onSceneMouseUp); + this.viewer.scene.input.off(this._onSceneMouseMove); + this.viewer.scene.off(this._onSceneTick); super.destroy(); } } -const tempVec3a$8 = math.vec3(); - /** - * @private + * Default data access strategy for {@link GLTFLoaderPlugin}. + * + * This just loads assets using XMLHttpRequest. */ -class OBJSceneGraphLoader { +class GLTFDefaultDataSource { + + constructor() { + } /** - * Loads OBJ and MTL from file(s) into a {@link Node}. + * Gets metamodel JSON. * - * @static - * @param {Node} modelNode Node to load into. - * @param {String} src Path to OBJ file. - * @param {Object} params Loading options. + * @param {String|Number} metaModelSrc Identifies the metamodel JSON asset. + * @param {Function} ok Fired on successful loading of the metamodel JSON asset. + * @param {Function} error Fired on error while loading the metamodel JSON asset. */ - load(modelNode, src, params = {}) { - - var spinner = modelNode.scene.canvas.spinner; - spinner.processes++; - - loadOBJ(modelNode, src, function (state) { - loadMTLs(modelNode, state, function () { - - createMeshes(modelNode, state); - - spinner.processes--; + getMetaModel(metaModelSrc, ok, error) { + utils.loadJSON(metaModelSrc, + (json) => { + ok(json); + }, + function (errMsg) { + error(errMsg); + }); + } - core.scheduleTask(function () { - modelNode.fire("loaded", true, false); - }); + /** + * Gets glTF JSON. + * + * @param {String|Number} glTFSrc Identifies the glTF JSON asset. + * @param {Function} ok Fired on successful loading of the glTF JSON asset. + * @param {Function} error Fired on error while loading the glTF JSON asset. + */ + getGLTF(glTFSrc, ok, error) { + utils.loadArraybuffer(glTFSrc, + (gltf) => { + ok(gltf); + }, + function (errMsg) { + error(errMsg); }); - }); } /** - * Parses OBJ and MTL text strings into a {@link Node}. + * Gets binary glTF file. * - * @static - * @param {Node} modelNode Node to load into. - * @param {String} objText OBJ text string. - * @param {String} [mtlText] MTL text string. - * @param {String} [basePath] Base path for external resources. + * @param {String|Number} glbSrc Identifies the .glb asset. + * @param {Function} ok Fired on successful loading of the .glb asset. + * @param {Function} error Fired on error while loading the .glb asset. */ - parse(modelNode, objText, mtlText, basePath) { - if (!objText) { - this.warn("load() param expected: objText"); - return; - } - var state = parseOBJ(modelNode, objText, null); - if (mtlText) { - parseMTL(modelNode, mtlText, basePath); - } - createMeshes(modelNode, state); - modelNode.src = null; - modelNode.fire("loaded", true, false); + getGLB(glbSrc, ok, error) { + utils.loadArraybuffer(glbSrc, + (arraybuffer) => { + ok(arraybuffer); + }, + function (errMsg) { + error(errMsg); + }); } -} -//-------------------------------------------------------------------------------------------- -// Loads OBJ -// -// Parses OBJ into an intermediate state object. The object will contain geometry data -// and material IDs from which meshes can be created later. The object will also -// contain a list of filenames of the MTL files referenced by the OBJ, is any. -// -// Originally based on the THREE.js OBJ and MTL loaders: -// -// https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/OBJLoader.js -// https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/MTLLoader.js -//-------------------------------------------------------------------------------------------- - -var loadOBJ = function (modelNode, url, ok) { - loadFile(url, function (text) { - var state = parseOBJ(modelNode, text, url); - ok(state); - }, - function (error) { - modelNode.error(error); - }); -}; - -var parseOBJ = (function () { + /** + * Gets glTF binary attachment. + * + * Note that this method requires the source of the glTF JSON asset. This is because the binary attachment + * source could be relative to the glTF source, IE. it may not be a global ID. + * + * @param {String|Number} glTFSrc Identifies the glTF JSON asset. + * @param {String|Number} binarySrc Identifies the glTF binary asset. + * @param {Function} ok Fired on successful loading of the glTF binary asset. + * @param {Function} error Fired on error while loading the glTF binary asset. + */ + getArrayBuffer(glTFSrc, binarySrc, ok, error) { + loadArraybuffer(glTFSrc, binarySrc, + (arrayBuffer) => { + ok(arrayBuffer); + }, + function (errMsg) { + error(errMsg); + }); + } +} - const regexp = { - // v float float float - vertex_pattern: /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/, - // vn float float float - normal_pattern: /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/, - // vt float float - uv_pattern: /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/, - // f vertex vertex vertex - face_vertex: /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/, - // f vertex/uv vertex/uv vertex/uv - face_vertex_uv: /^f\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+))?/, - // f vertex/uv/normal vertex/uv/normal vertex/uv/normal - face_vertex_uv_normal: /^f\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+)\/(-?\d+))?/, - // f vertex//normal vertex//normal vertex//normal - face_vertex_normal: /^f\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)(?:\s+(-?\d+)\/\/(-?\d+))?/, - // o object_name | g group_name - object_pattern: /^[og]\s*(.+)?/, - // s boolean - smoothing_pattern: /^s\s+(\d+|on|off)/, - // mtllib file_reference - material_library_pattern: /^mtllib /, - // usemtl material_name - material_use_pattern: /^usemtl / +function loadArraybuffer(glTFSrc, binarySrc, ok, err) { + // Check for data: URI + var defaultCallback = () => { }; + ok = ok || defaultCallback; + err = err || defaultCallback; + const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; + const dataUriRegexResult = binarySrc.match(dataUriRegex); + if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest + const isBase64 = !!dataUriRegexResult[2]; + var data = dataUriRegexResult[3]; + data = window.decodeURIComponent(data); + if (isBase64) { + data = window.atob(data); + } + try { + const buffer = new ArrayBuffer(data.length); + const view = new Uint8Array(buffer); + for (var i = 0; i < data.length; i++) { + view[i] = data.charCodeAt(i); + } + window.setTimeout(function () { + ok(buffer); + }, 0); + } catch (error) { + window.setTimeout(function () { + err(error); + }, 0); + } + } else { + const basePath = getBasePath$1(glTFSrc); + const url = basePath + binarySrc; + const request = new XMLHttpRequest(); + request.open('GET', url, true); + request.responseType = 'arraybuffer'; + request.onreadystatechange = function () { + if (request.readyState === 4) { + if (request.status === 200) { + ok(request.response); + } else { + err('loadArrayBuffer error : ' + request.response); + } + } + }; + request.send(null); + } +} - return function (modelNode, text, url) { +function getBasePath$1(src) { + var i = src.lastIndexOf("/"); + return (i !== 0) ? src.substring(0, i + 1) : ""; +} - url = url || ""; +function assert$5(condition, message) { + if (!condition) { + throw new Error(message || 'loader assertion failed.'); + } +} - var state = { - src: url, - basePath: getBasePath(url), - objects: [], - object: {}, - positions: [], - normals: [], - uv: [], - materialLibraries: {} - }; +const isBrowser$4 = Boolean(typeof process !== 'object' || String(process) !== '[object process]' || process.browser); +const matches$1 = typeof process !== 'undefined' && process.version && /v([0-9]*)/.exec(process.version); +matches$1 && parseFloat(matches$1[1]) || 0; - startObject(state, "", false); +const VERSION$9 = "3.2.6" ; - // Parts of this parser logic are derived from the THREE.js OBJ loader: - // https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/OBJLoader.js +function assert$4(condition, message) { + if (!condition) { + throw new Error(message || 'loaders.gl assertion failed.'); + } +} - if (text.indexOf('\r\n') !== -1) { - // This is faster than String.split with regex that splits on both - text = text.replace('\r\n', '\n'); - } +const globals$2 = { + self: typeof self !== 'undefined' && self, + window: typeof window !== 'undefined' && window, + global: typeof global !== 'undefined' && global, + document: typeof document !== 'undefined' && document +}; +const global_ = globals$2.global || globals$2.self || globals$2.window || {}; +const isBrowser$3 = typeof process !== 'object' || String(process) !== '[object process]' || process.browser; +const isWorker = typeof importScripts === 'function'; +const isMobile = typeof window !== 'undefined' && typeof window.orientation !== 'undefined'; +const matches = typeof process !== 'undefined' && process.version && /v([0-9]*)/.exec(process.version); +matches && parseFloat(matches[1]) || 0; - var lines = text.split('\n'); - var line = '', lineFirstChar = '', lineSecondChar = ''; - var lineLength = 0; - var result = []; +function _defineProperty(obj, key, value) { + if (key in obj) { + Object.defineProperty(obj, key, { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } else { + obj[key] = value; + } - // Faster to just trim left side of the line. Use if available. - var trimLeft = (typeof ''.trimLeft === 'function'); + return obj; +} - for (var i = 0, l = lines.length; i < l; i++) { +class WorkerJob { + constructor(jobName, workerThread) { + _defineProperty(this, "name", void 0); - line = lines[i]; + _defineProperty(this, "workerThread", void 0); - line = trimLeft ? line.trimLeft() : line.trim(); + _defineProperty(this, "isRunning", true); - lineLength = line.length; + _defineProperty(this, "result", void 0); - if (lineLength === 0) { - continue; - } + _defineProperty(this, "_resolve", () => {}); - lineFirstChar = line.charAt(0); + _defineProperty(this, "_reject", () => {}); - if (lineFirstChar === '#') { - continue; - } + this.name = jobName; + this.workerThread = workerThread; + this.result = new Promise((resolve, reject) => { + this._resolve = resolve; + this._reject = reject; + }); + } - if (lineFirstChar === 'v') { + postMessage(type, payload) { + this.workerThread.postMessage({ + source: 'loaders.gl', + type, + payload + }); + } - lineSecondChar = line.charAt(1); + done(value) { + assert$4(this.isRunning); + this.isRunning = false; - if (lineSecondChar === ' ' && (result = regexp.vertex_pattern.exec(line)) !== null) { + this._resolve(value); + } - // 0 1 2 3 - // ['v 1.0 2.0 3.0', '1.0', '2.0', '3.0'] + error(error) { + assert$4(this.isRunning); + this.isRunning = false; - state.positions.push( - parseFloat(result[1]), - parseFloat(result[2]), - parseFloat(result[3]) - ); + this._reject(error); + } - } else if (lineSecondChar === 'n' && (result = regexp.normal_pattern.exec(line)) !== null) { +} - // 0 1 2 3 - // ['vn 1.0 2.0 3.0', '1.0', '2.0', '3.0'] +class Worker$1 {} - state.normals.push( - parseFloat(result[1]), - parseFloat(result[2]), - parseFloat(result[3]) - ); +const workerURLCache = new Map(); +function getLoadableWorkerURL(props) { + assert$4(props.source && !props.url || !props.source && props.url); + let workerURL = workerURLCache.get(props.source || props.url); - } else if (lineSecondChar === 't' && (result = regexp.uv_pattern.exec(line)) !== null) { + if (!workerURL) { + if (props.url) { + workerURL = getLoadableWorkerURLFromURL(props.url); + workerURLCache.set(props.url, workerURL); + } - // 0 1 2 - // ['vt 0.1 0.2', '0.1', '0.2'] + if (props.source) { + workerURL = getLoadableWorkerURLFromSource(props.source); + workerURLCache.set(props.source, workerURL); + } + } - state.uv.push( - parseFloat(result[1]), - parseFloat(result[2]) - ); + assert$4(workerURL); + return workerURL; +} - } else { +function getLoadableWorkerURLFromURL(url) { + if (!url.startsWith('http')) { + return url; + } - modelNode.error('Unexpected vertex/normal/uv line: \'' + line + '\''); - return; - } + const workerSource = buildScriptSource(url); + return getLoadableWorkerURLFromSource(workerSource); +} - } else if (lineFirstChar === 'f') { +function getLoadableWorkerURLFromSource(workerSource) { + const blob = new Blob([workerSource], { + type: 'application/javascript' + }); + return URL.createObjectURL(blob); +} - if ((result = regexp.face_vertex_uv_normal.exec(line)) !== null) { +function buildScriptSource(workerUrl) { + return "try {\n importScripts('".concat(workerUrl, "');\n} catch (error) {\n console.error(error);\n throw error;\n}"); +} - // f vertex/uv/normal vertex/uv/normal vertex/uv/normal - // 0 1 2 3 4 5 6 7 8 9 10 11 12 - // ['f 1/1/1 2/2/2 3/3/3', '1', '1', '1', '2', '2', '2', '3', '3', '3', undefined, undefined, undefined] +function getTransferList(object, recursive = true, transfers) { + const transfersSet = transfers || new Set(); - addFace(state, - result[1], result[4], result[7], result[10], - result[2], result[5], result[8], result[11], - result[3], result[6], result[9], result[12] - ); + if (!object) ; else if (isTransferable(object)) { + transfersSet.add(object); + } else if (isTransferable(object.buffer)) { + transfersSet.add(object.buffer); + } else if (ArrayBuffer.isView(object)) ; else if (recursive && typeof object === 'object') { + for (const key in object) { + getTransferList(object[key], recursive, transfersSet); + } + } - } else if ((result = regexp.face_vertex_uv.exec(line)) !== null) { + return transfers === undefined ? Array.from(transfersSet) : []; +} - // f vertex/uv vertex/uv vertex/uv - // 0 1 2 3 4 5 6 7 8 - // ['f 1/1 2/2 3/3', '1', '1', '2', '2', '3', '3', undefined, undefined] +function isTransferable(object) { + if (!object) { + return false; + } - addFace(state, - result[1], result[3], result[5], result[7], - result[2], result[4], result[6], result[8] - ); + if (object instanceof ArrayBuffer) { + return true; + } - } else if ((result = regexp.face_vertex_normal.exec(line)) !== null) { + if (typeof MessagePort !== 'undefined' && object instanceof MessagePort) { + return true; + } - // f vertex//normal vertex//normal vertex//normal - // 0 1 2 3 4 5 6 7 8 - // ['f 1//1 2//2 3//3', '1', '1', '2', '2', '3', '3', undefined, undefined] + if (typeof ImageBitmap !== 'undefined' && object instanceof ImageBitmap) { + return true; + } - addFace(state, - result[1], result[3], result[5], result[7], - undefined, undefined, undefined, undefined, - result[2], result[4], result[6], result[8] - ); + if (typeof OffscreenCanvas !== 'undefined' && object instanceof OffscreenCanvas) { + return true; + } - } else if ((result = regexp.face_vertex.exec(line)) !== null) { + return false; +} - // f vertex vertex vertex - // 0 1 2 3 4 - // ['f 1 2 3', '1', '2', '3', undefined] +const NOOP = () => {}; - addFace(state, result[1], result[2], result[3], result[4]); - } else { - modelNode.error('Unexpected face line: \'' + line + '\''); - return; - } +class WorkerThread { + static isSupported() { + return typeof Worker !== 'undefined' && isBrowser$3 || typeof Worker$1 !== undefined; + } - } else if (lineFirstChar === 'l') { + constructor(props) { + _defineProperty(this, "name", void 0); - var lineParts = line.substring(1).trim().split(' '); - var lineVertices = [], lineUVs = []; + _defineProperty(this, "source", void 0); - if (line.indexOf('/') === -1) { + _defineProperty(this, "url", void 0); - lineVertices = lineParts; + _defineProperty(this, "terminated", false); - } else { - for (var li = 0, llen = lineParts.length; li < llen; li++) { - var parts = lineParts[li].split('/'); - if (parts[0] !== '') { - lineVertices.push(parts[0]); - } - if (parts[1] !== '') { - lineUVs.push(parts[1]); - } - } - } - addLineGeometry(state, lineVertices, lineUVs); + _defineProperty(this, "worker", void 0); - } else if ((result = regexp.object_pattern.exec(line)) !== null) { + _defineProperty(this, "onMessage", void 0); - // o object_name - // or - // g group_name + _defineProperty(this, "onError", void 0); - var id = result[0].substr(1).trim(); - startObject(state, id, true); + _defineProperty(this, "_loadableURL", ''); - } else if (regexp.material_use_pattern.test(line)) { + const { + name, + source, + url + } = props; + assert$4(source || url); + this.name = name; + this.source = source; + this.url = url; + this.onMessage = NOOP; - // material + this.onError = error => console.log(error); - var id = line.substring(7).trim(); - state.object.material.id = id; + this.worker = isBrowser$3 ? this._createBrowserWorker() : this._createNodeWorker(); + } - } else if (regexp.material_library_pattern.test(line)) { + destroy() { + this.onMessage = NOOP; + this.onError = NOOP; + this.worker.terminate(); + this.terminated = true; + } - // mtl file + get isRunning() { + return Boolean(this.onMessage); + } - state.materialLibraries[line.substring(7).trim()] = true; + postMessage(data, transferList) { + transferList = transferList || getTransferList(data); + this.worker.postMessage(data, transferList); + } - } else if ((result = regexp.smoothing_pattern.exec(line)) !== null) { + _getErrorFromErrorEvent(event) { + let message = 'Failed to load '; + message += "worker ".concat(this.name, " from ").concat(this.url, ". "); - // smooth shading + if (event.message) { + message += "".concat(event.message, " in "); + } - var value = result[1].trim().toLowerCase(); - state.object.material.smooth = (value === '1' || value === 'on'); + if (event.lineno) { + message += ":".concat(event.lineno, ":").concat(event.colno); + } - } else { + return new Error(message); + } - // Handle null terminated files without exception - if (line === '\0') { - continue; - } + _createBrowserWorker() { + this._loadableURL = getLoadableWorkerURL({ + source: this.source, + url: this.url + }); + const worker = new Worker(this._loadableURL, { + name: this.name + }); - modelNode.error('Unexpected line: \'' + line + '\''); - return; - } - } + worker.onmessage = event => { + if (!event.data) { + this.onError(new Error('No data received')); + } else { + this.onMessage(event.data); + } + }; - return state; + worker.onerror = error => { + this.onError(this._getErrorFromErrorEvent(error)); + this.terminated = true; }; - function getBasePath(src) { - var n = src.lastIndexOf('/'); - return (n === -1) ? src : src.substring(0, n + 1); - } + worker.onmessageerror = event => console.error(event); - function startObject(state, id, fromDeclaration) { - if (state.object && state.object.fromDeclaration === false) { - state.object.id = id; - state.object.fromDeclaration = (fromDeclaration !== false); - return; - } - state.object = { - id: id || '', - geometry: { - positions: [], - normals: [], - uv: [] - }, - material: { - id: '', - smooth: true - }, - fromDeclaration: (fromDeclaration !== false) - }; - state.objects.push(state.object); - } + return worker; + } - function parseVertexIndex(value, len) { - var index = parseInt(value, 10); - return (index >= 0 ? index - 1 : index + len / 3) * 3; - } + _createNodeWorker() { + let worker; - function parseNormalIndex(value, len) { - var index = parseInt(value, 10); - return (index >= 0 ? index - 1 : index + len / 3) * 3; + if (this.url) { + const absolute = this.url.includes(':/') || this.url.startsWith('/'); + const url = absolute ? this.url : "./".concat(this.url); + worker = new Worker$1(url, { + eval: false + }); + } else if (this.source) { + worker = new Worker$1(this.source, { + eval: true + }); + } else { + throw new Error('no worker'); } - function parseUVIndex(value, len) { - var index = parseInt(value, 10); - return (index >= 0 ? index - 1 : index + len / 2) * 2; - } + worker.on('message', data => { + this.onMessage(data); + }); + worker.on('error', error => { + this.onError(error); + }); + worker.on('exit', code => {}); + return worker; + } - function addVertex(state, a, b, c) { - var src = state.positions; - var dst = state.object.geometry.positions; - dst.push(src[a + 0]); - dst.push(src[a + 1]); - dst.push(src[a + 2]); - dst.push(src[b + 0]); - dst.push(src[b + 1]); - dst.push(src[b + 2]); - dst.push(src[c + 0]); - dst.push(src[c + 1]); - dst.push(src[c + 2]); - } +} - function addVertexLine(state, a) { - var src = state.positions; - var dst = state.object.geometry.positions; - dst.push(src[a + 0]); - dst.push(src[a + 1]); - dst.push(src[a + 2]); - } +class WorkerPool { + static isSupported() { + return WorkerThread.isSupported(); + } - function addNormal(state, a, b, c) { - var src = state.normals; - var dst = state.object.geometry.normals; - dst.push(src[a + 0]); - dst.push(src[a + 1]); - dst.push(src[a + 2]); - dst.push(src[b + 0]); - dst.push(src[b + 1]); - dst.push(src[b + 2]); - dst.push(src[c + 0]); - dst.push(src[c + 1]); - dst.push(src[c + 2]); - } + constructor(props) { + _defineProperty(this, "name", 'unnamed'); - function addUV(state, a, b, c) { - var src = state.uv; - var dst = state.object.geometry.uv; - dst.push(src[a + 0]); - dst.push(src[a + 1]); - dst.push(src[b + 0]); - dst.push(src[b + 1]); - dst.push(src[c + 0]); - dst.push(src[c + 1]); - } + _defineProperty(this, "source", void 0); - function addUVLine(state, a) { - var src = state.uv; - var dst = state.object.geometry.uv; - dst.push(src[a + 0]); - dst.push(src[a + 1]); - } + _defineProperty(this, "url", void 0); - function addFace(state, a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd) { - var vLen = state.positions.length; - var ia = parseVertexIndex(a, vLen); - var ib = parseVertexIndex(b, vLen); - var ic = parseVertexIndex(c, vLen); - var id; - if (d === undefined) { - addVertex(state, ia, ib, ic); + _defineProperty(this, "maxConcurrency", 1); - } else { - id = parseVertexIndex(d, vLen); - addVertex(state, ia, ib, id); - addVertex(state, ib, ic, id); - } + _defineProperty(this, "maxMobileConcurrency", 1); - if (ua !== undefined) { + _defineProperty(this, "onDebug", () => {}); - var uvLen = state.uv.length; + _defineProperty(this, "reuseWorkers", true); - ia = parseUVIndex(ua, uvLen); - ib = parseUVIndex(ub, uvLen); - ic = parseUVIndex(uc, uvLen); + _defineProperty(this, "props", {}); - if (d === undefined) { - addUV(state, ia, ib, ic); + _defineProperty(this, "jobQueue", []); - } else { - id = parseUVIndex(ud, uvLen); - addUV(state, ia, ib, id); - addUV(state, ib, ic, id); - } - } + _defineProperty(this, "idleQueue", []); - if (na !== undefined) { + _defineProperty(this, "count", 0); - // Normals are many times the same. If so, skip function call and parseInt. + _defineProperty(this, "isDestroyed", false); - var nLen = state.normals.length; + this.source = props.source; + this.url = props.url; + this.setProps(props); + } - ia = parseNormalIndex(na, nLen); - ib = na === nb ? ia : parseNormalIndex(nb, nLen); - ic = na === nc ? ia : parseNormalIndex(nc, nLen); + destroy() { + this.idleQueue.forEach(worker => worker.destroy()); + this.isDestroyed = true; + } - if (d === undefined) { - addNormal(state, ia, ib, ic); + setProps(props) { + this.props = { ...this.props, + ...props + }; - } else { + if (props.name !== undefined) { + this.name = props.name; + } - id = parseNormalIndex(nd, nLen); - addNormal(state, ia, ib, id); - addNormal(state, ib, ic, id); - } - } + if (props.maxConcurrency !== undefined) { + this.maxConcurrency = props.maxConcurrency; } - function addLineGeometry(state, positions, uv) { + if (props.maxMobileConcurrency !== undefined) { + this.maxMobileConcurrency = props.maxMobileConcurrency; + } - state.object.geometry.type = 'Line'; + if (props.reuseWorkers !== undefined) { + this.reuseWorkers = props.reuseWorkers; + } - var vLen = state.positions.length; - var uvLen = state.uv.length; + if (props.onDebug !== undefined) { + this.onDebug = props.onDebug; + } + } - for (var vi = 0, l = positions.length; vi < l; vi++) { - addVertexLine(state, parseVertexIndex(positions[vi], vLen)); - } + async startJob(name, onMessage = (job, type, data) => job.done(data), onError = (job, error) => job.error(error)) { + const startPromise = new Promise(onStart => { + this.jobQueue.push({ + name, + onMessage, + onError, + onStart + }); + return this; + }); - for (var uvi = 0, uvl = uv.length; uvi < uvl; uvi++) { - addUVLine(state, parseUVIndex(uv[uvi], uvLen)); - } - } -})(); + this._startQueuedJob(); -//-------------------------------------------------------------------------------------------- -// Loads MTL files listed in parsed state -//-------------------------------------------------------------------------------------------- + return await startPromise; + } -function loadMTLs(modelNode, state, ok) { - var basePath = state.basePath; - var srcList = Object.keys(state.materialLibraries); - var numToLoad = srcList.length; - for (var i = 0, len = numToLoad; i < len; i++) { - loadMTL(modelNode, basePath, basePath + srcList[i], function () { - if (--numToLoad === 0) { - ok(); - } - }); + async _startQueuedJob() { + if (!this.jobQueue.length) { + return; } -} -//-------------------------------------------------------------------------------------------- -// Loads an MTL file -//-------------------------------------------------------------------------------------------- + const workerThread = this._getAvailableWorker(); -var loadMTL = function (modelNode, basePath, src, ok) { - loadFile(src, function (text) { - parseMTL(modelNode, text, basePath); - ok(); - }, - function (error) { - modelNode.error(error); - ok(); - }); -}; + if (!workerThread) { + return; + } -var parseMTL = (function () { + const queuedJob = this.jobQueue.shift(); - var delimiter_pattern = /\s+/; + if (queuedJob) { + this.onDebug({ + message: 'Starting job', + name: queuedJob.name, + workerThread, + backlog: this.jobQueue.length + }); + const job = new WorkerJob(queuedJob.name, workerThread); - return function (modelNode, mtlText, basePath) { + workerThread.onMessage = data => queuedJob.onMessage(job, data.type, data.payload); - var lines = mtlText.split('\n'); - var materialCfg = { - id: "Default" - }; - var needCreate = false; - var line; - var pos; - var key; - var value; - var alpha; + workerThread.onError = error => queuedJob.onError(job, error); - basePath = basePath || ""; + queuedJob.onStart(job); - for (var i = 0; i < lines.length; i++) { + try { + await job.result; + } finally { + this.returnWorkerToQueue(workerThread); + } + } + } - line = lines[i].trim(); + returnWorkerToQueue(worker) { + const shouldDestroyWorker = this.isDestroyed || !this.reuseWorkers || this.count > this._getMaxConcurrency(); - if (line.length === 0 || line.charAt(0) === '#') { // Blank line or comment ignore - continue; - } + if (shouldDestroyWorker) { + worker.destroy(); + this.count--; + } else { + this.idleQueue.push(worker); + } - pos = line.indexOf(' '); + if (!this.isDestroyed) { + this._startQueuedJob(); + } + } - key = (pos >= 0) ? line.substring(0, pos) : line; - key = key.toLowerCase(); + _getAvailableWorker() { + if (this.idleQueue.length > 0) { + return this.idleQueue.shift() || null; + } - value = (pos >= 0) ? line.substring(pos + 1) : ''; - value = value.trim(); + if (this.count < this._getMaxConcurrency()) { + this.count++; + const name = "".concat(this.name.toLowerCase(), " (#").concat(this.count, " of ").concat(this.maxConcurrency, ")"); + return new WorkerThread({ + name, + source: this.source, + url: this.url + }); + } - switch (key.toLowerCase()) { + return null; + } - case "newmtl": // New material - //if (needCreate) { - createMaterial(modelNode, materialCfg); - //} - materialCfg = { - id: value - }; - needCreate = true; - break; + _getMaxConcurrency() { + return isMobile ? this.maxMobileConcurrency : this.maxConcurrency; + } - case 'ka': - materialCfg.ambient = parseRGB(value); - break; +} - case 'kd': - materialCfg.diffuse = parseRGB(value); - break; +const DEFAULT_PROPS = { + maxConcurrency: 3, + maxMobileConcurrency: 1, + reuseWorkers: true, + onDebug: () => {} +}; +class WorkerFarm { + static isSupported() { + return WorkerThread.isSupported(); + } - case 'ks': - materialCfg.specular = parseRGB(value); - break; + static getWorkerFarm(props = {}) { + WorkerFarm._workerFarm = WorkerFarm._workerFarm || new WorkerFarm({}); - case 'map_kd': - if (!materialCfg.diffuseMap) { - materialCfg.diffuseMap = createTexture(modelNode, basePath, value, "sRGB"); - } - break; + WorkerFarm._workerFarm.setProps(props); - case 'map_ks': - if (!materialCfg.specularMap) { - materialCfg.specularMap = createTexture(modelNode, basePath, value, "linear"); - } - break; + return WorkerFarm._workerFarm; + } - case 'map_bump': - case 'bump': - if (!materialCfg.normalMap) { - materialCfg.normalMap = createTexture(modelNode, basePath, value); - } - break; + constructor(props) { + _defineProperty(this, "props", void 0); - case 'ns': - materialCfg.shininess = parseFloat(value); - break; + _defineProperty(this, "workerPools", new Map()); - case 'd': - alpha = parseFloat(value); - if (alpha < 1) { - materialCfg.alpha = alpha; - materialCfg.alphaMode = "blend"; - } - break; + this.props = { ...DEFAULT_PROPS + }; + this.setProps(props); + this.workerPools = new Map(); + } - case 'tr': - alpha = parseFloat(value); - if (alpha > 0) { - materialCfg.alpha = 1 - alpha; - materialCfg.alphaMode = "blend"; - } - break; - // modelNode.error("Unrecognized token: " + key); - } - } + destroy() { + for (const workerPool of this.workerPools.values()) { + workerPool.destroy(); + } - if (needCreate) { - createMaterial(modelNode, materialCfg); - } + this.workerPools = new Map(); + } + + setProps(props) { + this.props = { ...this.props, + ...props }; - function createTexture(modelNode, basePath, value, encoding) { - var textureCfg = {}; - var items = value.split(/\s+/); - var pos = items.indexOf('-bm'); - if (pos >= 0) { - //matParams.bumpScale = parseFloat(items[pos + 1]); - items.splice(pos, 2); - } - pos = items.indexOf('-s'); - if (pos >= 0) { - textureCfg.scale = [parseFloat(items[pos + 1]), parseFloat(items[pos + 2])]; - items.splice(pos, 4); // we expect 3 parameters here! - } - pos = items.indexOf('-o'); - if (pos >= 0) { - textureCfg.translate = [parseFloat(items[pos + 1]), parseFloat(items[pos + 2])]; - items.splice(pos, 4); // we expect 3 parameters here! - } - textureCfg.src = basePath + items.join(' ').trim(); - textureCfg.flipY = true; - textureCfg.encoding = encoding || "linear"; - //textureCfg.wrapS = self.wrap; - //textureCfg.wrapT = self.wrap; - var texture = new Texture(modelNode, textureCfg); - return texture.id; + for (const workerPool of this.workerPools.values()) { + workerPool.setProps(this._getWorkerPoolProps()); } + } - function createMaterial(modelNode, materialCfg) { - new PhongMaterial(modelNode, materialCfg); - } + getWorkerPool(options) { + const { + name, + source, + url + } = options; + let workerPool = this.workerPools.get(name); - function parseRGB(value) { - var ss = value.split(delimiter_pattern, 3); - return [parseFloat(ss[0]), parseFloat(ss[1]), parseFloat(ss[2])]; + if (!workerPool) { + workerPool = new WorkerPool({ + name, + source, + url + }); + workerPool.setProps(this._getWorkerPoolProps()); + this.workerPools.set(name, workerPool); } -})(); -//-------------------------------------------------------------------------------------------- -// Creates meshes from parsed state -//-------------------------------------------------------------------------------------------- - + return workerPool; + } -function createMeshes(modelNode, state) { + _getWorkerPoolProps() { + return { + maxConcurrency: this.props.maxConcurrency, + maxMobileConcurrency: this.props.maxMobileConcurrency, + reuseWorkers: this.props.reuseWorkers, + onDebug: this.props.onDebug + }; + } - for (var j = 0, k = state.objects.length; j < k; j++) { +} - var object = state.objects[j]; - var geometry = object.geometry; - (geometry.type === 'Line'); +_defineProperty(WorkerFarm, "_workerFarm", void 0); - if (geometry.positions.length === 0) { - // Skip o/g line declarations that did not follow with any faces - continue; - } +const NPM_TAG = 'latest'; +function getWorkerURL(worker, options = {}) { + const workerOptions = options[worker.id] || {}; + const workerFile = "".concat(worker.id, "-worker.js"); + let url = workerOptions.workerUrl; - var geometryCfg = { - primitive: "triangles", - compressGeometry: false - }; + if (!url && worker.id === 'compression') { + url = options.workerUrl; + } - geometryCfg.positions = geometry.positions; + if (options._workerType === 'test') { + url = "modules/".concat(worker.module, "/dist/").concat(workerFile); + } - if (geometry.normals.length > 0) { - geometryCfg.normals = geometry.normals; - } + if (!url) { + let version = worker.version; - if (geometry.uv.length > 0) { - geometryCfg.uv = geometry.uv; - } + if (version === 'latest') { + version = NPM_TAG; + } - var indices = new Array(geometryCfg.positions.length / 3); // Triangle soup - for (var idx = 0; idx < indices.length; idx++) { - indices[idx] = idx; - } - geometryCfg.indices = indices; + const versionTag = version ? "@".concat(version) : ''; + url = "https://unpkg.com/@loaders.gl/".concat(worker.module).concat(versionTag, "/dist/").concat(workerFile); + } - const origin = tempVec3a$8; + assert$4(url); + return url; +} - worldToRTCPositions(geometry.positions, geometry.positions, origin); +function validateWorkerVersion(worker, coreVersion = VERSION$9) { + assert$4(worker, 'no worker provided'); + const workerVersion = worker.version; - var readableGeometry = new ReadableGeometry(modelNode, geometryCfg); + if (!coreVersion || !workerVersion) { + return false; + } - var materialId = object.material.id; - var material; - if (materialId && materialId !== "") { - material = modelNode.scene.components[materialId]; - if (!material) { - modelNode.error("Material not found: " + materialId); - } - } else { - material = new PhongMaterial(modelNode, { - //emissive: [0.6, 0.6, 0.0], - diffuse: [0.6, 0.6, 0.6], - backfaces: true - }); + return true; +} - } +var ChildProcessProxy = {}; - // material.emissive = [Math.random(), Math.random(), Math.random()]; +var node = /*#__PURE__*/Object.freeze({ + __proto__: null, + 'default': ChildProcessProxy +}); - var mesh = new Mesh(modelNode, { - id: modelNode.id + "#" + object.id, - origin: (origin[0] !== 0 || origin[1] !== 0 || origin[2] !== 0) ? origin : null, - isObject: true, - geometry: readableGeometry, - material: material, - pickable: true - }); +const VERSION$8 = "3.2.6" ; +const loadLibraryPromises = {}; +async function loadLibrary(libraryUrl, moduleName = null, options = {}) { + if (moduleName) { + libraryUrl = getLibraryUrl(libraryUrl, moduleName, options); + } - modelNode.addChild(mesh); - } + loadLibraryPromises[libraryUrl] = loadLibraryPromises[libraryUrl] || loadLibraryFromFile(libraryUrl); + return await loadLibraryPromises[libraryUrl]; } +function getLibraryUrl(library, moduleName, options) { + if (library.startsWith('http')) { + return library; + } -function loadFile(url, ok, err) { - var request = new XMLHttpRequest(); - request.open('GET', url, true); - request.addEventListener('load', function (event) { - var response = event.target.response; - if (this.status === 200) { - if (ok) { - ok(response); - } - } else if (this.status === 0) { - // Some browsers return HTTP Status 0 when using non-http protocol - // e.g. 'file://' or 'data://'. Handle as success. - console.warn('loadFile: HTTP Status 0 received.'); - if (ok) { - ok(response); - } - } else { - if (err) { - err(event); - } - } - }, false); + const modules = options.modules || {}; - request.addEventListener('error', function (event) { - if (err) { - err(event); - } - }, false); - request.send(null); -} + if (modules[library]) { + return modules[library]; + } -/** - * {@link Viewer} plugin that loads models from [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file) files. - * - * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. - * * Creates an {@link Entity} for each object within the model, which will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. - * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. - * - * ## Metadata - * - * OBJLoaderPlugin can also load an accompanying JSON metadata file with each model, which creates a {@link MetaModel} corresponding - * to the model {@link Entity} and a {@link MetaObject} corresponding to each object {@link Entity}. - * - * Each {@link MetaObject} has a {@link MetaObject#type}, which indicates the classification of its corresponding {@link Entity}. When loading - * metadata, we can also provide GLTFModelLoaderPlugin with a custom lookup table of initial values to set on the properties of each type of {@link Entity}. By default, OBJLoaderPlugin - * uses its own map of standard default colors, visibilities and opacities for IFC element types. + if (!isBrowser$3) { + return "modules/".concat(moduleName, "/dist/libs/").concat(library); + } - * - * ## Usage - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#loading_OBJ_SportsCar)] - * - * ````javascript - * import {Viewer, OBJLoaderPlugin} from "xeokit-sdk.es.js"; - * - * // Create a xeokit Viewer and arrange the camera - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.orbitPitch(20); - * - * // Add an OBJLoaderPlugin to the Viewer - * const objLoader = new OBJLoaderPlugin(viewer); - * - * // Load an OBJ model - * var model = objLoader.load({ // Model is an Entity - * id: "myModel", - * src: "./models/obj/sportsCar/sportsCar.obj", - * edges: true - * }); - * - * // When the model has loaded, fit it to view - * model.on("loaded", () => { - * viewer.cameraFlight.flyTo(model); - * }) - * - * // Find the model Entity by ID - * model = viewer.scene.models["myModel"]; - * - * // Update properties of the model Entity - * model.highlight = [1,0,0]; - * - * // Destroy the model - * model.destroy(); - * ```` - * @class OBJLoaderPlugin - */ -class OBJLoaderPlugin extends Plugin { + if (options.CDN) { + assert$4(options.CDN.startsWith('http')); + return "".concat(options.CDN, "/").concat(moduleName, "@").concat(VERSION$8, "/dist/libs/").concat(library); + } - /** - * @constructor - * - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="OBJLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - */ - constructor(viewer, cfg) { + if (isWorker) { + return "../src/libs/".concat(library); + } - super("OBJLoader", viewer, cfg); + return "modules/".concat(moduleName, "/src/libs/").concat(library); +} - /** - * @private - */ - this._sceneGraphLoader = new OBJSceneGraphLoader(); +async function loadLibraryFromFile(libraryUrl) { + if (libraryUrl.endsWith('wasm')) { + const response = await fetch(libraryUrl); + return await response.arrayBuffer(); + } + + if (!isBrowser$3) { + try { + return node && undefined && (await undefined(libraryUrl)); + } catch { + return null; } + } - /** - * Loads an OBJ model from a file into this OBJLoader's {@link Viewer}. - * - * @param {*} params Loading parameters. - * @param {String} params.id ID to assign to the model's root {@link Entity}, unique among all components in the Viewer's {@link Scene}. - * @param {String} params.src Path to an OBJ file. - * @param {String} [params.metaModelSrc] Path to an optional metadata file. - * @param {Number[]} [params.position=[0,0,0]] The model World-space 3D position. - * @param {Number[]} [params.scale=[1,1,1]] The model's World-space scale. - * @param {Number[]} [params.rotation=[0,0,0]] The model's World-space rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. - * @param {Number} [params.edgeThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. - * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} - */ - load(params = {}) { + if (isWorker) { + return importScripts(libraryUrl); + } - if (params.id && this.viewer.scene.components[params.id]) { - this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); - delete params.id; - } + const response = await fetch(libraryUrl); + const scriptSource = await response.text(); + return loadLibraryFromString(scriptSource, libraryUrl); +} - var modelNode = new Node$1(this.viewer.scene, utils.apply(params, { - isModel: true - })); +function loadLibraryFromString(scriptSource, id) { + if (!isBrowser$3) { + return undefined ; + } - const modelId = modelNode.id; // In case ID was auto-generated - const src = params.src; + if (isWorker) { + eval.call(global_, scriptSource); + return null; + } - if (!src) { - this.error("load() param expected: src"); - return modelNode; - } + const script = document.createElement('script'); + script.id = id; - if (params.metaModelSrc) { - const metaModelSrc = params.metaModelSrc; - utils.loadJSON(metaModelSrc, - (modelMetadata) => { - this.viewer.metaScene.createMetaModel(modelId, modelMetadata); - this._sceneGraphLoader.load(modelNode, src, params); - }, - (errMsg) => { - this.error(`load(): Failed to load model modelMetadata for model '${modelId} from '${metaModelSrc}' - ${errMsg}`); - }); - } else { - this._sceneGraphLoader.load(modelNode, src, params); - } + try { + script.appendChild(document.createTextNode(scriptSource)); + } catch (e) { + script.text = scriptSource; + } - modelNode.once("destroyed", () => { - this.viewer.metaScene.destroyMetaModel(modelId); - }); + document.body.appendChild(script); + return null; +} - return modelNode; - } +function canParseWithWorker(loader, options) { + if (!WorkerFarm.isSupported()) { + return false; + } - /** - * Destroys this OBJLoaderPlugin. - */ - destroy() { - super.destroy(); - } -} + if (!isBrowser$3 && !(options !== null && options !== void 0 && options._nodeWorkers)) { + return false; + } -/** - * @desc Creates a torus-shaped {@link Geometry}. - * - * ## Usage - * Creating a {@link Mesh} with a torus-shaped {@link ReadableGeometry} : - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildTorusGeometry)] - * - * ````javascript - * import {Viewer, Mesh, buildTorusGeometry, ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [0, 0, 5]; - * viewer.camera.look = [0, 0, 0]; - * viewer.camera.up = [0, 1, 0]; - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ - * center: [0,0,0], - * radius: 1.0, - * tube: 0.5, - * radialSegments: 32, - * tubeSegments: 24, - * arc: Math.PI * 2.0 - * }), - * material: new PhongMaterial(viewer.scene, { - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }) - * }) - * }); - * ```` - * - * @function buildTorusGeometry - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for the {@link Geometry}, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number[]} [cfg.center] 3D point indicating the center position. - * @param {Number} [cfg.radius=1] The overall radius. - * @param {Number} [cfg.tube=0.3] The tube radius. - * @param {Number} [cfg.radialSegments=32] The number of radial segments. - * @param {Number} [cfg.tubeSegments=24] The number of tubular segments. - * @param {Number} [cfg.arc=Math.PI*0.5] The length of the arc in radians, where Math.PI*2 is a closed torus. - * @returns {Object} Configuration for a {@link Geometry} subtype. - */ -function buildTorusGeometry(cfg = {}) { + return loader.worker && (options === null || options === void 0 ? void 0 : options.worker); +} +async function parseWithWorker(loader, data, options, context, parseOnMainThread) { + const name = loader.id; + const url = getWorkerURL(loader, options); + const workerFarm = WorkerFarm.getWorkerFarm(options); + const workerPool = workerFarm.getWorkerPool({ + name, + url + }); + options = JSON.parse(JSON.stringify(options)); + context = JSON.parse(JSON.stringify(context || {})); + const job = await workerPool.startJob('process-on-worker', onMessage.bind(null, parseOnMainThread)); + job.postMessage('process', { + input: data, + options, + context + }); + const result = await job.result; + return await result.result; +} - let radius = cfg.radius || 1; - if (radius < 0) { - console.error("negative radius not allowed - will invert"); - radius *= -1; - } - radius *= 0.5; +async function onMessage(parseOnMainThread, job, type, payload) { + switch (type) { + case 'done': + job.done(payload); + break; - let tube = cfg.tube || 0.3; - if (tube < 0) { - console.error("negative tube not allowed - will invert"); - tube *= -1; - } + case 'error': + job.error(new Error(payload.error)); + break; - let radialSegments = cfg.radialSegments || 32; - if (radialSegments < 0) { - console.error("negative radialSegments not allowed - will invert"); - radialSegments *= -1; - } - if (radialSegments < 4) { - radialSegments = 4; - } + case 'process': + const { + id, + input, + options + } = payload; - let tubeSegments = cfg.tubeSegments || 24; - if (tubeSegments < 0) { - console.error("negative tubeSegments not allowed - will invert"); - tubeSegments *= -1; - } - if (tubeSegments < 4) { - tubeSegments = 4; - } + try { + const result = await parseOnMainThread(input, options); + job.postMessage('done', { + id, + result + }); + } catch (error) { + const message = error instanceof Error ? error.message : 'unknown error'; + job.postMessage('error', { + id, + error: message + }); + } - let arc = cfg.arc || Math.PI * 2; - if (arc < 0) { - console.warn("negative arc not allowed - will invert"); - arc *= -1; - } - if (arc > 360) { - arc = 360; - } + break; - const center = cfg.center; - let centerX = center ? center[0] : 0; - let centerY = center ? center[1] : 0; - const centerZ = center ? center[2] : 0; + default: + console.warn("parse-with-worker unknown message ".concat(type)); + } +} - const positions = []; - const normals = []; - const uvs = []; - const indices = []; +function getFirstCharacters$1(data, length = 5) { + if (typeof data === 'string') { + return data.slice(0, length); + } else if (ArrayBuffer.isView(data)) { + return getMagicString$2(data.buffer, data.byteOffset, length); + } else if (data instanceof ArrayBuffer) { + const byteOffset = 0; + return getMagicString$2(data, byteOffset, length); + } - let u; - let v; - let x; - let y; - let z; - let vec; + return ''; +} +function getMagicString$2(arrayBuffer, byteOffset, length) { + if (arrayBuffer.byteLength <= byteOffset + length) { + return ''; + } - let i; - let j; + const dataView = new DataView(arrayBuffer); + let magic = ''; - for (j = 0; j <= tubeSegments; j++) { - for (i = 0; i <= radialSegments; i++) { + for (let i = 0; i < length; i++) { + magic += String.fromCharCode(dataView.getUint8(byteOffset + i)); + } - u = i / radialSegments * arc; - v = 0.785398 + (j / tubeSegments * Math.PI * 2); + return magic; +} - centerX = radius * Math.cos(u); - centerY = radius * Math.sin(u); +function parseJSON(string) { + try { + return JSON.parse(string); + } catch (_) { + throw new Error("Failed to parse JSON from data starting with \"".concat(getFirstCharacters$1(string), "\"")); + } +} - x = (radius + tube * Math.cos(v)) * Math.cos(u); - y = (radius + tube * Math.cos(v)) * Math.sin(u); - z = tube * Math.sin(v); +function isBuffer$1(value) { + return value && typeof value === 'object' && value.isBuffer; +} +function bufferToArrayBuffer(buffer) { + if (isBuffer$1(buffer)) { + const typedArray = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.length); + return typedArray.slice().buffer; + } - positions.push(x + centerX); - positions.push(y + centerY); - positions.push(z + centerZ); + return buffer; +} - uvs.push(1 - (i / radialSegments)); - uvs.push((j / tubeSegments)); +function toArrayBuffer(data) { + if (isBuffer$1(data)) { + return bufferToArrayBuffer(data); + } - vec = math.normalizeVec3(math.subVec3([x, y, z], [centerX, centerY, centerZ], []), []); + if (data instanceof ArrayBuffer) { + return data; + } - normals.push(vec[0]); - normals.push(vec[1]); - normals.push(vec[2]); - } + if (ArrayBuffer.isView(data)) { + if (data.byteOffset === 0 && data.byteLength === data.buffer.byteLength) { + return data.buffer; } - let a; - let b; - let c; - let d; + return data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength); + } - for (j = 1; j <= tubeSegments; j++) { - for (i = 1; i <= radialSegments; i++) { + if (typeof data === 'string') { + const text = data; + const uint8Array = new TextEncoder().encode(text); + return uint8Array.buffer; + } - a = (radialSegments + 1) * j + i - 1; - b = (radialSegments + 1) * (j - 1) + i - 1; - c = (radialSegments + 1) * (j - 1) + i; - d = (radialSegments + 1) * j + i; + if (data && typeof data === 'object' && data._toArrayBuffer) { + return data._toArrayBuffer(); + } - indices.push(a); - indices.push(b); - indices.push(c); + throw new Error('toArrayBuffer'); +} +function compareArrayBuffers(arrayBuffer1, arrayBuffer2, byteLength) { + byteLength = byteLength || arrayBuffer1.byteLength; - indices.push(c); - indices.push(d); - indices.push(a); - } + if (arrayBuffer1.byteLength < byteLength || arrayBuffer2.byteLength < byteLength) { + return false; + } + + const array1 = new Uint8Array(arrayBuffer1); + const array2 = new Uint8Array(arrayBuffer2); + + for (let i = 0; i < array1.length; ++i) { + if (array1[i] !== array2[i]) { + return false; } + } - return utils.apply(cfg, { - positions: positions, - normals: normals, - uv: uvs, - indices: indices - }); + return true; } +function concatenateArrayBuffers(...sources) { + const sourceArrays = sources.map(source2 => source2 instanceof ArrayBuffer ? new Uint8Array(source2) : source2); + const byteLength = sourceArrays.reduce((length, typedArray) => length + typedArray.byteLength, 0); + const result = new Uint8Array(byteLength); + let offset = 0; -const zeroVec$1 = new Float64Array([0, 0, 1]); -const quat = new Float64Array(4); + for (const sourceArray of sourceArrays) { + result.set(sourceArray, offset); + offset += sourceArray.byteLength; + } -/** - * Controls a {@link SectionPlane} with mouse and touch input. - * - * @private - */ -class Control { + return result.buffer; +} +function sliceArrayBuffer(arrayBuffer, byteOffset, byteLength) { + const subArray = byteLength !== undefined ? new Uint8Array(arrayBuffer).subarray(byteOffset, byteOffset + byteLength) : new Uint8Array(arrayBuffer).subarray(byteOffset); + const arrayCopy = new Uint8Array(subArray); + return arrayCopy.buffer; +} - /** @private */ - constructor(plugin) { +function padToNBytes(byteLength, padding) { + assert$5(byteLength >= 0); + assert$5(padding > 0); + return byteLength + (padding - 1) & ~(padding - 1); +} +function copyToArray(source, target, targetOffset) { + let sourceArray; - /** - * ID of this Control. - * - * SectionPlaneControls are mapped by this ID in {@link SectionPlanesPlugin#sectionPlaneControls}. - * - * @property id - * @type {String|Number} - */ - this.id = null; + if (source instanceof ArrayBuffer) { + sourceArray = new Uint8Array(source); + } else { + const srcByteOffset = source.byteOffset; + const srcByteLength = source.byteLength; + sourceArray = new Uint8Array(source.buffer || source.arrayBuffer, srcByteOffset, srcByteLength); + } - this._viewer = plugin.viewer; + target.set(sourceArray, targetOffset); + return targetOffset + padToNBytes(sourceArray.byteLength, 4); +} - this._visible = false; - this._pos = math.vec3(); // Full-precision position of the center of the Control - this._origin = math.vec3(); - this._rtcPos = math.vec3(); +async function concatenateArrayBuffersAsync(asyncIterator) { + const arrayBuffers = []; - this._baseDir = math.vec3(); // Saves direction of clip plane when we start dragging an arrow or ring. - this._rootNode = null; // Root of Node graph that represents this control in the 3D scene - this._displayMeshes = null; // Meshes that are always visible - this._affordanceMeshes = null; // Meshes displayed momentarily for affordance + for await (const chunk of asyncIterator) { + arrayBuffers.push(chunk); + } - this._ignoreNextSectionPlaneDirUpdate = false; + return concatenateArrayBuffers(...arrayBuffers); +} - this._createNodes(); - this._bindEvents(); +let pathPrefix = ''; +const fileAliases = {}; +function resolvePath(filename) { + for (const alias in fileAliases) { + if (filename.startsWith(alias)) { + const replacement = fileAliases[alias]; + filename = filename.replace(alias, replacement); } + } - /** - * Called by SectionPlanesPlugin to assign this Control to a SectionPlane. - * SectionPlanesPlugin keeps SectionPlaneControls in a reuse pool. - * Call with a null or undefined value to disconnect the Control ffrom whatever SectionPlane it was assigned to. - * @private - */ - _setSectionPlane(sectionPlane) { - if (this._sectionPlane) { - this._sectionPlane.off(this._onSectionPlanePos); - this._sectionPlane.off(this._onSectionPlaneDir); - this._onSectionPlanePos = null; - this._onSectionPlaneDir = null; - this._sectionPlane = null; - } - if (sectionPlane) { - this.id = sectionPlane.id; - this._setPos(sectionPlane.pos); - this._setDir(sectionPlane.dir); - this._sectionPlane = sectionPlane; - this._onSectionPlanePos = sectionPlane.on("pos", () => { - this._setPos(this._sectionPlane.pos); - }); - this._onSectionPlaneDir = sectionPlane.on("dir", () => { - if (!this._ignoreNextSectionPlaneDirUpdate) { - this._setDir(this._sectionPlane.dir); - } else { - this._ignoreNextSectionPlaneDirUpdate = false; - } - }); - } - } + if (!filename.startsWith('http://') && !filename.startsWith('https://')) { + filename = "".concat(pathPrefix).concat(filename); + } - /** - * Gets the {@link SectionPlane} controlled by this Control. - * @returns {SectionPlane} The SectionPlane. - */ - get sectionPlane() { - return this._sectionPlane; - } + return filename; +} - /** @private */ - _setPos(xyz) { +function filename(url) { + const slashIndex = url && url.lastIndexOf('/'); + return slashIndex >= 0 ? url.substr(slashIndex + 1) : ''; +} - this._pos.set(xyz); +const isBoolean = x => typeof x === 'boolean'; - worldToRTCPos(this._pos, this._origin, this._rtcPos); +const isFunction = x => typeof x === 'function'; - this._rootNode.origin = this._origin; - this._rootNode.position = this._rtcPos; - } +const isObject = x => x !== null && typeof x === 'object'; +const isPureObject = x => isObject(x) && x.constructor === {}.constructor; +const isIterable = x => x && typeof x[Symbol.iterator] === 'function'; +const isAsyncIterable = x => x && typeof x[Symbol.asyncIterator] === 'function'; +const isResponse = x => typeof Response !== 'undefined' && x instanceof Response || x && x.arrayBuffer && x.text && x.json; +const isBlob = x => typeof Blob !== 'undefined' && x instanceof Blob; +const isBuffer = x => x && typeof x === 'object' && x.isBuffer; +const isReadableDOMStream = x => typeof ReadableStream !== 'undefined' && x instanceof ReadableStream || isObject(x) && isFunction(x.tee) && isFunction(x.cancel) && isFunction(x.getReader); +const isReadableNodeStream = x => isObject(x) && isFunction(x.read) && isFunction(x.pipe) && isBoolean(x.readable); +const isReadableStream = x => isReadableDOMStream(x) || isReadableNodeStream(x); - /** @private */ - _setDir(xyz) { - this._baseDir.set(xyz); - this._rootNode.quaternion = math.vec3PairToQuaternion(zeroVec$1, xyz, quat); - } +const DATA_URL_PATTERN = /^data:([-\w.]+\/[-\w.+]+)(;|,)/; +const MIME_TYPE_PATTERN = /^([-\w.]+\/[-\w.+]+)/; +function parseMIMEType(mimeString) { + const matches = MIME_TYPE_PATTERN.exec(mimeString); - _setSectionPlaneDir(dir) { - if (this._sectionPlane) { - this._ignoreNextSectionPlaneDirUpdate = true; - this._sectionPlane.dir = dir; - } - } + if (matches) { + return matches[1]; + } - /** - * Sets if this Control is visible. - * - * @type {Boolean} - */ - setVisible(visible = true) { - if (this._visible === visible) { - return; - } - this._visible = visible; - var id; - for (id in this._displayMeshes) { - if (this._displayMeshes.hasOwnProperty(id)) { - this._displayMeshes[id].visible = visible; - } - } - if (!visible) { - for (id in this._affordanceMeshes) { - if (this._affordanceMeshes.hasOwnProperty(id)) { - this._affordanceMeshes[id].visible = visible; - } - } - } - } + return mimeString; +} +function parseMIMETypeFromURL(url) { + const matches = DATA_URL_PATTERN.exec(url); - /** - * Gets if this Control is visible. - * - * @type {Boolean} - */ - getVisible() { - return this._visible; - } + if (matches) { + return matches[1]; + } - /** - * Sets if this Control is culled. This is called by SectionPlanesPlugin to - * temporarily hide the Control while a snapshot is being taken by Viewer#getSnapshot(). - * @param culled - */ - setCulled(culled) { - var id; - for (id in this._displayMeshes) { - if (this._displayMeshes.hasOwnProperty(id)) { - this._displayMeshes[id].culled = culled; - } - } - if (!culled) { - for (id in this._affordanceMeshes) { - if (this._affordanceMeshes.hasOwnProperty(id)) { - this._affordanceMeshes[id].culled = culled; - } - } - } - } + return ''; +} - /** - * Builds the Entities that represent this Control. - * @private - */ - _createNodes() { +const QUERY_STRING_PATTERN = /\?.*/; +function getResourceUrlAndType(resource) { + if (isResponse(resource)) { + const url = stripQueryString(resource.url || ''); + const contentTypeHeader = resource.headers.get('content-type') || ''; + return { + url, + type: parseMIMEType(contentTypeHeader) || parseMIMETypeFromURL(url) + }; + } - const NO_STATE_INHERIT = false; - const scene = this._viewer.scene; - const radius = 1.0; - const handleTubeRadius = 0.06; - const hoopRadius = radius - 0.2; - const tubeRadius = 0.01; - const arrowRadius = 0.07; + if (isBlob(resource)) { + return { + url: stripQueryString(resource.name || ''), + type: resource.type || '' + }; + } - this._rootNode = new Node$1(scene, { - position: [0, 0, 0], - scale: [5, 5, 5] - }); + if (typeof resource === 'string') { + return { + url: stripQueryString(resource), + type: parseMIMETypeFromURL(resource) + }; + } - const rootNode = this._rootNode; + return { + url: '', + type: '' + }; +} +function getResourceContentLength(resource) { + if (isResponse(resource)) { + return resource.headers['content-length'] || -1; + } - const shapes = {// Reusable geometries + if (isBlob(resource)) { + return resource.size; + } - arrowHead: new ReadableGeometry(rootNode, buildCylinderGeometry({ - radiusTop: 0.001, - radiusBottom: arrowRadius, - radialSegments: 32, - heightSegments: 1, - height: 0.2, - openEnded: false - })), + if (typeof resource === 'string') { + return resource.length; + } - arrowHeadBig: new ReadableGeometry(rootNode, buildCylinderGeometry({ - radiusTop: 0.001, - radiusBottom: 0.09, - radialSegments: 32, - heightSegments: 1, - height: 0.25, - openEnded: false - })), + if (resource instanceof ArrayBuffer) { + return resource.byteLength; + } - arrowHeadHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({ - radiusTop: 0.09, - radiusBottom: 0.09, - radialSegments: 8, - heightSegments: 1, - height: 0.37, - openEnded: false - })), + if (ArrayBuffer.isView(resource)) { + return resource.byteLength; + } - curve: new ReadableGeometry(rootNode, buildTorusGeometry({ - radius: hoopRadius, - tube: tubeRadius, - radialSegments: 64, - tubeSegments: 14, - arc: (Math.PI * 2.0) / 4.0 - })), + return -1; +} - curveHandle: new ReadableGeometry(rootNode, buildTorusGeometry({ - radius: hoopRadius, - tube: handleTubeRadius, - radialSegments: 64, - tubeSegments: 14, - arc: (Math.PI * 2.0) / 4.0 - })), +function stripQueryString(url) { + return url.replace(QUERY_STRING_PATTERN, ''); +} - hoop: new ReadableGeometry(rootNode, buildTorusGeometry({ - radius: hoopRadius, - tube: tubeRadius, - radialSegments: 64, - tubeSegments: 8, - arc: (Math.PI * 2.0) - })), +async function makeResponse(resource) { + if (isResponse(resource)) { + return resource; + } - axis: new ReadableGeometry(rootNode, buildCylinderGeometry({ - radiusTop: tubeRadius, - radiusBottom: tubeRadius, - radialSegments: 20, - heightSegments: 1, - height: radius, - openEnded: false - })), + const headers = {}; + const contentLength = getResourceContentLength(resource); - axisHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({ - radiusTop: 0.08, - radiusBottom: 0.08, - radialSegments: 20, - heightSegments: 1, - height: radius, - openEnded: false - })) - }; + if (contentLength >= 0) { + headers['content-length'] = String(contentLength); + } - const materials = { // Reusable materials + const { + url, + type + } = getResourceUrlAndType(resource); - pickable: new PhongMaterial(rootNode, { // Invisible material for pickable handles, which define a pickable 3D area - diffuse: [1, 1, 0], - alpha: 0, // Invisible - alphaMode: "blend" - }), + if (type) { + headers['content-type'] = type; + } - red: new PhongMaterial(rootNode, { - diffuse: [1, 0.0, 0.0], - emissive: [1, 0.0, 0.0], - ambient: [0.0, 0.0, 0.0], - specular: [.6, .6, .3], - shininess: 80, - lineWidth: 2 - }), + const initialDataUrl = await getInitialDataUrl(resource); - highlightRed: new EmphasisMaterial(rootNode, { // Emphasis for red rotation affordance hoop - edges: false, - fill: true, - fillColor: [1, 0, 0], - fillAlpha: 0.6 - }), + if (initialDataUrl) { + headers['x-first-bytes'] = initialDataUrl; + } - green: new PhongMaterial(rootNode, { - diffuse: [0.0, 1, 0.0], - emissive: [0.0, 1, 0.0], - ambient: [0.0, 0.0, 0.0], - specular: [.6, .6, .3], - shininess: 80, - lineWidth: 2 - }), + if (typeof resource === 'string') { + resource = new TextEncoder().encode(resource); + } - highlightGreen: new EmphasisMaterial(rootNode, { // Emphasis for green rotation affordance hoop - edges: false, - fill: true, - fillColor: [0, 1, 0], - fillAlpha: 0.6 - }), + const response = new Response(resource, { + headers + }); + Object.defineProperty(response, 'url', { + value: url + }); + return response; +} +async function checkResponse(response) { + if (!response.ok) { + const message = await getResponseError(response); + throw new Error(message); + } +} - blue: new PhongMaterial(rootNode, { - diffuse: [0.0, 0.0, 1], - emissive: [0.0, 0.0, 1], - ambient: [0.0, 0.0, 0.0], - specular: [.6, .6, .3], - shininess: 80, - lineWidth: 2 - }), +async function getResponseError(response) { + let message = "Failed to fetch resource ".concat(response.url, " (").concat(response.status, "): "); - highlightBlue: new EmphasisMaterial(rootNode, { // Emphasis for blue rotation affordance hoop - edges: false, - fill: true, - fillColor: [0, 0, 1], - fillAlpha: 0.2 - }), + try { + const contentType = response.headers.get('Content-Type'); + let text = response.statusText; - center: new PhongMaterial(rootNode, { - diffuse: [0.0, 0.0, 0.0], - emissive: [0, 0, 0], - ambient: [0.0, 0.0, 0.0], - specular: [.6, .6, .3], - shininess: 80 - }), + if (contentType.includes('application/json')) { + text += " ".concat(await response.text()); + } - highlightBall: new EmphasisMaterial(rootNode, { - edges: false, - fill: true, - fillColor: [0.5, 0.5, 0.5], - fillAlpha: 0.5, - vertices: false - }), + message += text; + message = message.length > 60 ? "".concat(message.slice(0, 60), "...") : message; + } catch (error) {} - highlightPlane: new EmphasisMaterial(rootNode, { - edges: true, - edgeWidth: 3, - fill: false, - fillColor: [0.5, 0.5, .5], - fillAlpha: 0.5, - vertices: false - }) - }; + return message; +} - this._displayMeshes = { +async function getInitialDataUrl(resource) { + const INITIAL_DATA_LENGTH = 5; - plane: rootNode.addChild(new Mesh(rootNode, { - geometry: new ReadableGeometry(rootNode, { - primitive: "triangles", - positions: [ - 0.5, 0.5, 0.0, 0.5, -0.5, 0.0, // 0 - -0.5, -0.5, 0.0, -0.5, 0.5, 0.0, // 1 - 0.5, 0.5, -0.0, 0.5, -0.5, -0.0, // 2 - -0.5, -0.5, -0.0, -0.5, 0.5, -0.0 // 3 - ], - indices: [0, 1, 2, 2, 3, 0] - }), - material: new PhongMaterial(rootNode, { - emissive: [0, 0.0, 0], - diffuse: [0, 0, 0], - backfaces: true - }), - opacity: 0.6, - ghosted: true, - ghostMaterial: new EmphasisMaterial(rootNode, { - edges: false, - filled: true, - fillColor: [1, 1, 0], - edgeColor: [0, 0, 0], - fillAlpha: 0.1, - backfaces: true - }), - pickable: false, - collidable: true, - clippable: false, - visible: false, - scale: [2.4, 2.4, 1] - }), NO_STATE_INHERIT), + if (typeof resource === 'string') { + return "data:,".concat(resource.slice(0, INITIAL_DATA_LENGTH)); + } - planeFrame: rootNode.addChild(new Mesh(rootNode, { // Visible frame - geometry: new ReadableGeometry(rootNode, buildTorusGeometry({ - center: [0, 0, 0], - radius: 1.7, - tube: tubeRadius * 2, - radialSegments: 4, - tubeSegments: 4, - arc: Math.PI * 2.0 - })), - material: new PhongMaterial(rootNode, { - emissive: [0, 0, 0], - diffuse: [0, 0, 0], - specular: [0, 0, 0], - shininess: 0 - }), - //highlighted: true, - highlightMaterial: new EmphasisMaterial(rootNode, { - edges: false, - edgeColor: [0.0, 0.0, 0.0], - filled: true, - fillColor: [0.8, 0.8, 0.8], - fillAlpha: 1.0 - }), - pickable: false, - collidable: false, - clippable: false, - visible: false, - scale: [1, 1, .1], - rotation: [0, 0, 45] - }), NO_STATE_INHERIT), + if (resource instanceof Blob) { + const blobSlice = resource.slice(0, 5); + return await new Promise(resolve => { + const reader = new FileReader(); - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- + reader.onload = event => { + var _event$target; - xCurve: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis - geometry: shapes.curve, - material: materials.red, - matrix: (function () { - const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4()); - const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate1, rotate2, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - backfaces: true, - visible: false - }), NO_STATE_INHERIT), + return resolve(event === null || event === void 0 ? void 0 : (_event$target = event.target) === null || _event$target === void 0 ? void 0 : _event$target.result); + }; - xCurveHandle: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis - geometry: shapes.curveHandle, - material: materials.pickable, - matrix: (function () { - const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4()); - const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate1, rotate2, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - backfaces: true, - visible: false - }), NO_STATE_INHERIT), + reader.readAsDataURL(blobSlice); + }); + } - xCurveArrow1: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.red, - matrix: (function () { - const translate = math.translateMat4c(0., -0.07, -0.8, math.identityMat4()); - const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); - const rotate = math.rotationMat4v(0 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + if (resource instanceof ArrayBuffer) { + const slice = resource.slice(0, INITIAL_DATA_LENGTH); + const base64 = arrayBufferToBase64(slice); + return "data:base64,".concat(base64); + } - xCurveArrow2: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.red, - matrix: (function () { - const translate = math.translateMat4c(0.0, -0.8, -0.07, math.identityMat4()); - const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); - const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + return null; +} - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- +function arrayBufferToBase64(buffer) { + let binary = ''; + const bytes = new Uint8Array(buffer); - yCurve: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.curve, - material: materials.green, - rotation: [-90, 0, 0], - pickable: false, - collidable: true, - clippable: false, - backfaces: true, - visible: false - }), NO_STATE_INHERIT), + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]); + } - yCurveHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.curveHandle, - material: materials.pickable, - rotation: [-90, 0, 0], - pickable: true, - collidable: true, - clippable: false, - backfaces: true, - visible: false - }), NO_STATE_INHERIT), + return btoa(binary); +} - yCurveArrow1: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.green, - matrix: (function () { - const translate = math.translateMat4c(0.07, 0, -0.8, math.identityMat4()); - const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); - const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +async function fetchFile(url, options) { + if (typeof url === 'string') { + url = resolvePath(url); + let fetchOptions = options; - yCurveArrow2: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.green, - matrix: (function () { - const translate = math.translateMat4c(0.8, 0.0, -0.07, math.identityMat4()); - const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); - const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + if (options !== null && options !== void 0 && options.fetch && typeof (options === null || options === void 0 ? void 0 : options.fetch) !== 'function') { + fetchOptions = options.fetch; + } - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- + return await fetch(url, fetchOptions); + } - zCurve: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis - geometry: shapes.curve, - material: materials.blue, - matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + return await makeResponse(url); +} - zCurveHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.curveHandle, - material: materials.pickable, - matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +function isElectron$1(mockUserAgent) { + if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { + return true; + } - zCurveCurveArrow1: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.blue, - matrix: (function () { - const translate = math.translateMat4c(.8, -0.07, 0, math.identityMat4()); - const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); - return math.mulMat4(translate, scale, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + if (typeof process !== 'undefined' && typeof process.versions === 'object' && Boolean(process.versions.electron)) { + return true; + } - zCurveArrow2: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.blue, - matrix: (function () { - const translate = math.translateMat4c(.05, -0.8, 0, math.identityMat4()); - const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); - const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + const realUserAgent = typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent; + const userAgent = mockUserAgent || realUserAgent; - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- + if (userAgent && userAgent.indexOf('Electron') >= 0) { + return true; + } - center: rootNode.addChild(new Mesh(rootNode, { - geometry: new ReadableGeometry(rootNode, buildSphereGeometry({ - radius: 0.05 - })), - material: materials.center, - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + return false; +} - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- +function isBrowser$2() { + const isNode = typeof process === 'object' && String(process) === '[object process]' && !process.browser; + return !isNode || isElectron$1(); +} - xAxisArrow: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.red, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +const globals$1 = { + self: typeof self !== 'undefined' && self, + window: typeof window !== 'undefined' && window, + global: typeof global !== 'undefined' && global, + document: typeof document !== 'undefined' && document, + process: typeof process === 'object' && process +}; +const window_$1 = globals$1.window || globals$1.self || globals$1.global; +const process_$1 = globals$1.process || {}; - xAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHeadHandle, - material: materials.pickable, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +const VERSION$7 = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'untranspiled source'; +const isBrowser$1 = isBrowser$2(); - xAxis: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.axis, - material: materials.red, - matrix: (function () { - const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +function getStorage$1(type) { + try { + const storage = window[type]; + const x = '__storage_test__'; + storage.setItem(x, x); + storage.removeItem(x); + return storage; + } catch (e) { + return null; + } +} - xAxisHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.axisHandle, - material: materials.pickable, - matrix: (function () { - const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +class LocalStorage$1 { + constructor(id, defaultSettings, type = 'sessionStorage') { + this.storage = getStorage$1(type); + this.id = id; + this.config = {}; + Object.assign(this.config, defaultSettings); - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- + this._loadConfiguration(); + } - yAxisArrow: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.green, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + getConfiguration() { + return this.config; + } - yAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHeadHandle, - material: materials.pickable, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false, - opacity: 0.2 - }), NO_STATE_INHERIT), + setConfiguration(configuration) { + this.config = {}; + return this.updateConfiguration(configuration); + } - yShaft: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.axis, - material: materials.green, - position: [0, -radius / 2, 0], - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + updateConfiguration(configuration) { + Object.assign(this.config, configuration); - yShaftHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.axisHandle, - material: materials.pickable, - position: [0, -radius / 2, 0], - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + if (this.storage) { + const serialized = JSON.stringify(this.config); + this.storage.setItem(this.id, serialized); + } - //---------------------------------------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------------------------------------- + return this; + } - zAxisArrow: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHead, - material: materials.blue, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + _loadConfiguration() { + let configuration = {}; - zAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHeadHandle, - material: materials.pickable, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: true, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + if (this.storage) { + const serializedConfiguration = this.storage.getItem(this.id); + configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {}; + } + Object.assign(this.config, configuration); + return this; + } - zShaft: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.axis, - material: materials.blue, - matrix: (function () { - const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - clippable: false, - pickable: false, - collidable: true, - visible: false - }), NO_STATE_INHERIT), +} - zAxisHandle: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.axisHandle, - material: materials.pickable, - matrix: (function () { - const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - clippable: false, - pickable: true, - collidable: true, - visible: false - }), NO_STATE_INHERIT) - }; +function formatTime$1(ms) { + let formatted; - this._affordanceMeshes = { + if (ms < 10) { + formatted = "".concat(ms.toFixed(2), "ms"); + } else if (ms < 100) { + formatted = "".concat(ms.toFixed(1), "ms"); + } else if (ms < 1000) { + formatted = "".concat(ms.toFixed(0), "ms"); + } else { + formatted = "".concat((ms / 1000).toFixed(2), "s"); + } - planeFrame: rootNode.addChild(new Mesh(rootNode, { - geometry: new ReadableGeometry(rootNode, buildTorusGeometry({ - center: [0, 0, 0], - radius: 2, - tube: tubeRadius, - radialSegments: 4, - tubeSegments: 4, - arc: Math.PI * 2.0 - })), - material: new PhongMaterial(rootNode, { - ambient: [1, 1, 1], - diffuse: [0, 0, 0], - emissive: [1, 1, 0] - }), - highlighted: true, - highlightMaterial: new EmphasisMaterial(rootNode, { - edges: false, - filled: true, - fillColor: [1, 1, 0], - fillAlpha: 1.0 - }), - pickable: false, - collidable: false, - clippable: false, - visible: false, - scale: [1, 1, 1], - rotation: [0, 0, 45] - }), NO_STATE_INHERIT), + return formatted; +} +function leftPad$1(string, length = 8) { + const padLength = Math.max(length - string.length, 0); + return "".concat(' '.repeat(padLength)).concat(string); +} - xHoop: rootNode.addChild(new Mesh(rootNode, { // Full - geometry: shapes.hoop, - material: materials.red, - highlighted: true, - highlightMaterial: materials.highlightRed, - matrix: (function () { - const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4()); - const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate1, rotate2, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +function formatImage$1(image, message, scale, maxWidth = 600) { + const imageUrl = image.src.replace(/\(/g, '%28').replace(/\)/g, '%29'); - yHoop: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.hoop, - material: materials.green, - highlighted: true, - highlightMaterial: materials.highlightGreen, - rotation: [-90, 0, 0], - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), + if (image.width > maxWidth) { + scale = Math.min(scale, maxWidth / image.width); + } - zHoop: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis - geometry: shapes.hoop, - material: materials.blue, - highlighted: true, - highlightMaterial: materials.highlightBlue, - matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()), - pickable: false, - collidable: true, - clippable: false, - backfaces: true, - visible: false - }), NO_STATE_INHERIT), + const width = image.width * scale; + const height = image.height * scale; + const style = ['font-size:1px;', "padding:".concat(Math.floor(height / 2), "px ").concat(Math.floor(width / 2), "px;"), "line-height:".concat(height, "px;"), "background:url(".concat(imageUrl, ");"), "background-size:".concat(width, "px ").concat(height, "px;"), 'color:transparent;'].join(''); + return ["".concat(message, " %c+"), style]; +} - xAxisArrow: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHeadBig, - material: materials.red, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +const COLOR$1 = { + BLACK: 30, + RED: 31, + GREEN: 32, + YELLOW: 33, + BLUE: 34, + MAGENTA: 35, + CYAN: 36, + WHITE: 37, + BRIGHT_BLACK: 90, + BRIGHT_RED: 91, + BRIGHT_GREEN: 92, + BRIGHT_YELLOW: 93, + BRIGHT_BLUE: 94, + BRIGHT_MAGENTA: 95, + BRIGHT_CYAN: 96, + BRIGHT_WHITE: 97 +}; - yAxisArrow: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHeadBig, - material: materials.green, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT), +function getColor$1(color) { + return typeof color === 'string' ? COLOR$1[color.toUpperCase()] || COLOR$1.WHITE : color; +} - zAxisArrow: rootNode.addChild(new Mesh(rootNode, { - geometry: shapes.arrowHeadBig, - material: materials.blue, - matrix: (function () { - const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); - const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4()); - return math.mulMat4(rotate, translate, math.identityMat4()); - })(), - pickable: false, - collidable: true, - clippable: false, - visible: false - }), NO_STATE_INHERIT) - }; +function addColor$1(string, color, background) { + if (!isBrowser$1 && typeof string === 'string') { + if (color) { + color = getColor$1(color); + string = "\x1B[".concat(color, "m").concat(string, "\x1B[39m"); } - _bindEvents() { + if (background) { + color = getColor$1(background); + string = "\x1B[".concat(background + 10, "m").concat(string, "\x1B[49m"); + } + } - const self = this; + return string; +} - var grabbed = false; +function autobind$1(obj, predefined = ['constructor']) { + const proto = Object.getPrototypeOf(obj); + const propNames = Object.getOwnPropertyNames(proto); - const DRAG_ACTIONS = { - none: -1, - xTranslate: 0, - yTranslate: 1, - zTranslate: 2, - xRotate: 3, - yRotate: 4, - zRotate: 5 - }; + for (const key of propNames) { + if (typeof obj[key] === 'function') { + if (!predefined.find(name => key === name)) { + obj[key] = obj[key].bind(obj); + } + } + } +} - const rootNode = this._rootNode; +function assert$3(condition, message) { + if (!condition) { + throw new Error(message || 'Assertion failed'); + } +} - var nextDragAction = null; // As we hover grabbed an arrow or hoop, self is the action we would do if we then dragged it. - var dragAction = null; // Action we're doing while we drag an arrow or hoop. - const lastCanvasPos = math.vec2(); +function getHiResTimestamp$1() { + let timestamp; - const xBaseAxis = math.vec3([1, 0, 0]); - const yBaseAxis = math.vec3([0, 1, 0]); - const zBaseAxis = math.vec3([0, 0, 1]); + if (isBrowser$1 && window_$1.performance) { + timestamp = window_$1.performance.now(); + } else if (process_$1.hrtime) { + const timeParts = process_$1.hrtime(); + timestamp = timeParts[0] * 1000 + timeParts[1] / 1e6; + } else { + timestamp = Date.now(); + } - const canvas = this._viewer.scene.canvas.canvas; - const camera = this._viewer.camera; - const scene = this._viewer.scene; + return timestamp; +} - { // Keep gizmo screen size constant +const originalConsole$1 = { + debug: isBrowser$1 ? console.debug || console.log : console.log, + log: console.log, + info: console.info, + warn: console.warn, + error: console.error +}; +const DEFAULT_SETTINGS$1 = { + enabled: true, + level: 0 +}; - const tempVec3a = math.vec3([0, 0, 0]); - let lastDist = -1; +function noop$1() {} - this._onCameraViewMatrix = scene.camera.on("viewMatrix", () => { - }); +const cache$1 = {}; +const ONCE$1 = { + once: true +}; - this._onCameraProjMatrix = scene.camera.on("projMatrix", () => { - }); +function getTableHeader$1(table) { + for (const key in table) { + for (const title in table[key]) { + return title || 'untitled'; + } + } - this._onSceneTick = scene.on("tick", () => { + return 'empty'; +} - const dist = Math.abs(math.lenVec3(math.subVec3(scene.camera.eye, this._pos, tempVec3a))); +class Log$1 { + constructor({ + id + } = { + id: '' + }) { + this.id = id; + this.VERSION = VERSION$7; + this._startTs = getHiResTimestamp$1(); + this._deltaTs = getHiResTimestamp$1(); + this.LOG_THROTTLE_TIMEOUT = 0; + this._storage = new LocalStorage$1("__probe-".concat(this.id, "__"), DEFAULT_SETTINGS$1); + this.userData = {}; + this.timeStamp("".concat(this.id, " started")); + autobind$1(this); + Object.seal(this); + } - if (dist !== lastDist) { - if (camera.projection === "perspective") { - const worldSize = (Math.tan(camera.perspective.fov * math.DEGTORAD)) * dist; - const size = 0.07 * worldSize; - rootNode.scale = [size, size, size]; - lastDist = dist; - } - } + set level(newLevel) { + this.setLevel(newLevel); + } - if (camera.projection === "ortho") { - const worldSize = camera.ortho.scale / 10; - const size = worldSize; - rootNode.scale = [size, size, size]; - lastDist = dist; - } - }); - } + get level() { + return this.getLevel(); + } - const getClickCoordsWithinElement = (function () { - const canvasPos = new Float64Array(2); - return function (event) { - if (!event) { - event = window.event; - canvasPos[0] = event.x; - canvasPos[1] = event.y; - } else { - var element = event.target; - var totalOffsetLeft = 0; - var totalOffsetTop = 0; + isEnabled() { + return this._storage.config.enabled; + } - while (element.offsetParent) { - totalOffsetLeft += element.offsetLeft; - totalOffsetTop += element.offsetTop; - element = element.offsetParent; - } - canvasPos[0] = event.pageX - totalOffsetLeft; - canvasPos[1] = event.pageY - totalOffsetTop; - } - return canvasPos; - }; - })(); + getLevel() { + return this._storage.config.level; + } - const localToWorldVec = (function () { - const mat = math.mat4(); - return function (localVec, worldVec) { - math.quaternionToMat4(self._rootNode.quaternion, mat); - math.transformVec3(mat, localVec, worldVec); - math.normalizeVec3(worldVec); - return worldVec; - }; - })(); + getTotal() { + return Number((getHiResTimestamp$1() - this._startTs).toPrecision(10)); + } - var getTranslationPlane = (function () { - const planeNormal = math.vec3(); - return function (worldAxis) { - const absX = Math.abs(worldAxis[0]); - if (absX > Math.abs(worldAxis[1]) && absX > Math.abs(worldAxis[2])) { - math.cross3Vec3(worldAxis, [0, 1, 0], planeNormal); - } else { - math.cross3Vec3(worldAxis, [1, 0, 0], planeNormal); - } - math.cross3Vec3(planeNormal, worldAxis, planeNormal); - math.normalizeVec3(planeNormal); - return planeNormal; - } - })(); + getDelta() { + return Number((getHiResTimestamp$1() - this._deltaTs).toPrecision(10)); + } - const dragTranslateSectionPlane = (function () { - const p1 = math.vec3(); - const p2 = math.vec3(); - const worldAxis = math.vec4(); - return function (baseAxis, fromMouse, toMouse) { - localToWorldVec(baseAxis, worldAxis); - const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse); - getPointerPlaneIntersect(fromMouse, planeNormal, p1); - getPointerPlaneIntersect(toMouse, planeNormal, p2); - math.subVec3(p2, p1); - const dot = math.dotVec3(p2, worldAxis); - self._pos[0] += worldAxis[0] * dot; - self._pos[1] += worldAxis[1] * dot; - self._pos[2] += worldAxis[2] * dot; - self._rootNode.position = self._pos; - if (self._sectionPlane) { - self._sectionPlane.pos = self._pos; - } - } - })(); + set priority(newPriority) { + this.level = newPriority; + } - var dragRotateSectionPlane = (function () { - const p1 = math.vec4(); - const p2 = math.vec4(); - const c = math.vec4(); - const worldAxis = math.vec4(); - return function (baseAxis, fromMouse, toMouse) { - localToWorldVec(baseAxis, worldAxis); - const hasData = getPointerPlaneIntersect(fromMouse, worldAxis, p1) && getPointerPlaneIntersect(toMouse, worldAxis, p2); - if (!hasData) { // Find intersections with view plane and project down to origin - const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse); - getPointerPlaneIntersect(fromMouse, planeNormal, p1, 1); // Ensure plane moves closer to camera so angles become workable - getPointerPlaneIntersect(toMouse, planeNormal, p2, 1); - var dot = math.dotVec3(p1, worldAxis); - p1[0] -= dot * worldAxis[0]; - p1[1] -= dot * worldAxis[1]; - p1[2] -= dot * worldAxis[2]; - dot = math.dotVec3(p2, worldAxis); - p2[0] -= dot * worldAxis[0]; - p2[1] -= dot * worldAxis[1]; - p2[2] -= dot * worldAxis[2]; - } - math.normalizeVec3(p1); - math.normalizeVec3(p2); - dot = math.dotVec3(p1, p2); - dot = math.clamp(dot, -1.0, 1.0); // Rounding errors cause dot to exceed allowed range - var incDegrees = Math.acos(dot) * math.RADTODEG; - math.cross3Vec3(p1, p2, c); - if (math.dotVec3(c, worldAxis) < 0.0) { - incDegrees = -incDegrees; - } - self._rootNode.rotate(baseAxis, incDegrees); - rotateSectionPlane(); - } - })(); + get priority() { + return this.level; + } - var getPointerPlaneIntersect = (function () { - const dir = math.vec4([0, 0, 0, 1]); - const matrix = math.mat4(); - return function (mouse, axis, dest, offset) { - offset = offset || 0; - dir[0] = mouse[0] / canvas.width * 2.0 - 1.0; - dir[1] = -(mouse[1] / canvas.height * 2.0 - 1.0); - dir[2] = 0.0; - dir[3] = 1.0; - math.mulMat4(camera.projMatrix, camera.viewMatrix, matrix); // Unproject norm device coords to view coords - math.inverseMat4(matrix); - math.transformVec4(matrix, dir, dir); - math.mulVec4Scalar(dir, 1.0 / dir[3]); // This is now point A on the ray in world space - var rayO = camera.eye; // The direction - math.subVec4(dir, rayO, dir); - const origin = self._sectionPlane.pos; // Plane origin: - var d = -math.dotVec3(origin, axis) - offset; - var dot = math.dotVec3(axis, dir); - if (Math.abs(dot) > 0.005) { - var t = -(math.dotVec3(axis, rayO) + d) / dot; - math.mulVec3Scalar(dir, t, dest); - math.addVec3(dest, rayO); - math.subVec3(dest, origin, dest); - return true; - } - return false; - } - })(); + getPriority() { + return this.level; + } - const rotateSectionPlane = (function () { - const dir = math.vec3(); - const mat = math.mat4(); - return function () { - if (self.sectionPlane) { - math.quaternionToMat4(rootNode.quaternion, mat); // << --- - math.transformVec3(mat, [0, 0, 1], dir); - self._setSectionPlaneDir(dir); - } - }; - })(); + enable(enabled = true) { + this._storage.updateConfiguration({ + enabled + }); - { - var down = false; - var lastAffordanceMesh; + return this; + } - this._onCameraControlHover = this._viewer.cameraControl.on("hoverEnter", (hit) => { - if (!this._visible) { - return; - } - if (down) { - return; - } - grabbed = false; - if (lastAffordanceMesh) { - lastAffordanceMesh.visible = false; - } - var affordanceMesh; - const meshId = hit.entity.id; - switch (meshId) { + setLevel(level) { + this._storage.updateConfiguration({ + level + }); - case this._displayMeshes.xAxisArrowHandle.id: - affordanceMesh = this._affordanceMeshes.xAxisArrow; - nextDragAction = DRAG_ACTIONS.xTranslate; - break; + return this; + } - case this._displayMeshes.xAxisHandle.id: - affordanceMesh = this._affordanceMeshes.xAxisArrow; - nextDragAction = DRAG_ACTIONS.xTranslate; - break; + assert(condition, message) { + assert$3(condition, message); + } - case this._displayMeshes.yAxisArrowHandle.id: - affordanceMesh = this._affordanceMeshes.yAxisArrow; - nextDragAction = DRAG_ACTIONS.yTranslate; - break; + warn(message) { + return this._getLogFunction(0, message, originalConsole$1.warn, arguments, ONCE$1); + } - case this._displayMeshes.yShaftHandle.id: - affordanceMesh = this._affordanceMeshes.yAxisArrow; - nextDragAction = DRAG_ACTIONS.yTranslate; - break; + error(message) { + return this._getLogFunction(0, message, originalConsole$1.error, arguments); + } - case this._displayMeshes.zAxisArrowHandle.id: - affordanceMesh = this._affordanceMeshes.zAxisArrow; - nextDragAction = DRAG_ACTIONS.zTranslate; - break; + deprecated(oldUsage, newUsage) { + return this.warn("`".concat(oldUsage, "` is deprecated and will be removed in a later version. Use `").concat(newUsage, "` instead")); + } - case this._displayMeshes.zAxisHandle.id: - affordanceMesh = this._affordanceMeshes.zAxisArrow; - nextDragAction = DRAG_ACTIONS.zTranslate; - break; + removed(oldUsage, newUsage) { + return this.error("`".concat(oldUsage, "` has been removed. Use `").concat(newUsage, "` instead")); + } - case this._displayMeshes.xCurveHandle.id: - affordanceMesh = this._affordanceMeshes.xHoop; - nextDragAction = DRAG_ACTIONS.xRotate; - break; + probe(logLevel, message) { + return this._getLogFunction(logLevel, message, originalConsole$1.log, arguments, { + time: true, + once: true + }); + } - case this._displayMeshes.yCurveHandle.id: - affordanceMesh = this._affordanceMeshes.yHoop; - nextDragAction = DRAG_ACTIONS.yRotate; - break; + log(logLevel, message) { + return this._getLogFunction(logLevel, message, originalConsole$1.debug, arguments); + } - case this._displayMeshes.zCurveHandle.id: - affordanceMesh = this._affordanceMeshes.zHoop; - nextDragAction = DRAG_ACTIONS.zRotate; - break; + info(logLevel, message) { + return this._getLogFunction(logLevel, message, console.info, arguments); + } - default: - nextDragAction = DRAG_ACTIONS.none; - return; // Not clicked an arrow or hoop - } - if (affordanceMesh) { - affordanceMesh.visible = true; - } - lastAffordanceMesh = affordanceMesh; - grabbed = true; - }); + once(logLevel, message) { + return this._getLogFunction(logLevel, message, originalConsole$1.debug || originalConsole$1.info, arguments, ONCE$1); + } - this._onCameraControlHoverLeave = this._viewer.cameraControl.on("hoverOut", (hit) => { - if (!this._visible) { - return; - } - if (lastAffordanceMesh) { - lastAffordanceMesh.visible = false; - } - lastAffordanceMesh = null; - nextDragAction = DRAG_ACTIONS.none; - }); + table(logLevel, table, columns) { + if (table) { + return this._getLogFunction(logLevel, table, console.table || noop$1, columns && [columns], { + tag: getTableHeader$1(table) + }); + } - canvas.addEventListener("mousedown", this._canvasMouseDownListener = (e) => { - e.preventDefault(); - if (!this._visible) { - return; - } - if (!grabbed) { - return; - } - this._viewer.cameraControl.pointerEnabled = false; - switch (e.which) { - case 1: // Left button - down = true; - var canvasPos = getClickCoordsWithinElement(e); - dragAction = nextDragAction; - lastCanvasPos[0] = canvasPos[0]; - lastCanvasPos[1] = canvasPos[1]; - break; - } - }); + return noop$1; + } - canvas.addEventListener("mousemove", this._canvasMouseMoveListener = (e) => { - if (!this._visible) { - return; - } - if (!down) { - return; - } - var canvasPos = getClickCoordsWithinElement(e); - const x = canvasPos[0]; - const y = canvasPos[1]; + image({ + logLevel, + priority, + image, + message = '', + scale = 1 + }) { + if (!this._shouldLog(logLevel || priority)) { + return noop$1; + } - switch (dragAction) { - case DRAG_ACTIONS.xTranslate: - dragTranslateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos); - break; - case DRAG_ACTIONS.yTranslate: - dragTranslateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos); - break; - case DRAG_ACTIONS.zTranslate: - dragTranslateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos); - break; - case DRAG_ACTIONS.xRotate: - dragRotateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos); - break; - case DRAG_ACTIONS.yRotate: - dragRotateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos); - break; - case DRAG_ACTIONS.zRotate: - dragRotateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos); - break; - } + return isBrowser$1 ? logImageInBrowser$1({ + image, + message, + scale + }) : logImageInNode$1({ + image, + message, + scale + }); + } - lastCanvasPos[0] = x; - lastCanvasPos[1] = y; - }); + settings() { + if (console.table) { + console.table(this._storage.config); + } else { + console.log(this._storage.config); + } + } - canvas.addEventListener("mouseup", this._canvasMouseUpListener = (e) => { - if (!this._visible) { - return; - } - this._viewer.cameraControl.pointerEnabled = true; - if (!down) { - return; - } - switch (e.which) { - } - down = false; - grabbed = false; - }); + get(setting) { + return this._storage.config[setting]; + } - canvas.addEventListener("wheel", this._canvasWheelListener = (e) => { - if (!this._visible) { - return; - } - var delta = Math.max(-1, Math.min(1, -e.deltaY * 40)); - if (delta === 0) { - return; - } - }); - } - } + set(setting, value) { + this._storage.updateConfiguration({ + [setting]: value + }); + } - _destroy() { - this._unbindEvents(); - this._destroyNodes(); - } + time(logLevel, message) { + return this._getLogFunction(logLevel, message, console.time ? console.time : console.info); + } - _unbindEvents() { + timeEnd(logLevel, message) { + return this._getLogFunction(logLevel, message, console.timeEnd ? console.timeEnd : console.info); + } - const viewer = this._viewer; - const scene = viewer.scene; - const canvas = scene.canvas.canvas; - const camera = viewer.camera; - const cameraControl = viewer.cameraControl; + timeStamp(logLevel, message) { + return this._getLogFunction(logLevel, message, console.timeStamp || noop$1); + } - scene.off(this._onSceneTick); + group(logLevel, message, opts = { + collapsed: false + }) { + opts = normalizeArguments$1({ + logLevel, + message, + opts + }); + const { + collapsed + } = opts; + opts.method = (collapsed ? console.groupCollapsed : console.group) || console.info; + return this._getLogFunction(opts); + } - canvas.removeEventListener("mousedown", this._canvasMouseDownListener); - canvas.removeEventListener("mousemove", this._canvasMouseMoveListener); - canvas.removeEventListener("mouseup", this._canvasMouseUpListener); - canvas.removeEventListener("wheel", this._canvasWheelListener); + groupCollapsed(logLevel, message, opts = {}) { + return this.group(logLevel, message, Object.assign({}, opts, { + collapsed: true + })); + } - camera.off(this._onCameraViewMatrix); - camera.off(this._onCameraProjMatrix); + groupEnd(logLevel) { + return this._getLogFunction(logLevel, '', console.groupEnd || noop$1); + } - cameraControl.off(this._onCameraControlHover); - cameraControl.off(this._onCameraControlHoverLeave); + withGroup(logLevel, message, func) { + this.group(logLevel, message)(); + + try { + func(); + } finally { + this.groupEnd(logLevel)(); } + } - _destroyNodes() { - this._setSectionPlane(null); - this._rootNode.destroy(); - this._displayMeshes = {}; - this._affordanceMeshes = {}; + trace() { + if (console.trace) { + console.trace(); } -} + } -/** - * Renders a 3D plane within an {@link Overview} to indicate its {@link SectionPlane}'s current position and orientation. - * - * @private - */ -class Plane { + _shouldLog(logLevel) { + return this.isEnabled() && this.getLevel() >= normalizeLogLevel$1(logLevel); + } - /** @private */ - constructor(overview, overviewScene, sectionPlane) { + _getLogFunction(logLevel, message, method, args = [], opts) { + if (this._shouldLog(logLevel)) { + opts = normalizeArguments$1({ + logLevel, + message, + args, + opts + }); + method = method || opts.method; + assert$3(method); + opts.total = this.getTotal(); + opts.delta = this.getDelta(); + this._deltaTs = getHiResTimestamp$1(); + const tag = opts.tag || opts.message; - /** - * The ID of this SectionPlanesOverviewPlane. - * - * @type {String} - */ - this.id = sectionPlane.id; + if (opts.once) { + if (!cache$1[tag]) { + cache$1[tag] = getHiResTimestamp$1(); + } else { + return noop$1; + } + } - /** - * The {@link SectionPlane} represented by this SectionPlanesOverviewPlane. - * - * @type {SectionPlane} - */ - this._sectionPlane = sectionPlane; + message = decorateMessage$1(this.id, opts.message, opts); + return method.bind(console, message, ...opts.args); + } - this._mesh = new Mesh(overviewScene, { - id: sectionPlane.id, - geometry: new ReadableGeometry(overviewScene, buildBoxGeometry({ - xSize: .5, - ySize: .5, - zSize: .001 - })), - material: new PhongMaterial(overviewScene, { - emissive: [1, 1, 1], - diffuse: [0, 0, 0], - backfaces: false - }), - edgeMaterial: new EdgeMaterial(overviewScene, { - edgeColor: [0.0, 0.0, 0.0], - edgeAlpha: 1.0, - edgeWidth: 1 - }), - highlightMaterial: new EmphasisMaterial(overviewScene, { - fill: true, - fillColor: [0.5, 1, 0.5], - fillAlpha: 0.7, - edges: true, - edgeColor: [0.0, 0.0, 0.0], - edgeAlpha: 1.0, - edgeWidth: 1 - }), - selectedMaterial: new EmphasisMaterial(overviewScene, { - fill: true, - fillColor: [0, 0, 1], - fillAlpha: 0.7, - edges: true, - edgeColor: [1.0, 0.0, 0.0], - edgeAlpha: 1.0, - edgeWidth: 1 - }), - highlighted: true, - scale: [3, 3, 3], - position: [0, 0, 0], - rotation: [0, 0, 0], - opacity: 0.3, - edges: true - }); + return noop$1; + } +} +Log$1.VERSION = VERSION$7; - { - const vec = math.vec3([0, 0, 0]); - const pos2 = math.vec3(); - const zeroVec = math.vec3([0, 0, 1]); - const quat = math.vec4(4); - const pos3 = math.vec3(); +function normalizeLogLevel$1(logLevel) { + if (!logLevel) { + return 0; + } - const update = () => { + let resolvedLevel; - const origin = this._sectionPlane.scene.center; + switch (typeof logLevel) { + case 'number': + resolvedLevel = logLevel; + break; - const negDir = [-this._sectionPlane.dir[0], -this._sectionPlane.dir[1], -this._sectionPlane.dir[2]]; - math.subVec3(origin, this._sectionPlane.pos, vec); - const dist = -math.dotVec3(negDir, vec); + case 'object': + resolvedLevel = logLevel.logLevel || logLevel.priority || 0; + break; - math.normalizeVec3(negDir); - math.mulVec3Scalar(negDir, dist, pos2); - const quaternion = math.vec3PairToQuaternion(zeroVec, this._sectionPlane.dir, quat); + default: + return 0; + } - pos3[0] = pos2[0] * 0.1; - pos3[1] = pos2[1] * 0.1; - pos3[2] = pos2[2] * 0.1; + assert$3(Number.isFinite(resolvedLevel) && resolvedLevel >= 0); + return resolvedLevel; +} - this._mesh.quaternion = quaternion; - this._mesh.position = pos3; - }; +function normalizeArguments$1(opts) { + const { + logLevel, + message + } = opts; + opts.logLevel = normalizeLogLevel$1(logLevel); + const args = opts.args ? Array.from(opts.args) : []; - this._onSectionPlanePos = this._sectionPlane.on("pos", update); - this._onSectionPlaneDir = this._sectionPlane.on("dir", update); + while (args.length && args.shift() !== message) {} - // update(); - } + opts.args = args; - this._highlighted = false; - this._selected = false; - } + switch (typeof logLevel) { + case 'string': + case 'function': + if (message !== undefined) { + args.unshift(message); + } - /** - * Sets if this SectionPlanesOverviewPlane is highlighted. - * - * @type {Boolean} - * @private - */ - setHighlighted(highlighted) { - this._highlighted = !!highlighted; - this._mesh.highlighted = this._highlighted; - this._mesh.highlightMaterial.fillColor = highlighted ? [0, 0.7, 0] : [0, 0, 0]; - // this._selectedMesh.highlighted = true; - } + opts.message = logLevel; + break; - /** - * Gets if this SectionPlanesOverviewPlane is highlighted. - * - * @type {Boolean} - * @private - */ - getHighlighted() { - return this._highlighted; - } + case 'object': + Object.assign(opts, logLevel); + break; + } - /** - * Sets if this SectionPlanesOverviewPlane is selected. - * - * @type {Boolean} - * @private - */ - setSelected(selected) { - this._selected = !!selected; - this._mesh.edgeMaterial.edgeWidth = selected ? 3 : 1; - this._mesh.highlightMaterial.edgeWidth = selected ? 3 : 1; + if (typeof opts.message === 'function') { + opts.message = opts.message(); + } - } + const messageType = typeof opts.message; + assert$3(messageType === 'string' || messageType === 'object'); + return Object.assign(opts, opts.opts); +} - /** - * Gets if this SectionPlanesOverviewPlane is selected. - * - * @type {Boolean} - * @private - */ - getSelected() { - return this._selected; - } +function decorateMessage$1(id, message, opts) { + if (typeof message === 'string') { + const time = opts.time ? leftPad$1(formatTime$1(opts.total)) : ''; + message = opts.time ? "".concat(id, ": ").concat(time, " ").concat(message) : "".concat(id, ": ").concat(message); + message = addColor$1(message, opts.color, opts.background); + } - /** @private */ - destroy() { - this._sectionPlane.off(this._onSectionPlanePos); - this._sectionPlane.off(this._onSectionPlaneDir); - this._mesh.destroy(); - } + return message; } -/** - * @desc An interactive 3D overview for navigating the {@link SectionPlane}s created by its {@link SectionPlanesPlugin}. - * - * * Located at {@link SectionPlanesPlugin#overview}. - * * Renders the overview on a separate canvas at a corner of the {@link Viewer}'s {@link Scene} {@link Canvas}. - * * The overview shows a 3D plane object for each {@link SectionPlane} in the {@link Scene}. - * * Click a plane object in the overview to toggle the visibility of a 3D gizmo to edit the position and orientation of its {@link SectionPlane}. - * - * @private - */ -class Overview { +function logImageInNode$1({ + image, + message = '', + scale = 1 +}) { + let asciify = null; - /** - * @private - */ - constructor(plugin, cfg) { + try { + asciify = module.require('asciify-image'); + } catch (error) {} - if (!cfg.onHoverEnterPlane || !cfg.onHoverLeavePlane || !cfg.onClickedNothing || !cfg.onClickedPlane) { - throw "Missing config(s): onHoverEnterPlane, onHoverLeavePlane, onClickedNothing || onClickedPlane"; - } + if (asciify) { + return () => asciify(image, { + fit: 'box', + width: "".concat(Math.round(80 * scale), "%") + }).then(data => console.log(data)); + } - /** - * The {@link SectionPlanesPlugin} that owns this SectionPlanesOverview. - * - * @type {SectionPlanesPlugin} - */ - this.plugin = plugin; + return noop$1; +} - this._viewer = plugin.viewer; +function logImageInBrowser$1({ + image, + message = '', + scale = 1 +}) { + if (typeof image === 'string') { + const img = new Image(); - this._onHoverEnterPlane = cfg.onHoverEnterPlane; - this._onHoverLeavePlane = cfg.onHoverLeavePlane; - this._onClickedNothing = cfg.onClickedNothing; - this._onClickedPlane = cfg.onClickedPlane; - this._visible = true; + img.onload = () => { + const args = formatImage$1(img, message, scale); + console.log(...args); + }; - this._planes = {}; + img.src = image; + return noop$1; + } - //-------------------------------------------------------------------------------------------------------------- - // Init canvas - //-------------------------------------------------------------------------------------------------------------- + const element = image.nodeName || ''; - this._canvas = cfg.overviewCanvas; + if (element.toLowerCase() === 'img') { + console.log(...formatImage$1(image, message, scale)); + return noop$1; + } - //-------------------------------------------------------------------------------------------------------------- - // Init scene - //-------------------------------------------------------------------------------------------------------------- + if (element.toLowerCase() === 'canvas') { + const img = new Image(); - this._scene = new Scene(this._viewer, { - canvasId: this._canvas.id, - transparent: true - }); - this._scene.clearLights(); - new DirLight(this._scene, { - dir: [0.4, -0.4, 0.8], - color: [0.8, 1.0, 1.0], - intensity: 1.0, - space: "view" - }); - new DirLight(this._scene, { - dir: [-0.8, -0.3, -0.4], - color: [0.8, 0.8, 0.8], - intensity: 1.0, - space: "view" - }); - new DirLight(this._scene, { - dir: [0.8, -0.6, -0.8], - color: [1.0, 1.0, 1.0], - intensity: 1.0, - space: "view" - }); + img.onload = () => console.log(...formatImage$1(img, message, scale)); - this._scene.camera; - this._scene.camera.perspective.fov = 70; + img.src = image.toDataURL(); + return noop$1; + } - this._zUp = false; + return noop$1; +} - //-------------------------------------------------------------------------------------------------------------- - // Synchronize overview scene camera with viewer camera - //-------------------------------------------------------------------------------------------------------------- +const probeLog = new Log$1({ + id: 'loaders.gl' +}); +class NullLog { + log() { + return () => {}; + } - { - const camera = this._scene.camera; - const matrix = math.rotationMat4c(-90 * math.DEGTORAD, 1, 0, 0); - const eyeLookVec = math.vec3(); - const eyeLookVecOverview = math.vec3(); - const upOverview = math.vec3(); + info() { + return () => {}; + } - this._synchCamera = () => { - const eye = this._viewer.camera.eye; - const look = this._viewer.camera.look; - const up = this._viewer.camera.up; - math.mulVec3Scalar(math.normalizeVec3(math.subVec3(eye, look, eyeLookVec)), 7); - if (this._zUp) { // +Z up - math.transformVec3(matrix, eyeLookVec, eyeLookVecOverview); - math.transformVec3(matrix, up, upOverview); - camera.look = [0, 0, 0]; - camera.eye = math.transformVec3(matrix, eyeLookVec, eyeLookVecOverview); - camera.up = math.transformPoint3(matrix, up, upOverview); - } else { // +Y up - camera.look = [0, 0, 0]; - camera.eye = eyeLookVec; - camera.up = up; - } - }; - } + warn() { + return () => {}; + } - this._onViewerCameraMatrix = this._viewer.camera.on("matrix", this._synchCamera); + error() { + return () => {}; + } - this._onViewerCameraWorldAxis = this._viewer.camera.on("worldAxis", this._synchCamera); +} +class ConsoleLog { + constructor() { + _defineProperty(this, "console", void 0); - this._onViewerCameraFOV = this._viewer.camera.perspective.on("fov", (fov) => { - this._scene.camera.perspective.fov = fov; - }); + this.console = console; + } - //-------------------------------------------------------------------------------------------------------------- - // Bind overview canvas events - //-------------------------------------------------------------------------------------------------------------- + log(...args) { + return this.console.log.bind(this.console, ...args); + } - { - var hoveredEntity = null; + info(...args) { + return this.console.info.bind(this.console, ...args); + } - this._onInputMouseMove = this._scene.input.on("mousemove", (coords) => { - const hit = this._scene.pick({ - canvasPos: coords - }); - if (hit) { - if (!hoveredEntity || hit.entity.id !== hoveredEntity.id) { - if (hoveredEntity) { - const plane = this._planes[hoveredEntity.id]; - if (plane) { - this._onHoverLeavePlane(hoveredEntity.id); - } - } - hoveredEntity = hit.entity; - const plane = this._planes[hoveredEntity.id]; - if (plane) { - this._onHoverEnterPlane(hoveredEntity.id); - } - } - } else { - if (hoveredEntity) { - this._onHoverLeavePlane(hoveredEntity.id); - hoveredEntity = null; - } - } - }); + warn(...args) { + return this.console.warn.bind(this.console, ...args); + } - this._scene.canvas.canvas.addEventListener("mouseup", this._onCanvasMouseUp = () => { - if (hoveredEntity) { - const plane = this._planes[hoveredEntity.id]; - if (plane) { - this._onClickedPlane(hoveredEntity.id); - } - } else { - this._onClickedNothing(); - } - }); + error(...args) { + return this.console.error.bind(this.console, ...args); + } - this._scene.canvas.canvas.addEventListener("mouseout", this._onCanvasMouseOut = () => { - if (hoveredEntity) { - this._onHoverLeavePlane(hoveredEntity.id); - hoveredEntity = null; - } - }); - } +} - //-------------------------------------------------------------------------------------------------------------- - // Configure overview - //-------------------------------------------------------------------------------------------------------------- +const DEFAULT_LOADER_OPTIONS = { + fetch: null, + mimeType: undefined, + nothrow: false, + log: new ConsoleLog(), + CDN: 'https://unpkg.com/@loaders.gl', + worker: true, + maxConcurrency: 3, + maxMobileConcurrency: 1, + reuseWorkers: isBrowser$4, + _nodeWorkers: false, + _workerType: '', + limit: 0, + _limitMB: 0, + batchSize: 'auto', + batchDebounceMs: 0, + metadata: false, + transforms: [] +}; +const REMOVED_LOADER_OPTIONS = { + throws: 'nothrow', + dataType: '(no longer used)', + uri: 'baseUri', + method: 'fetch.method', + headers: 'fetch.headers', + body: 'fetch.body', + mode: 'fetch.mode', + credentials: 'fetch.credentials', + cache: 'fetch.cache', + redirect: 'fetch.redirect', + referrer: 'fetch.referrer', + referrerPolicy: 'fetch.referrerPolicy', + integrity: 'fetch.integrity', + keepalive: 'fetch.keepalive', + signal: 'fetch.signal' +}; - this.setVisible(cfg.overviewVisible); - } +function getGlobalLoaderState() { + globalThis.loaders = globalThis.loaders || {}; + const { + loaders + } = globalThis; + loaders._state = loaders._state || {}; + return loaders._state; +} +const getGlobalLoaderOptions = () => { + const state = getGlobalLoaderState(); + state.globalOptions = state.globalOptions || { ...DEFAULT_LOADER_OPTIONS + }; + return state.globalOptions; +}; +function normalizeOptions(options, loader, loaders, url) { + loaders = loaders || []; + loaders = Array.isArray(loaders) ? loaders : [loaders]; + validateOptions(options, loaders); + return normalizeOptionsInternal(loader, options, url); +} +function getFetchFunction(options, context) { + const globalOptions = getGlobalLoaderOptions(); + const fetchOptions = options || globalOptions; - /** Called by SectionPlanesPlugin#createSectionPlane() - * @private - */ - addSectionPlane(sectionPlane) { - this._planes[sectionPlane.id] = new Plane(this, this._scene, sectionPlane); - } + if (typeof fetchOptions.fetch === 'function') { + return fetchOptions.fetch; + } - /** @private - */ - setPlaneHighlighted(id, highlighted) { - const plane = this._planes[id]; - if (plane) { - plane.setHighlighted(highlighted); - } - } + if (isObject(fetchOptions.fetch)) { + return url => fetchFile(url, fetchOptions); + } - /** @private - */ - setPlaneSelected(id, selected) { - const plane = this._planes[id]; - if (plane) { - plane.setSelected(selected); - } - } + if (context !== null && context !== void 0 && context.fetch) { + return context === null || context === void 0 ? void 0 : context.fetch; + } - /** @private - */ - removeSectionPlane(sectionPlane) { - const plane = this._planes[sectionPlane.id]; - if (plane) { - plane.destroy(); - delete this._planes[sectionPlane.id]; - } - } + return fetchFile; +} - /** - * Sets if this SectionPlanesOverview is visible. - * - * @param {Boolean} visible Whether or not this SectionPlanesOverview is visible. - */ - setVisible(visible = true) { - this._visible = visible; - this._canvas.style.visibility = visible ? "visible" : "hidden"; - } +function validateOptions(options, loaders) { + validateOptionsObject(options, null, DEFAULT_LOADER_OPTIONS, REMOVED_LOADER_OPTIONS, loaders); - /** - * Gets if this SectionPlanesOverview is visible. - * - * @return {Boolean} True when this SectionPlanesOverview is visible. - */ - getVisible() { - return this._visible; - } + for (const loader of loaders) { + const idOptions = options && options[loader.id] || {}; + const loaderOptions = loader.options && loader.options[loader.id] || {}; + const deprecatedOptions = loader.deprecatedOptions && loader.deprecatedOptions[loader.id] || {}; + validateOptionsObject(idOptions, loader.id, loaderOptions, deprecatedOptions, loaders); + } +} - /** @private - */ - destroy() { - this._viewer.camera.off(this._onViewerCameraMatrix); - this._viewer.camera.off(this._onViewerCameraWorldAxis); - this._viewer.camera.perspective.off(this._onViewerCameraFOV); +function validateOptionsObject(options, id, defaultOptions, deprecatedOptions, loaders) { + const loaderName = id || 'Top level'; + const prefix = id ? "".concat(id, ".") : ''; - this._scene.input.off(this._onInputMouseMove); - this._scene.canvas.canvas.removeEventListener("mouseup", this._onCanvasMouseUp); - this._scene.canvas.canvas.removeEventListener("mouseout", this._onCanvasMouseOut); - this._scene.destroy(); + for (const key in options) { + const isSubOptions = !id && isObject(options[key]); + const isBaseUriOption = key === 'baseUri' && !id; + const isWorkerUrlOption = key === 'workerUrl' && id; + + if (!(key in defaultOptions) && !isBaseUriOption && !isWorkerUrlOption) { + if (key in deprecatedOptions) { + probeLog.warn("".concat(loaderName, " loader option '").concat(prefix).concat(key, "' no longer supported, use '").concat(deprecatedOptions[key], "'"))(); + } else if (!isSubOptions) { + const suggestion = findSimilarOption(key, loaders); + probeLog.warn("".concat(loaderName, " loader option '").concat(prefix).concat(key, "' not recognized. ").concat(suggestion))(); + } } + } } -const tempAABB = math.AABB3(); -const tempVec3$3 = math.vec3(); +function findSimilarOption(optionKey, loaders) { + const lowerCaseOptionKey = optionKey.toLowerCase(); + let bestSuggestion = ''; -/** - * SectionPlanesPlugin is a {@link Viewer} plugin that manages {@link SectionPlane}s. - * - * [](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_SectionPlanesPlugin) - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_SectionPlanesPlugin)] - * - * ## Overview - * - * * Use the SectionPlanesPlugin to - * create and edit {@link SectionPlane}s to slice portions off your models and reveal internal structures. - * * As shown in the screen capture above, SectionPlanesPlugin shows an overview of all your SectionPlanes (on the right, in - * this example). - * * Click a plane in the overview to activate a 3D control with which you can interactively - * reposition its SectionPlane in the main canvas. - * - * ## Usage - * - * In the example below, we'll use a {@link GLTFLoaderPlugin} to load a model, and a SectionPlanesPlugin - * to slice it open with two {@link SectionPlane}s. We'll show the overview in the bottom right of the Viewer - * canvas. Finally, we'll programmatically activate the 3D editing control, so that we can use it to interactively - * reposition our second SectionPlane. - * - * ````JavaScript - * import {Viewer, GLTFLoaderPlugin, SectionPlanesPlugin} from "xeokit-sdk.es.js"; - * - * // Create a Viewer and arrange its Camera - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [-5.02, 2.22, 15.09]; - * viewer.camera.look = [4.97, 2.79, 9.89]; - * viewer.camera.up = [-0.05, 0.99, 0.02]; - * - * - * // Add a GLTFLoaderPlugin - * - * const gltfLoader = new GLTFLoaderPlugin(viewer); - * - * // Add a SectionPlanesPlugin, with overview visible - * - * const sectionPlanes = new SectionPlanesPlugin(viewer, { - * overviewCanvasID: "myOverviewCanvas", - * overviewVisible: true - * }); - * - * // Load a model - * - * const model = gltfLoader.load({ - * id: "myModel", - * src: "./models/gltf/schependomlaan/scene.gltf" - * }); - * - * // Create a couple of section planes - * // These will be shown in the overview - * - * sectionPlanes.createSectionPlane({ - * id: "mySectionPlane", - * pos: [1.04, 1.95, 9.74], - * dir: [1.0, 0.0, 0.0] - * }); - * - * sectionPlanes.createSectionPlane({ - * id: "mySectionPlane2", - * pos: [2.30, 4.46, 14.93], - * dir: [0.0, -0.09, -0.79] - * }); - * - * // Show the SectionPlanePlugin's 3D editing gizmo, - * // to interactively reposition one of our SectionPlanes - * - * sectionPlanes.showControl("mySectionPlane2"); - * - * const mySectionPlane2 = sectionPlanes.sectionPlanes["mySectionPlane2"]; - * - * // Programmatically reposition one of our SectionPlanes - * // This also updates its position as shown in the overview gizmo - * - * mySectionPlane2.pos = [11.0, 6.-, -12]; - * mySectionPlane2.dir = [0.4, 0.0, 0.5]; - * ```` - */ -class SectionPlanesPlugin extends Plugin { + for (const loader of loaders) { + for (const key in loader.options) { + if (optionKey === key) { + return "Did you mean '".concat(loader.id, ".").concat(key, "'?"); + } - /** - * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="SectionPlanes"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {String} [cfg.overviewCanvasId] ID of a canvas element to display the overview. - * @param {String} [cfg.overviewVisible=true] Initial visibility of the overview canvas. - */ - constructor(viewer, cfg = {}) { + const lowerCaseKey = key.toLowerCase(); + const isPartialMatch = lowerCaseOptionKey.startsWith(lowerCaseKey) || lowerCaseKey.startsWith(lowerCaseOptionKey); - super("SectionPlanes", viewer); + if (isPartialMatch) { + bestSuggestion = bestSuggestion || "Did you mean '".concat(loader.id, ".").concat(key, "'?"); + } + } + } - this._freeControls = []; - this._sectionPlanes = viewer.scene.sectionPlanes; - this._controls = {}; - this._shownControlId = null; + return bestSuggestion; +} - if (cfg.overviewCanvasId !== null && cfg.overviewCanvasId !== undefined) { +function normalizeOptionsInternal(loader, options, url) { + const loaderDefaultOptions = loader.options || {}; + const mergedOptions = { ...loaderDefaultOptions + }; + addUrlOptions(mergedOptions, url); - const overviewCanvas = document.getElementById(cfg.overviewCanvasId); + if (mergedOptions.log === null) { + mergedOptions.log = new NullLog(); + } - if (!overviewCanvas) { - this.warn("Can't find overview canvas: '" + cfg.overviewCanvasId + "' - will create plugin without overview"); + mergeNestedFields(mergedOptions, getGlobalLoaderOptions()); + mergeNestedFields(mergedOptions, options); + return mergedOptions; +} - } else { +function mergeNestedFields(mergedOptions, options) { + for (const key in options) { + if (key in options) { + const value = options[key]; - this._overview = new Overview(this, { - overviewCanvas: overviewCanvas, - visible: cfg.overviewVisible, + if (isPureObject(value) && isPureObject(mergedOptions[key])) { + mergedOptions[key] = { ...mergedOptions[key], + ...options[key] + }; + } else { + mergedOptions[key] = options[key]; + } + } + } +} - onHoverEnterPlane: ((id) => { - this._overview.setPlaneHighlighted(id, true); - }), +function addUrlOptions(options, url) { + if (url && !('baseUri' in options)) { + options.baseUri = url; + } +} - onHoverLeavePlane: ((id) => { - this._overview.setPlaneHighlighted(id, false); - }), +function isLoaderObject(loader) { + var _loader; - onClickedPlane: ((id) => { - if (this.getShownControl() === id) { - this.hideControl(); - return; - } - this.showControl(id); - const sectionPlane = this.sectionPlanes[id]; - const sectionPlanePos = sectionPlane.pos; - tempAABB.set(this.viewer.scene.aabb); - math.getAABB3Center(tempAABB, tempVec3$3); - tempAABB[0] += sectionPlanePos[0] - tempVec3$3[0]; - tempAABB[1] += sectionPlanePos[1] - tempVec3$3[1]; - tempAABB[2] += sectionPlanePos[2] - tempVec3$3[2]; - tempAABB[3] += sectionPlanePos[0] - tempVec3$3[0]; - tempAABB[4] += sectionPlanePos[1] - tempVec3$3[1]; - tempAABB[5] += sectionPlanePos[2] - tempVec3$3[2]; - this.viewer.cameraFlight.flyTo({ - aabb: tempAABB, - fitFOV: 65 - }); - }), + if (!loader) { + return false; + } - onClickedNothing: (() => { - this.hideControl(); - }) - }); - } - } + if (Array.isArray(loader)) { + loader = loader[0]; + } - this._onSceneSectionPlaneCreated = viewer.scene.on("sectionPlaneCreated", (sectionPlane) => { + const hasExtensions = Array.isArray((_loader = loader) === null || _loader === void 0 ? void 0 : _loader.extensions); + return hasExtensions; +} +function normalizeLoader(loader) { + var _loader2, _loader3; - // SectionPlane created, either via SectionPlanesPlugin#createSectionPlane(), or by directly - // instantiating a SectionPlane independently of SectionPlanesPlugin, which can be done - // by BCFViewpointsPlugin#loadViewpoint(). + assert$5(loader, 'null loader'); + assert$5(isLoaderObject(loader), 'invalid loader'); + let options; - this._sectionPlaneCreated(sectionPlane); - }); - } + if (Array.isArray(loader)) { + options = loader[1]; + loader = loader[0]; + loader = { ...loader, + options: { ...loader.options, + ...options + } + }; + } - /** - * Sets if the overview canvas is visible. - * - * @param {Boolean} visible Whether or not the overview canvas is visible. - */ - setOverviewVisible(visible) { - if (this._overview) { - this._overview.setVisible(visible); - } - } + if ((_loader2 = loader) !== null && _loader2 !== void 0 && _loader2.parseTextSync || (_loader3 = loader) !== null && _loader3 !== void 0 && _loader3.parseText) { + loader.text = true; + } - /** - * Gets if the overview canvas is visible. - * - * @return {Boolean} True when the overview canvas is visible. - */ - getOverviewVisible() { - if (this._overview) { - return this._overview.getVisible(); - } - } + if (!loader.text) { + loader.binary = true; + } - /** - * Returns a map of the {@link SectionPlane}s created by this SectionPlanesPlugin. - * - * @returns {{String:SectionPlane}} A map containing the {@link SectionPlane}s, each mapped to its {@link SectionPlane#id}. - */ - get sectionPlanes() { - return this._sectionPlanes; - } + return loader; +} - /** - * Creates a {@link SectionPlane}. - * - * The {@link SectionPlane} will be registered by {@link SectionPlane#id} in {@link SectionPlanesPlugin#sectionPlanes}. - * - * @param {Object} params {@link SectionPlane} configuration. - * @param {String} [params.id] Unique ID to assign to the {@link SectionPlane}. Must be unique among all components in the {@link Viewer}'s {@link Scene}. Auto-generated when omitted. - * @param {Number[]} [params.pos=[0,0,0]] World-space position of the {@link SectionPlane}. - * @param {Number[]} [params.dir=[0,0,-1]] World-space vector indicating the orientation of the {@link SectionPlane}. - * @param {Boolean} [params.active=true] Whether the {@link SectionPlane} is initially active. Only clips while this is true. - * @returns {SectionPlane} The new {@link SectionPlane}. - */ - createSectionPlane(params = {}) { +const getGlobalLoaderRegistry = () => { + const state = getGlobalLoaderState(); + state.loaderRegistry = state.loaderRegistry || []; + return state.loaderRegistry; +}; +function getRegisteredLoaders() { + return getGlobalLoaderRegistry(); +} - if (params.id !== undefined && params.id !== null && this.viewer.scene.components[params.id]) { - this.error("Viewer component with this ID already exists: " + params.id); - delete params.id; - } +function isElectron(mockUserAgent) { + if (typeof window !== 'undefined' && typeof window.process === 'object' && window.process.type === 'renderer') { + return true; + } - // Note that SectionPlane constructor fires "sectionPlaneCreated" on the Scene, - // which SectionPlanesPlugin handles and calls #_sectionPlaneCreated to create gizmo and add to overview canvas. + if (typeof process !== 'undefined' && typeof process.versions === 'object' && Boolean(process.versions.electron)) { + return true; + } - const sectionPlane = new SectionPlane(this.viewer.scene, { - id: params.id, - pos: params.pos, - dir: params.dir, - active: true - }); - return sectionPlane; - } + const realUserAgent = typeof navigator === 'object' && typeof navigator.userAgent === 'string' && navigator.userAgent; + const userAgent = mockUserAgent || realUserAgent; - _sectionPlaneCreated(sectionPlane) { - const control = (this._freeControls.length > 0) ? this._freeControls.pop() : new Control(this); - control._setSectionPlane(sectionPlane); - control.setVisible(false); - this._controls[sectionPlane.id] = control; - if (this._overview) { - this._overview.addSectionPlane(sectionPlane); - } - sectionPlane.once("destroyed", () => { - this._sectionPlaneDestroyed(sectionPlane); - }); - } + if (userAgent && userAgent.indexOf('Electron') >= 0) { + return true; + } - /** - * Inverts the direction of {@link SectionPlane#dir} on every existing SectionPlane. - * - * Inverts all SectionPlanes, including those that were not created with SectionPlanesPlugin. - */ - flipSectionPlanes() { - const sectionPlanes = this.viewer.scene.sectionPlanes; - for (let id in sectionPlanes) { - const sectionPlane = sectionPlanes[id]; - sectionPlane.flipDir(); - } - } + return false; +} - /** - * Shows the 3D editing gizmo for a {@link SectionPlane}. - * - * @param {String} id ID of the {@link SectionPlane}. - */ - showControl(id) { - const control = this._controls[id]; - if (!control) { - this.error("Control not found: " + id); - return; - } - this.hideControl(); - control.setVisible(true); - if (this._overview) { - this._overview.setPlaneSelected(id, true); - } - this._shownControlId = id; - } +function isBrowser() { + const isNode = typeof process === 'object' && String(process) === '[object process]' && !process.browser; + return !isNode || isElectron(); +} - /** - * Gets the ID of the {@link SectionPlane} that the 3D editing gizmo is shown for. - * - * Returns ````null```` when the editing gizmo is not shown. - * - * @returns {String} ID of the the {@link SectionPlane} that the 3D editing gizmo is shown for, if shown, else ````null````. - */ - getShownControl() { - return this._shownControlId; - } +const globals = { + self: typeof self !== 'undefined' && self, + window: typeof window !== 'undefined' && window, + global: typeof global !== 'undefined' && global, + document: typeof document !== 'undefined' && document, + process: typeof process === 'object' && process +}; +const window_ = globals.window || globals.self || globals.global; +const process_ = globals.process || {}; - /** - * Hides the 3D {@link SectionPlane} editing gizmo if shown. - */ - hideControl() { - for (var id in this._controls) { - if (this._controls.hasOwnProperty(id)) { - this._controls[id].setVisible(false); - if (this._overview) { - this._overview.setPlaneSelected(id, false); - } - } - } - this._shownControlId = null; - } +const VERSION$6 = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'untranspiled source'; +isBrowser(); - /** - * Destroys a {@link SectionPlane} created by this SectionPlanesPlugin. - * - * @param {String} id ID of the {@link SectionPlane}. - */ - destroySectionPlane(id) { - var sectionPlane = this.viewer.scene.sectionPlanes[id]; - if (!sectionPlane) { - this.error("SectionPlane not found: " + id); - return; - } - this._sectionPlaneDestroyed(sectionPlane); - sectionPlane.destroy(); +function getStorage(type) { + try { + const storage = window[type]; + const x = '__storage_test__'; + storage.setItem(x, x); + storage.removeItem(x); + return storage; + } catch (e) { + return null; + } +} - if (id === this._shownControlId) { - this._shownControlId = null; - } - } +class LocalStorage { + constructor(id) { + let defaultSettings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + let type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'sessionStorage'; - _sectionPlaneDestroyed(sectionPlane) { - if (this._overview) { - this._overview.removeSectionPlane(sectionPlane); - } - const control = this._controls[sectionPlane.id]; - if (!control) { - return; - } - control.setVisible(false); - control._setSectionPlane(null); - delete this._controls[sectionPlane.id]; - this._freeControls.push(control); - } + _defineProperty(this, "storage", void 0); - /** - * Destroys all {@link SectionPlane}s created by this SectionPlanesPlugin. - */ - clear() { - const ids = Object.keys(this._sectionPlanes); - for (var i = 0, len = ids.length; i < len; i++) { - this.destroySectionPlane(ids[i]); - } - } + _defineProperty(this, "id", void 0); - /** - * @private - */ - send(name, value) { - switch (name) { + _defineProperty(this, "config", {}); - case "snapshotStarting": // Viewer#getSnapshot() about to take snapshot - hide controls - for (let id in this._controls) { - if (this._controls.hasOwnProperty(id)) { - this._controls[id].setCulled(true); - } - } - break; + this.storage = getStorage(type); + this.id = id; + this.config = {}; + Object.assign(this.config, defaultSettings); - case "snapshotFinished": // Viewer#getSnapshot() finished taking snapshot - show controls again - for (let id in this._controls) { - if (this._controls.hasOwnProperty(id)) { - this._controls[id].setCulled(false); - } - } - break; + this._loadConfiguration(); + } - case "clearSectionPlanes": - this.clear(); - break; - } - } + getConfiguration() { + return this.config; + } - /** - * Destroys this SectionPlanesPlugin. - * - * Also destroys each {@link SectionPlane} created by this SectionPlanesPlugin. - * - * Does not destroy the canvas the SectionPlanesPlugin was configured with. - */ - destroy() { - this.clear(); - if (this._overview) { - this._overview.destroy(); - } - this._destroyFreeControls(); - super.destroy(); + setConfiguration(configuration) { + this.config = {}; + return this.updateConfiguration(configuration); + } + + updateConfiguration(configuration) { + Object.assign(this.config, configuration); + + if (this.storage) { + const serialized = JSON.stringify(this.config); + this.storage.setItem(this.id, serialized); } - _destroyFreeControls() { - var control = this._freeControls.pop(); - while (control) { - control._destroy(); - control = this._freeControls.pop(); - } - this.viewer.scene.off(this._onSceneSectionPlaneCreated); + return this; + } + + _loadConfiguration() { + let configuration = {}; + + if (this.storage) { + const serializedConfiguration = this.storage.getItem(this.id); + configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {}; } + + Object.assign(this.config, configuration); + return this; + } + } -/** - * @desc A Skybox. - */ -class Skybox extends Component { +function formatTime(ms) { + let formatted; - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this PointLight as well. - * @param {*} [cfg] Skybox configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {Scene}, generated automatically when omitted. - * @param {String} [cfg.src=null] Path to skybox texture - * @param {String} [cfg.encoding="linear"] Texture encoding format. See the {@link Texture#encoding} property for more info. - * @param {Number} [cfg.size=1000] Size of this Skybox, given as the distance from the center at ````[0,0,0]```` to each face. - * @param {Boolean} [cfg.active=true] True when this Skybox is visible. - */ - constructor(owner, cfg = {}) { + if (ms < 10) { + formatted = "".concat(ms.toFixed(2), "ms"); + } else if (ms < 100) { + formatted = "".concat(ms.toFixed(1), "ms"); + } else if (ms < 1000) { + formatted = "".concat(ms.toFixed(0), "ms"); + } else { + formatted = "".concat((ms / 1000).toFixed(2), "s"); + } - super(owner, cfg); + return formatted; +} +function leftPad(string) { + let length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 8; + const padLength = Math.max(length - string.length, 0); + return "".concat(' '.repeat(padLength)).concat(string); +} - this._skyboxMesh = new Mesh(this, { +function formatImage(image, message, scale) { + let maxWidth = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 600; + const imageUrl = image.src.replace(/\(/g, '%28').replace(/\)/g, '%29'); - geometry: new ReadableGeometry(this, { // Box-shaped geometry - primitive: "triangles", - positions: [ - 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // v0-v1-v2-v3 front - 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // v0-v3-v4-v5 right - 1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // v0-v5-v6-v1 top - -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // v1-v6-v7-v2 left - -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, // v7-v4-v3-v2 bottom - 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 // v4-v7-v6-v5 back - ], - uv: [ - 0.5, 0.6666, 0.25, 0.6666, 0.25, 0.3333, 0.5, 0.3333, 0.5, 0.6666, 0.5, 0.3333, 0.75, 0.3333, 0.75, 0.6666, - 0.5, 0.6666, 0.5, 1, 0.25, 1, 0.25, 0.6666, 0.25, 0.6666, 0.0, 0.6666, 0.0, 0.3333, 0.25, 0.3333, - 0.25, 0, 0.50, 0, 0.50, 0.3333, 0.25, 0.3333, 0.75, 0.3333, 1.0, 0.3333, 1.0, 0.6666, 0.75, 0.6666 - ], - indices: [ - 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, - 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 - ] - }), - background: true, - scale: [2000, 2000, 2000], // Overridden when we initialize the 'size' property, below - rotation: [0, -90, 0], - material: new PhongMaterial(this, { - ambient: [0, 0, 0], - diffuse: [0, 0, 0], - specular: [0, 0, 0], - emissive: [1, 1, 1], - emissiveMap: new Texture(this, { - src: cfg.src, - flipY: true, - wrapS: "clampToEdge", - wrapT: "clampToEdge", - encoding: cfg.encoding || "sRGB" - }), - backfaces: true // Show interior faces of our skybox geometry - }), - // stationary: true, - visible: false, - pickable: false, - clippable: false, - collidable: false - }); + if (image.width > maxWidth) { + scale = Math.min(scale, maxWidth / image.width); + } - this.size = cfg.size; // Sets 'xyz' property on the Mesh's Scale transform - this.active = cfg.active; - } + const width = image.width * scale; + const height = image.height * scale; + const style = ['font-size:1px;', "padding:".concat(Math.floor(height / 2), "px ").concat(Math.floor(width / 2), "px;"), "line-height:".concat(height, "px;"), "background:url(".concat(imageUrl, ");"), "background-size:".concat(width, "px ").concat(height, "px;"), 'color:transparent;'].join(''); + return ["".concat(message, " %c+"), style]; +} +let COLOR; - /** - * Sets the size of this Skybox, given as the distance from the center at [0,0,0] to each face. - * - * Default value is ````1000````. - * - * @param {Number} value The size. - */ - set size(value) { - this._size = value || 1000; - this._skyboxMesh.scale = [this._size, this._size, this._size]; - } +(function (COLOR) { + COLOR[COLOR["BLACK"] = 30] = "BLACK"; + COLOR[COLOR["RED"] = 31] = "RED"; + COLOR[COLOR["GREEN"] = 32] = "GREEN"; + COLOR[COLOR["YELLOW"] = 33] = "YELLOW"; + COLOR[COLOR["BLUE"] = 34] = "BLUE"; + COLOR[COLOR["MAGENTA"] = 35] = "MAGENTA"; + COLOR[COLOR["CYAN"] = 36] = "CYAN"; + COLOR[COLOR["WHITE"] = 37] = "WHITE"; + COLOR[COLOR["BRIGHT_BLACK"] = 90] = "BRIGHT_BLACK"; + COLOR[COLOR["BRIGHT_RED"] = 91] = "BRIGHT_RED"; + COLOR[COLOR["BRIGHT_GREEN"] = 92] = "BRIGHT_GREEN"; + COLOR[COLOR["BRIGHT_YELLOW"] = 93] = "BRIGHT_YELLOW"; + COLOR[COLOR["BRIGHT_BLUE"] = 94] = "BRIGHT_BLUE"; + COLOR[COLOR["BRIGHT_MAGENTA"] = 95] = "BRIGHT_MAGENTA"; + COLOR[COLOR["BRIGHT_CYAN"] = 96] = "BRIGHT_CYAN"; + COLOR[COLOR["BRIGHT_WHITE"] = 97] = "BRIGHT_WHITE"; +})(COLOR || (COLOR = {})); - /** - * Gets the size of this Skybox, given as the distance from the center at [0,0,0] to each face. - * - * Default value is ````1000````. - * - * @returns {Number} The size. - */ - get size() { - return this._size; - } +function getColor(color) { + return typeof color === 'string' ? COLOR[color.toUpperCase()] || COLOR.WHITE : color; +} - /** - * Sets whether this Skybox is visible or not. - * - * Default value is ````true````. - * - * @param {Boolean} active Whether to make active or not. - */ - set active(active) { - this._skyboxMesh.visible = active; +function addColor(string, color, background) { + if (!isBrowser && typeof string === 'string') { + if (color) { + color = getColor(color); + string = "\x1B[".concat(color, "m").concat(string, "\x1B[39m"); } - /** - * Gets if this Skybox is visible or not. - * - * Default active is ````true````. - * - * @returns {Boolean} ````true```` if the Skybox is active. - */ - get active() { - return this._skyboxMesh.visible; + if (background) { + color = getColor(background); + string = "\x1B[".concat(background + 10, "m").concat(string, "\x1B[49m"); } + } + + return string; } -/** - * {@link Viewer} plugin that manages skyboxes - * - * @example - * - * // Create a Viewer - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * // Add a GLTFModelsPlugin - * var gltfLoaderPlugin = new GLTFModelsPlugin(viewer, { - * id: "GLTFModels" // Default value - * }); - * - * // Add a SkyboxesPlugin - * var skyboxesPlugin = new SkyboxesPlugin(viewer, { - * id: "Skyboxes" // Default value - * }); - * - * // Load a glTF model - * const model = gltfLoaderPlugin.load({ - * id: "myModel", - * src: "./models/gltf/mygltfmodel.gltf" - * }); - * - * // Create three directional World-space lights. "World" means that they will appear as if part - * // of the world, instead of "View", where they move with the user's head. - * - * skyboxesPlugin.createLight({ - * id: "keyLight", - * dir: [0.8, -0.6, -0.8], - * color: [1.0, 0.3, 0.3], - * intensity: 1.0, - * space: "world" - * }); - * - * skyboxesPlugin.createLight({ - * id: "fillLight", - * dir: [-0.8, -0.4, -0.4], - * color: [0.3, 1.0, 0.3], - * intensity: 1.0, - * space: "world" - * }); - * - * skyboxesPlugin.createDirLight({ - * id: "rimLight", - * dir: [0.2, -0.8, 0.8], - * color: [0.6, 0.6, 0.6], - * intensity: 1.0, - * space: "world" - * }); - * - * @class SkyboxesPlugin - */ -class SkyboxesPlugin extends Plugin { +function autobind(obj) { + let predefined = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ['constructor']; + const proto = Object.getPrototypeOf(obj); + const propNames = Object.getOwnPropertyNames(proto); - constructor(viewer) { - super("skyboxes", viewer); - this.skyboxes = {}; + for (const key of propNames) { + if (typeof obj[key] === 'function') { + if (!predefined.find(name => key === name)) { + obj[key] = obj[key].bind(obj); + } } + } +} - /** - * @private - */ - send(name, value) { - switch (name) { - case "clear": - this.clear(); - break; - } - } +function assert$2(condition, message) { + if (!condition) { + throw new Error(message || 'Assertion failed'); + } +} - /** - Creates a skybox. +function getHiResTimestamp() { + let timestamp; - @param {String} id Unique ID to assign to the skybox. - @param {Object} params Skybox configuration. - @param {Boolean} [params.active=true] Whether the skybox plane is initially active. Only skyboxes while this is true. - @returns {Skybox} The new skybox. - */ - createSkybox(id, params) { - if (this.viewer.scene.components[id]) { - this.error("Component with this ID already exists: " + id); - return this; - } - var skybox = new Skybox(this.viewer.scene, { - id: id, - pos: params.pos, - dir: params.dir, - active: true - }); - this.skyboxes[id] = skybox; - return skybox; - } + if (isBrowser && 'performance' in window_) { + var _window$performance, _window$performance$n; - /** - Destroys a skybox. - @param id - */ - destroySkybox(id) { - var skybox = this.skyboxes[id]; - if (!skybox) { - this.error("Skybox not found: " + id); - return; - } - skybox.destroy(); - } + timestamp = window_ === null || window_ === void 0 ? void 0 : (_window$performance = window_.performance) === null || _window$performance === void 0 ? void 0 : (_window$performance$n = _window$performance.now) === null || _window$performance$n === void 0 ? void 0 : _window$performance$n.call(_window$performance); + } else if ('hrtime' in process_) { + var _process$hrtime; - /** - Destroys all skyboxes. - */ - clear() { - var ids = Object.keys(this.viewer.scene.skyboxes); - for (var i = 0, len = ids.length; i < len; i++) { - this.destroySkybox(ids[i]); - } - } + const timeParts = process_ === null || process_ === void 0 ? void 0 : (_process$hrtime = process_.hrtime) === null || _process$hrtime === void 0 ? void 0 : _process$hrtime.call(process_); + timestamp = timeParts[0] * 1000 + timeParts[1] / 1e6; + } else { + timestamp = Date.now(); + } - /** - * Destroys this plugin. - * - * Clears skyboxes from the Viewer first. - */ - destroy() { - this.clear(); - super.clear(); - } + return timestamp; } -/** - * Default data access strategy for {@link STLLoaderPlugin}. - * - * This implementation simply loads STL files using XMLHttpRequest. - */ -class STLDefaultDataSource { +const originalConsole = { + debug: isBrowser ? console.debug || console.log : console.log, + log: console.log, + info: console.info, + warn: console.warn, + error: console.error +}; +const DEFAULT_SETTINGS = { + enabled: true, + level: 0 +}; - /** - * Gets STL data. - * - * @param {String|Number} src Identifies the STL file. - * @param {Function} ok Fired on successful loading of the STL file. - * @param {Function} error Fired on error while loading the STL file. - */ - getSTL(src, ok, error) { - const request = new XMLHttpRequest(); - request.overrideMimeType("application/json"); - request.open('GET', src, true); - request.responseType = 'arraybuffer'; - request.onreadystatechange = function () { - if (request.readyState === 4) { - if (request.status === 200) { - ok(request.response); - } else { - error(request.statusText); - } - } - }; - request.send(null); - } -} +function noop() {} -const tempVec3a$7 = math.vec3(); +const cache = {}; +const ONCE = { + once: true +}; +class Log { + constructor() { + let { + id + } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { + id: '' + }; -/** - * @private - */ -class STLSceneGraphLoader { + _defineProperty(this, "id", void 0); - load(plugin, modelNode, src, options, ok, error) { + _defineProperty(this, "VERSION", VERSION$6); - options = options || {}; + _defineProperty(this, "_startTs", getHiResTimestamp()); - const spinner = plugin.viewer.scene.canvas.spinner; - spinner.processes++; + _defineProperty(this, "_deltaTs", getHiResTimestamp()); - plugin.dataSource.getSTL(src, function (data) { // OK - parse(plugin, modelNode, data, options); - try { - const binData = ensureBinary(data); - if (isBinary(binData)) { - parseBinary(plugin, binData, modelNode, options); - } else { - parseASCII(plugin, ensureString(data), modelNode, options); - } - spinner.processes--; - core.scheduleTask(function () { - modelNode.fire("loaded", true, false); - }); - if (ok) { - ok(); - } - } catch (e) { - spinner.processes--; - plugin.error(e); - if (error) { - error(e); - } - modelNode.fire("error", e); - } - }, - function (msg) { - spinner.processes--; - plugin.error(msg); - if (error) { - error(msg); - } - modelNode.fire("error", msg); - }); - } + _defineProperty(this, "_storage", void 0); - parse(plugin, modelNode, data, options) { - const spinner = plugin.viewer.scene.canvas.spinner; - spinner.processes++; - try { - const binData = ensureBinary(data); - if (isBinary(binData)) { - parseBinary(plugin, binData, modelNode, options); - } else { - parseASCII(plugin, ensureString(data), modelNode, options); - } - spinner.processes--; - core.scheduleTask(function () { - modelNode.fire("loaded", true, false); - }); - } catch (e) { - spinner.processes--; - modelNode.fire("error", e); - } - } -} + _defineProperty(this, "userData", {}); -function parse(plugin, modelNode, data, options) { - try { - const binData = ensureBinary(data); - if (isBinary(binData)) { - parseBinary(plugin, binData, modelNode, options); - } else { - parseASCII(plugin, ensureString(data), modelNode, options); - } - } catch (e) { - modelNode.fire("error", e); - } -} + _defineProperty(this, "LOG_THROTTLE_TIMEOUT", 0); -function isBinary(data) { - const reader = new DataView(data); - const numFaces = reader.getUint32(80, true); - const faceSize = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8); - const numExpectedBytes = 80 + (32 / 8) + (numFaces * faceSize); - if (numExpectedBytes === reader.byteLength) { - return true; - } - const solid = [115, 111, 108, 105, 100]; - for (var i = 0; i < 5; i++) { - if (solid[i] !== reader.getUint8(i, false)) { - return true; - } - } - return false; -} + this.id = id; + this._storage = new LocalStorage("__probe-".concat(this.id, "__"), DEFAULT_SETTINGS); + this.userData = {}; + this.timeStamp("".concat(this.id, " started")); + autobind(this); + Object.seal(this); + } -function parseBinary(plugin, data, modelNode, options) { - const reader = new DataView(data); - const faces = reader.getUint32(80, true); - let r; - let g; - let b; - let hasColors = false; - let colors; - let defaultR; - let defaultG; - let defaultB; - let lastR = null; - let lastG = null; - let lastB = null; - let newMesh = false; - for (let index = 0; index < 80 - 10; index++) { - if ((reader.getUint32(index, false) === 0x434F4C4F /*COLO*/) && - (reader.getUint8(index + 4) === 0x52 /*'R'*/) && - (reader.getUint8(index + 5) === 0x3D /*'='*/)) { - hasColors = true; - colors = []; - defaultR = reader.getUint8(index + 6) / 255; - defaultG = reader.getUint8(index + 7) / 255; - defaultB = reader.getUint8(index + 8) / 255; - reader.getUint8(index + 9) / 255; - } - } - const material = new MetallicMaterial(modelNode, { // Share material with all meshes - roughness: 0.5 + set level(newLevel) { + this.setLevel(newLevel); + } + + get level() { + return this.getLevel(); + } + + isEnabled() { + return this._storage.config.enabled; + } + + getLevel() { + return this._storage.config.level; + } + + getTotal() { + return Number((getHiResTimestamp() - this._startTs).toPrecision(10)); + } + + getDelta() { + return Number((getHiResTimestamp() - this._deltaTs).toPrecision(10)); + } + + set priority(newPriority) { + this.level = newPriority; + } + + get priority() { + return this.level; + } + + getPriority() { + return this.level; + } + + enable() { + let enabled = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; + + this._storage.updateConfiguration({ + enabled }); - // var material = new PhongMaterial(modelNode, { // Share material with all meshes - // diffuse: [0.4, 0.4, 0.4], - // reflectivity: 1, - // specular: [0.5, 0.5, 1.0] - // }); - let dataOffset = 84; - let faceLength = 12 * 4 + 2; - let positions = []; - let normals = []; - let splitMeshes = options.splitMeshes; - for (let face = 0; face < faces; face++) { - let start = dataOffset + face * faceLength; - let normalX = reader.getFloat32(start, true); - let normalY = reader.getFloat32(start + 4, true); - let normalZ = reader.getFloat32(start + 8, true); - if (hasColors) { - let packedColor = reader.getUint16(start + 48, true); - if ((packedColor & 0x8000) === 0) { - r = (packedColor & 0x1F) / 31; - g = ((packedColor >> 5) & 0x1F) / 31; - b = ((packedColor >> 10) & 0x1F) / 31; - } else { - r = defaultR; - g = defaultG; - b = defaultB; - } - if (splitMeshes && r !== lastR || g !== lastG || b !== lastB) { - if (lastR !== null) { - newMesh = true; - } - lastR = r; - lastG = g; - lastB = b; - } - } - for (let i = 1; i <= 3; i++) { - let vertexstart = start + i * 12; - positions.push(reader.getFloat32(vertexstart, true)); - positions.push(reader.getFloat32(vertexstart + 4, true)); - positions.push(reader.getFloat32(vertexstart + 8, true)); - normals.push(normalX, normalY, normalZ); - if (hasColors) { - colors.push(r, g, b, 1); // TODO: handle alpha - } - } - if (splitMeshes && newMesh) { - addMesh(modelNode, positions, normals, colors, material, options); - positions = []; - normals = []; - colors = colors ? [] : null; - newMesh = false; - } - } - if (positions.length > 0) { - addMesh(modelNode, positions, normals, colors, material, options); - } -} -function parseASCII(plugin, data, modelNode, options) { - const faceRegex = /facet([\s\S]*?)endfacet/g; - let faceCounter = 0; - const floatRegex = /[\s]+([+-]?(?:\d+.\d+|\d+.|\d+|.\d+)(?:[eE][+-]?\d+)?)/.source; - const vertexRegex = new RegExp('vertex' + floatRegex + floatRegex + floatRegex, 'g'); - const normalRegex = new RegExp('normal' + floatRegex + floatRegex + floatRegex, 'g'); - const positions = []; - const normals = []; - const colors = null; - let normalx; - let normaly; - let normalz; - let result; - let verticesPerFace; - let normalsPerFace; - let text; - while ((result = faceRegex.exec(data)) !== null) { - verticesPerFace = 0; - normalsPerFace = 0; - text = result[0]; - while ((result = normalRegex.exec(text)) !== null) { - normalx = parseFloat(result[1]); - normaly = parseFloat(result[2]); - normalz = parseFloat(result[3]); - normalsPerFace++; - } - while ((result = vertexRegex.exec(text)) !== null) { - positions.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])); - normals.push(normalx, normaly, normalz); - verticesPerFace++; - } - if (normalsPerFace !== 1) { - plugin.error("Error in normal of face " + faceCounter); - } - if (verticesPerFace !== 3) { - plugin.error("Error in positions of face " + faceCounter); - } - faceCounter++; - } - const material = new MetallicMaterial(modelNode, { - roughness: 0.5 + return this; + } + + setLevel(level) { + this._storage.updateConfiguration({ + level }); - // var material = new PhongMaterial(modelNode, { - // diffuse: [0.4, 0.4, 0.4], - // reflectivity: 1, - // specular: [0.5, 0.5, 1.0] - // }); - addMesh(modelNode, positions, normals, colors, material, options); -} -function addMesh(modelNode, positions, normals, colors, material, options) { + return this; + } - const indices = new Int32Array(positions.length / 3); - for (let ni = 0, len = indices.length; ni < len; ni++) { - indices[ni] = ni; - } + get(setting) { + return this._storage.config[setting]; + } - normals = normals && normals.length > 0 ? normals : null; - colors = colors && colors.length > 0 ? colors : null; + set(setting, value) { + this._storage.updateConfiguration({ + [setting]: value + }); + } - if (options.smoothNormals) { - math.faceToVertexNormals(positions, normals, options); + settings() { + if (console.table) { + console.table(this._storage.config); + } else { + console.log(this._storage.config); } + } - const origin = tempVec3a$7; + assert(condition, message) { + assert$2(condition, message); + } - worldToRTCPositions(positions, positions, origin); + warn(message) { + return this._getLogFunction(0, message, originalConsole.warn, arguments, ONCE); + } - const geometry = new ReadableGeometry(modelNode, { - primitive: "triangles", - positions: positions, - normals: normals, - colors: colors, - indices: indices - }); + error(message) { + return this._getLogFunction(0, message, originalConsole.error, arguments); + } - const mesh = new Mesh(modelNode, { - origin: (origin[0] !== 0 || origin[1] !== 0 || origin[2] !== 0) ? origin : null, - geometry: geometry, - material: material, - edges: options.edges + deprecated(oldUsage, newUsage) { + return this.warn("`".concat(oldUsage, "` is deprecated and will be removed in a later version. Use `").concat(newUsage, "` instead")); + } + + removed(oldUsage, newUsage) { + return this.error("`".concat(oldUsage, "` has been removed. Use `").concat(newUsage, "` instead")); + } + + probe(logLevel, message) { + return this._getLogFunction(logLevel, message, originalConsole.log, arguments, { + time: true, + once: true }); + } - modelNode.addChild(mesh); -} + log(logLevel, message) { + return this._getLogFunction(logLevel, message, originalConsole.debug, arguments); + } -function ensureString(buffer) { - if (typeof buffer !== 'string') { - return decodeText(new Uint8Array(buffer)); - } - return buffer; -} + info(logLevel, message) { + return this._getLogFunction(logLevel, message, console.info, arguments); + } -function ensureBinary(buffer) { - if (typeof buffer === 'string') { - const arrayBuffer = new Uint8Array(buffer.length); - for (let i = 0; i < buffer.length; i++) { - arrayBuffer[i] = buffer.charCodeAt(i) & 0xff; // implicitly assumes little-endian - } - return arrayBuffer.buffer || arrayBuffer; - } else { - return buffer; + once(logLevel, message) { + for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { + args[_key - 2] = arguments[_key]; } -} -function decodeText(array) { - if (typeof TextDecoder !== 'undefined') { - return new TextDecoder().decode(array); + return this._getLogFunction(logLevel, message, originalConsole.debug || originalConsole.info, arguments, ONCE); + } + + table(logLevel, table, columns) { + if (table) { + return this._getLogFunction(logLevel, table, console.table || noop, columns && [columns], { + tag: getTableHeader(table) + }); } - let s = ''; - for (let i = 0, il = array.length; i < il; i++) { - s += String.fromCharCode(array[i]); // Implicitly assumes little-endian. + + return noop; + } + + image(_ref) { + let { + logLevel, + priority, + image, + message = '', + scale = 1 + } = _ref; + + if (!this._shouldLog(logLevel || priority)) { + return noop; } - return decodeURIComponent(escape(s)); -} -/** - * {@link Viewer} plugin that loads models from STL files. - * - * ## Overview - * - * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. - * * Creates an {@link Entity} for each object within the model, which will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. - * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. - * * Supports both binary and ASCII formats. - * * Supports double-precision vertex positions. - * * Supports custom data source configuration. - * - * ## Smoothing STL Normals - * - * STL models are normally flat-shaded, however providing a ````smoothNormals```` parameter when loading gives a smooth - * appearance. Triangles in STL are disjoint, where each triangle has its own separate vertex positions, normals and - * (optionally) colors. This means that you can have gaps between triangles in an STL model. Normals for each triangle - * are perpendicular to the triangle's surface, which gives the model a faceted appearance by default. - * - * The ```smoothNormals``` parameter causes the plugin to recalculate the STL normals, so that each normal's direction is - * the average of the orientations of the triangles adjacent to its vertex. When smoothing, each vertex normal is set to - * the average of the orientations of all other triangles that have a vertex at the same position, excluding those triangles - * whose direction deviates from the direction of the vertice's triangle by a threshold given in - * the ````smoothNormalsAngleThreshold```` loading parameter. This makes smoothing robust for hard edges. - * - * ## Creating Entities for Objects - * - * An STL model is normally a single mesh, however providing a ````splitMeshes```` parameter when loading - * will create a separate object {@link Entity} for each group of faces that share the same vertex colors. This option - * only works with binary STL files. - * - * See the {@link STLLoaderPlugin#load} method for more info on loading options. - * - * ## Usage - * - * In the example below, we'll use an STLLoaderPlugin to load an STL model of a spur gear. When the model has loaded, - * we'll use the {@link CameraFlightAnimation} to fly the {@link Camera} to look at boundary of the model. We'll - * then get the model's {@link Entity} from the {@link Scene} and highlight the whole model. - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_STL_SpurGear)] - * - * ````javascript - * // Create a xeokit Viewer - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * // Add an STLLoaderPlugin to the Viewer - * var plugin = new STLLoaderPlugin(viewer); - * - * // Load the STL model - * var model = plugin.load({ // Model is an Entity - * id: "myModel", - * src: "./models/stl/binary/spurGear.stl", - * scale: [0.1, 0.1, 0.1], - * rotate: [90, 0, 0], - * translate: [100,0,0], - * edges: true, - * smoothNormals: true, // Default - * smoothNormalsAngleThreshold: 20, // Default - * splitMeshes: true // Default - * }); - * - * // When the model has loaded, fit it to view - * model.on("loaded", function() { // Model is an Entity - * viewer.cameraFlight.flyTo(model); - * }); - * - * // Find the model Entity by ID - * model = viewer.scene.models["myModel"]; - * - * // Update properties of the model Entity - * model.highlight = [1,0,0]; - * - * // Destroy the model Entity - * model.destroy(); - * ```` - * - * ## Loading from a Pre-Loaded STL File - * - * If we already have our STL file in memory (perhaps pre-loaded, or even generated in-client), then we can just pass that - * file data straight into the {@link STLLoaderPlugin#load} method. In the example below, to show how it's done, we'll pre-load - * our STL file data, then pass it straight into that method. - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_STL_dataAsParam)] - * - * ````javascript - * loadSTL("./models/stl/binary/spurGear.stl", (stlData) =>{ - * - * const model = stlLoader.load({ - * id: "myModel", - * stl: stlData, - * smoothNormals: true - * }); - * - * model.on("loaded", () => { - * viewer.cameraFlight.jumpTo(model); - * viewer.scene.on("tick", () => { - * viewer.camera.orbitYaw(0.4); - * }) - * }); - * }) - * - * function loadSTL(src, ok, error) { - * const request = new XMLHttpRequest(); - * request.overrideMimeType("application/json"); - * request.open('GET', src, true); - * request.responseType = 'arraybuffer'; - * request.onreadystatechange = function () { - * if (request.readyState === 4) { - * if (request.status === 200) { - * ok(request.response); - * } else if (error) { - * error(request.statusText); - * } - * } - * }; - * request.send(null); - * } - *```` - * - * ## Configuring a Custom Data Source - * - * In the example below, we'll create the STLLoaderPlugin again, this time configuring it with a - * custom data source object, through which it can load STL files. For this example, our data source just loads - * them via HTTP, for simplicity. Once we've created the STLLoaderPlugin, we'll load our STL file as before. - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_STL_dataSource)] - * - * ````javascript - * // Our custom STL data access strategy - implementation happens to be the same as STLDefaultDataSource - * - * class MyDataSource { - * getSTL(src, ok, error) { - * const request = new XMLHttpRequest(); - * request.overrideMimeType("application/json"); - * request.open('GET', src, true); - * request.responseType = 'arraybuffer'; - * request.onreadystatechange = function () { - * if (request.readyState === 4) { - * if (request.status === 200) { - * ok(request.response); - * } else { - * error(request.statusText); - * } - * } - * }; - * request.send(null); - * } - * } - * - * const stlLoader = new STLLoaderPlugin(viewer, { - * dataSource: new MyDataSource() - * }); - * - * // Load the STL model as before - * var model = plugin.load({ - * id: "myModel", - * src: "./models/stl/binary/spurGear.stl", - * scale: [0.1, 0.1, 0.1], - * rotate: [90, 0, 0], - * translate: [100,0,0], - * edges: true, - * smoothNormals: true, // Default - * smoothNormalsAngleThreshold: 20, // Default - * splitMeshes: true // Default - * }); - * - * //... - *```` - * - * @class STLLoaderPlugin - */ -class STLLoaderPlugin extends Plugin { + return isBrowser ? logImageInBrowser({ + image, + message, + scale + }) : logImageInNode({ + image, + message, + scale + }); + } - /** - * @constructor - * - * @param {Viewer} viewer The Viewer. - * @param {Object} [cfg] Plugin configuration. - * @param {String} [cfg.id="STLLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Object} [cfg.dataSource] A custom data source through which the STLLoaderPlugin can load STL files. Defaults to an instance of {@link STLDefaultDataSource}, which loads over HTTP. - */ - constructor(viewer, cfg = {}) { + time(logLevel, message) { + return this._getLogFunction(logLevel, message, console.time ? console.time : console.info); + } - super("STLLoader", viewer, cfg); + timeEnd(logLevel, message) { + return this._getLogFunction(logLevel, message, console.timeEnd ? console.timeEnd : console.info); + } - /** - * @private - */ - this._sceneGraphLoader = new STLSceneGraphLoader(); + timeStamp(logLevel, message) { + return this._getLogFunction(logLevel, message, console.timeStamp || noop); + } - this.dataSource = cfg.dataSource; - } + group(logLevel, message) { + let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { + collapsed: false + }; + const options = normalizeArguments({ + logLevel, + message, + opts + }); + const { + collapsed + } = opts; + options.method = (collapsed ? console.groupCollapsed : console.group) || console.info; + return this._getLogFunction(options); + } - /** - * Sets a custom data source through which the STLLoaderPlugin can load STL files. - * - * Default value is {@link STLDefaultDataSource}, which loads via an XMLHttpRequest. - * - * @type {Object} - */ - set dataSource(value) { - this._dataSource = value || new STLDefaultDataSource(); - } + groupCollapsed(logLevel, message) { + let opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + return this.group(logLevel, message, Object.assign({}, opts, { + collapsed: true + })); + } - /** - * Gets the custom data source through which the STLLoaderPlugin can load STL files. - * - * Default value is {@link STLDefaultDataSource}, which loads via an XMLHttpRequest. - * - * @type {Object} - */ - get dataSource() { - return this._dataSource; - } + groupEnd(logLevel) { + return this._getLogFunction(logLevel, '', console.groupEnd || noop); + } - /** - * Loads an STL model from a file into this STLLoaderPlugin's {@link Viewer}. - * - * @param {*} params Loading parameters. - * @param {String} params.id ID to assign to the model's root {@link Entity}, unique among all components in the Viewer's {@link Scene}. - * @param {String} [params.src] Path to an STL file. Overrides the ````stl```` parameter. - * @param {String} [params.stl] Contents of an STL file, either binary of ASCII. Overridden by the ````src```` parameter. - * @param {Boolean} [params.edges=false] Whether or not to renders the model with edges emphasized. - * @param {Number[]} [params.origin=[0,0,0]] The model's World-space double-precision 3D origin. Use this to position the model within xeokit's World coordinate system, using double-precision coordinates. - * @param {Number[]} [params.position=[0,0,0]] The model single-precision 3D position, relative to the ````origin```` parameter. - * @param {Number[]} [params.scale=[1,1,1]] The model's scale. - * @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, given as Euler angles in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. Relative to ````origin````. - * @param {Boolean} [params.backfaces=false] When true, allows visible backfaces, wherever specified in the STL. When false, ignores backfaces. - * @param {Boolean} [params.smoothNormals=true] When true, automatically converts face-oriented normals to vertex normals for a smooth appearance. - * @param {Number} [params.smoothNormalsAngleThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. - * @param {Number} [params.edgeThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. - * @param {Boolean} [params.splitMeshes=true] When true, creates a separate {@link Mesh} for each group of faces that share the same vertex colors. Only works with binary STL. - * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} - */ - load(params) { + withGroup(logLevel, message, func) { + this.group(logLevel, message)(); - if (params.id && this.viewer.scene.components[params.id]) { - this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); - delete params.id; - } + try { + func(); + } finally { + this.groupEnd(logLevel)(); + } + } - const modelNode = new Node$1(this.viewer.scene, utils.apply(params, { - isModel: true - })); + trace() { + if (console.trace) { + console.trace(); + } + } - const src = params.src; - const stl = params.stl; + _shouldLog(logLevel) { + return this.isEnabled() && this.getLevel() >= normalizeLogLevel(logLevel); + } - if (!src && !stl) { - this.error("load() param expected: either 'src' or 'stl'"); - return modelNode; - } + _getLogFunction(logLevel, message, method, args, opts) { + if (this._shouldLog(logLevel)) { + opts = normalizeArguments({ + logLevel, + message, + args, + opts + }); + method = method || opts.method; + assert$2(method); + opts.total = this.getTotal(); + opts.delta = this.getDelta(); + this._deltaTs = getHiResTimestamp(); + const tag = opts.tag || opts.message; - if (src) { - this._sceneGraphLoader.load(this, modelNode, src, params); + if (opts.once) { + if (!cache[tag]) { + cache[tag] = getHiResTimestamp(); } else { - this._sceneGraphLoader.parse(this, modelNode, stl, params); + return noop; } + } - return modelNode; + message = decorateMessage(this.id, opts.message, opts); + return method.bind(console, message, ...opts.args); } -} -/** - * @desc Information about an ````IfcBuildingStorey````. - * - * These are provided by a {@link StoreyViewsPlugin}. - */ -class Storey { + return noop; + } - /** - * @private - */ - constructor(plugin, aabb, modelId, storeyId, numObjects) { +} - /** - * The {@link StoreyViewsPlugin} this Storey belongs to. - * - * @property plugin - * @type {StoreyViewsPlugin} - */ - this.plugin = plugin; +_defineProperty(Log, "VERSION", VERSION$6); - /** - * ID of the IfcBuildingStorey. - * - * This matches IDs of the IfcBuildingStorey's {@link MetaObject} and {@link Entity}. - * - * @property storeyId - * @type {String} - */ - this.storeyId = storeyId; +function normalizeLogLevel(logLevel) { + if (!logLevel) { + return 0; + } - /** - * ID of the model. - * - * This matches the ID of the {@link MetaModel} that contains the IfcBuildingStorey's {@link MetaObject}. - * - * @property modelId - * @type {String|Number} - */ - this.modelId = modelId; + let resolvedLevel; - /** - * Axis-aligned World-space boundary of the {@link Entity}s that represent the IfcBuildingStorey. - * - * The boundary is a six-element Float32Array containing the min/max extents of the - * axis-aligned boundary, ie. ````[xmin, ymin, zmin, xmax, ymax, zmax]```` - * - * @property aabb - * @type {Number[]} - */ - this.aabb = aabb.slice(); + switch (typeof logLevel) { + case 'number': + resolvedLevel = logLevel; + break; - /** Number of {@link Entity}s within the IfcBuildingStorey. - * - * @property numObjects - * @type {Number} - */ - this.numObjects = numObjects; - } -} + case 'object': + resolvedLevel = logLevel.logLevel || logLevel.priority || 0; + break; -/** - * @desc Property states for {@link Entity}s in {@link Storey}s capture by a {@link StoreyViewsPlugin}. - * - * @type {{String:Object}} - */ -const IFCStoreyPlanObjectStates = { - IfcSlab: { - visible: true, - edges: false, - colorize: [1.0, 1.0, 1.0, 1.0] - }, - IfcWall: { - visible: true, - edges: false, - colorize: [0.1, 0.1, 0.1, 1.0] - }, - IfcWallStandardCase: { - visible: true, - edges: false, - colorize: [0.1, 0.1, 0.1, 1.0] - }, - IfcDoor: { - visible: true, - edges: false, - colorize: [0.5, 0.5, 0.5, 1.0] - }, - IfcWindow: { - visible: true, - edges: false, - colorize: [0.5, 0.5, 0.5, 1.0] - }, - IfcColumn: { - visible: true, - edges: false, - colorize: [0.5, 0.5, 0.5, 1.0] - }, - IfcCurtainWall: { - visible: true, - edges: false, - colorize: [0.5, 0.5, 0.5, 1.0] - }, - IfcStair: { - visible: true, - edges: false, - colorize: [0.7, 0.7, 0.7, 1.0] - }, - IfcStairFlight: { - visible: true, - edges: false, - colorize: [0.7, 0.7, 0.7, 1.0] - }, - IfcRamp: { - visible: true, - edges: false, - colorize: [0.7, 0.7, 0.7, 1.0] - }, - IfcFurniture: { - visible: true, - edges: false, - colorize: [0.7, 0.7, 0.7, 1.0] - }, - IfcFooting: { - visible: true, - edges: false, - colorize: [0.7, 0.7, 0.7, 1.0] - }, - IfcFloor: { - visible: true, - edges: false, - colorize: [1.0, 1.0, 1.0, 1.0] - }, - DEFAULT: { - visible: false - } -}; + default: + return 0; + } -const color$1 = math.vec3(); + assert$2(Number.isFinite(resolvedLevel) && resolvedLevel >= 0); + return resolvedLevel; +} -/** - * @desc Saves and restores a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. - * - * * An Entity represents an object when {@link Entity#isObject} is ````true````. - * * Each object-Entity is registered by {@link Entity#id} in {@link Scene#objects}. - * - * ## See Also - * - * * {@link CameraMemento} - Saves and restores the state of a {@link Scene}'s {@link Camera}. - * * {@link ModelMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s of a model within a {@link Scene}. - * - * ## Usage - * - * In the example below, we'll create a {@link Viewer} and use an {@link XKTLoaderPlugin} to load an ````.xkt```` model. When the model has loaded, we'll hide a couple of {@link Entity}s and save a snapshot of the visual states of all the Entitys in an ObjectsMemento. Then we'll show all the Entitys - * again, and then we'll restore the visual states of all the Entitys again from the ObjectsMemento, which will hide those two Entitys again. - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, ObjectsMemento} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * // Load a model - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/schependomlaan/schependomlaan.xkt" - * }); - * - * model.on("loaded", () => { - * - * // Model has loaded - * - * // Hide a couple of objects - * viewer.scene.objects["0u4wgLe6n0ABVaiXyikbkA"].visible = false; - * viewer.scene.objects["3u4wgLe3n0AXVaiXyikbYO"].visible = false; - * - * // Save memento of all object states, which includes those two hidden objects - * const objectsMemento = new ObjectsMemento(); - * - * objectsMemento.saveObjects(viewer.scene); - * - * // Show all objects - * viewer.scene.setObjectsVisible(viewer.scene.objectIds, true); - * - * // Restore the objects states again, which involves hiding those two objects again - * objectsMemento.restoreObjects(viewer.scene); - * }); - * ````` - * - * ## Masking Saved State - * - * We can optionally supply a mask to focus what state we save and restore. - * - * For example, to save and restore only the {@link Entity#visible} and {@link Entity#clippable} states: - * - * ````javascript - * objectsMemento.saveObjects(viewer.scene, { - * visible: true, - * clippable: true - * }); - * - * //... - * - * // Restore the objects states again - * objectsMemento.restoreObjects(viewer.scene); - * ```` - */ -class ObjectsMemento { +function normalizeArguments(opts) { + const { + logLevel, + message + } = opts; + opts.logLevel = normalizeLogLevel(logLevel); + const args = opts.args ? Array.from(opts.args) : []; - /** - * Creates an ObjectsMemento. - */ - constructor() { + while (args.length && args.shift() !== message) {} - /** @private */ - this.objectsVisible = []; + switch (typeof logLevel) { + case 'string': + case 'function': + if (message !== undefined) { + args.unshift(message); + } - /** @private */ - this.objectsEdges = []; + opts.message = logLevel; + break; - /** @private */ - this.objectsXrayed = []; + case 'object': + Object.assign(opts, logLevel); + break; + } - /** @private */ - this.objectsHighlighted = []; + if (typeof opts.message === 'function') { + opts.message = opts.message(); + } - /** @private */ - this.objectsSelected = []; + const messageType = typeof opts.message; + assert$2(messageType === 'string' || messageType === 'object'); + return Object.assign(opts, { + args + }, opts.opts); +} - /** @private */ - this.objectsClippable = []; +function decorateMessage(id, message, opts) { + if (typeof message === 'string') { + const time = opts.time ? leftPad(formatTime(opts.total)) : ''; + message = opts.time ? "".concat(id, ": ").concat(time, " ").concat(message) : "".concat(id, ": ").concat(message); + message = addColor(message, opts.color, opts.background); + } - /** @private */ - this.objectsPickable = []; + return message; +} - /** @private */ - this.objectsColorize = []; +function logImageInNode(_ref2) { + let { + image, + message = '', + scale = 1 + } = _ref2; + let asciify = null; - /** @private */ - this.objectsHasColorize = []; + try { + asciify = module.require('asciify-image'); + } catch (error) {} - /** @private */ - this.objectsOpacity = []; + if (asciify) { + return () => asciify(image, { + fit: 'box', + width: "".concat(Math.round(80 * scale), "%") + }).then(data => console.log(data)); + } - /** @private */ - this.numObjects = 0; - } + return noop; +} - /** - * Saves a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. - * - * @param {Scene} scene The scene. - * @param {Object} [mask] Masks what state gets saved. Saves all state when not supplied. - * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. - * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. - * @param {boolean} [mask.edges] Saves {@link Entity#edges} values when ````true````. - * @param {boolean} [mask.xrayed] Saves {@link Entity#xrayed} values when ````true````. - * @param {boolean} [mask.highlighted] Saves {@link Entity#highlighted} values when ````true````. - * @param {boolean} [mask.selected] Saves {@link Entity#selected} values when ````true````. - * @param {boolean} [mask.clippable] Saves {@link Entity#clippable} values when ````true````. - * @param {boolean} [mask.pickable] Saves {@link Entity#pickable} values when ````true````. - * @param {boolean} [mask.colorize] Saves {@link Entity#colorize} values when ````true````. - * @param {boolean} [mask.opacity] Saves {@link Entity#opacity} values when ````true````. - */ - saveObjects(scene, mask) { +function logImageInBrowser(_ref3) { + let { + image, + message = '', + scale = 1 + } = _ref3; - this.numObjects = 0; + if (typeof image === 'string') { + const img = new Image(); - this._mask = mask ? utils.apply(mask, {}) : null; + img.onload = () => { + const args = formatImage(img, message, scale); + console.log(...args); + }; - const objects = scene.objects; - const visible = (!mask || mask.visible); - const edges = (!mask || mask.edges); - const xrayed = (!mask || mask.xrayed); - const highlighted = (!mask || mask.highlighted); - const selected = (!mask || mask.selected); - const clippable = (!mask || mask.clippable); - const pickable = (!mask || mask.pickable); - const colorize = (!mask || mask.colorize); - const opacity = (!mask || mask.opacity); + img.src = image; + return noop; + } - for (let objectId in objects) { - if (objects.hasOwnProperty(objectId)) { - const object = objects[objectId]; - const i = this.numObjects; - if (visible) { - this.objectsVisible[i] = object.visible; - } - if (edges) { - this.objectsEdges[i] = object.edges; - } - if (xrayed) { - this.objectsXrayed[i] = object.xrayed; - } - if (highlighted) { - this.objectsHighlighted[i] = object.highlighted; - } - if (selected) { - this.objectsSelected[i] = object.selected; - } - if (clippable) { - this.objectsClippable[i] = object.clippable; - } - if (pickable) { - this.objectsPickable[i] = object.pickable; - } - if (colorize) { - const objectColor = object.colorize; - if (objectColor) { - this.objectsColorize[i * 3 + 0] = objectColor[0]; - this.objectsColorize[i * 3 + 1] = objectColor[1]; - this.objectsColorize[i * 3 + 2] = objectColor[2]; - this.objectsHasColorize[i] = true; - } else { - this.objectsHasColorize[i] = false; - } - } - if (opacity) { - this.objectsOpacity[i] = object.opacity; - } - this.numObjects++; - } - } - } + const element = image.nodeName || ''; - /** - * Restores a {@link Scene}'s {@link Entity}'s to their state previously captured with {@link ObjectsMemento#saveObjects}. - * @param {Scene} scene The scene. - */ - restoreObjects(scene) { + if (element.toLowerCase() === 'img') { + console.log(...formatImage(image, message, scale)); + return noop; + } - const mask = this._mask; + if (element.toLowerCase() === 'canvas') { + const img = new Image(); - const visible = (!mask || mask.visible); - const edges = (!mask || mask.edges); - const xrayed = (!mask || mask.xrayed); - const highlighted = (!mask || mask.highlighted); - const selected = (!mask || mask.selected); - const clippable = (!mask || mask.clippable); - const pickable = (!mask || mask.pickable); - const colorize = (!mask || mask.colorize); - const opacity = (!mask || mask.opacity); + img.onload = () => console.log(...formatImage(img, message, scale)); - var i = 0; + img.src = image.toDataURL(); + return noop; + } - const objects = scene.objects; + return noop; +} - for (let objectId in objects) { - if (objects.hasOwnProperty(objectId)) { - const object = objects[objectId]; - if (visible) { - object.visible = this.objectsVisible[i]; - } - if (edges) { - object.edges = this.objectsEdges[i]; - } - if (xrayed) { - object.xrayed = this.objectsXrayed[i]; - } - if (highlighted) { - object.highlighted = this.objectsHighlighted[i]; - } - if (selected) { - object.selected = this.objectsSelected[i]; - } - if (clippable) { - object.clippable = this.objectsClippable[i]; - } - if (pickable) { - object.pickable = this.objectsPickable[i]; - } - if (colorize ) { - if (this.objectsHasColorize[i]) { - color$1[0] = this.objectsColorize[i * 3 + 0]; - color$1[1] = this.objectsColorize[i * 3 + 1]; - color$1[2] = this.objectsColorize[i * 3 + 2]; - object.colorize = color$1; - } else { - object.colorize = null; - } - } - if (opacity) { - object.opacity = this.objectsOpacity[i]; - } - i++; - } - } +function getTableHeader(table) { + for (const key in table) { + for (const title in table[key]) { + return title || 'untitled'; } -} + } -/** - * @desc Saves and restores the state of a {@link Scene}'s {@link Camera}. - * - * ## See Also - * - * * {@link ModelMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s of a model within a {@link Scene}. - * * {@link ObjectsMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. - * - * ## Usage - * - * In the example below, we'll create a {@link Viewer} and use an {@link XKTLoaderPlugin} to load an ````.xkt```` model. When the model has loaded, we'll save a snapshot of the {@link Camera} state in an CameraMemento. Then we'll move the Camera, and then we'll restore its original state again from the CameraMemento. - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, CameraMemento} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * // Load a model - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/schependomlaan/schependomlaan.xkt" - * }); - * - * // Set camera - * viewer.camera.eye = [-2.56, 8.38, 8.27]; - * viewer.camera.look = [13.44, 3.31, -14.83]; - * viewer.camera.up = [0.10, 0.98, -0.14]; - * - * model.on("loaded", () => { - * - * // Model has loaded - * - * // Save memento of camera state - * const cameraMemento = new CameraMemento(); - * - * cameraMemento.saveCamera(viewer.scene); - * - * // Move the camera - * viewer.camera.eye = [45.3, 2.00, 5.13]; - * viewer.camera.look = [0.0, 5.5, 10.0]; - * viewer.camera.up = [0.10, 0.98, -0.14]; - * - * // Restore the camera state again - * objectsMemento.restoreCamera(viewer.scene); - * }); - * ```` - */ -class CameraMemento { + return 'empty'; +} - /** - * Creates a CameraState. - * - * @param {Scene} [scene] When given, immediately saves the state of the given {@link Scene}'s {@link Camera}. - */ - constructor(scene) { +const log = new Log({ + id: 'loaders.gl' +}); - /** @private */ - this._eye = math.vec3(); +const EXT_PATTERN = /\.([^.]+)$/; +async function selectLoader(data, loaders = [], options, context) { + if (!validHTTPResponse(data)) { + return null; + } - /** @private */ - this._look = math.vec3(); + let loader = selectLoaderSync(data, loaders, { ...options, + nothrow: true + }, context); - /** @private */ - this._up = math.vec3(); + if (loader) { + return loader; + } - /** @private */ - this._projection = {}; + if (isBlob(data)) { + data = await data.slice(0, 10).arrayBuffer(); + loader = selectLoaderSync(data, loaders, options, context); + } - if (scene) { - this.saveCamera(scene); - } - } + if (!loader && !(options !== null && options !== void 0 && options.nothrow)) { + throw new Error(getNoValidLoaderMessage(data)); + } - /** - * Saves the state of the given {@link Scene}'s {@link Camera}. - * - * @param {Scene} scene The scene that contains the {@link Camera}. - */ - saveCamera(scene) { + return loader; +} +function selectLoaderSync(data, loaders = [], options, context) { + if (!validHTTPResponse(data)) { + return null; + } - const camera = scene.camera; - const project = camera.project; + if (loaders && !Array.isArray(loaders)) { + return normalizeLoader(loaders); + } - this._eye.set(camera.eye); - this._look.set(camera.look); - this._up.set(camera.up); + let candidateLoaders = []; - switch (camera.projection) { + if (loaders) { + candidateLoaders = candidateLoaders.concat(loaders); + } - case "perspective": - this._projection = { - projection: "perspective", - fov: project.fov, - fovAxis: project.fovAxis, - near: project.near, - far: project.far - }; - break; + if (!(options !== null && options !== void 0 && options.ignoreRegisteredLoaders)) { + candidateLoaders.push(...getRegisteredLoaders()); + } - case "ortho": - this._projection = { - projection: "ortho", - scale: project.scale, - near: project.near, - far: project.far - }; - break; + normalizeLoaders(candidateLoaders); + const loader = selectLoaderInternal(data, candidateLoaders, options, context); - case "frustum": - this._projection = { - projection: "frustum", - left: project.left, - right: project.right, - top: project.top, - bottom: project.bottom, - near: project.near, - far: project.far - }; - break; + if (!loader && !(options !== null && options !== void 0 && options.nothrow)) { + throw new Error(getNoValidLoaderMessage(data)); + } - case "custom": - this._projection = { - projection: "custom", - matrix: project.matrix.slice() - }; - break; - } - } + return loader; +} - /** - * Restores a {@link Scene}'s {@link Camera} to the state previously captured with {@link CameraMemento#saveCamera}. - * - * @param {Scene} scene The scene. - * @param {Function} [done] When this callback is given, will fly the {@link Camera} to the saved state then fire the callback. Otherwise will just jump the Camera to the saved state. - */ - restoreCamera(scene, done) { +function selectLoaderInternal(data, loaders, options, context) { + const { + url, + type + } = getResourceUrlAndType(data); + const testUrl = url || (context === null || context === void 0 ? void 0 : context.url); + let loader = null; + let reason = ''; - const camera = scene.camera; - const savedProjection = this._projection; + if (options !== null && options !== void 0 && options.mimeType) { + loader = findLoaderByMIMEType(loaders, options === null || options === void 0 ? void 0 : options.mimeType); + reason = "match forced by supplied MIME type ".concat(options === null || options === void 0 ? void 0 : options.mimeType); + } - function restoreProjection() { + loader = loader || findLoaderByUrl(loaders, testUrl); + reason = reason || (loader ? "matched url ".concat(testUrl) : ''); + loader = loader || findLoaderByMIMEType(loaders, type); + reason = reason || (loader ? "matched MIME type ".concat(type) : ''); + loader = loader || findLoaderByInitialBytes(loaders, data); + reason = reason || (loader ? "matched initial data ".concat(getFirstCharacters(data)) : ''); + loader = loader || findLoaderByMIMEType(loaders, options === null || options === void 0 ? void 0 : options.fallbackMimeType); + reason = reason || (loader ? "matched fallback MIME type ".concat(type) : ''); - switch (savedProjection.type) { + if (reason) { + var _loader; - case "perspective": - camera.perspective.fov = savedProjection.fov; - camera.perspective.fovAxis = savedProjection.fovAxis; - camera.perspective.near = savedProjection.near; - camera.perspective.far = savedProjection.far; - break; + log.log(1, "selectLoader selected ".concat((_loader = loader) === null || _loader === void 0 ? void 0 : _loader.name, ": ").concat(reason, ".")); + } - case "ortho": - camera.ortho.scale = savedProjection.scale; - camera.ortho.near = savedProjection.near; - camera.ortho.far = savedProjection.far; - break; + return loader; +} - case "frustum": - camera.frustum.left = savedProjection.left; - camera.frustum.right = savedProjection.right; - camera.frustum.top = savedProjection.top; - camera.frustum.bottom = savedProjection.bottom; - camera.frustum.near = savedProjection.near; - camera.frustum.far = savedProjection.far; - break; +function validHTTPResponse(data) { + if (data instanceof Response) { + if (data.status === 204) { + return false; + } + } - case "custom": - camera.customProjection.matrix = savedProjection.matrix; - break; - } - } + return true; +} - if (done) { - scene.viewer.cameraFlight.flyTo({ - eye: this._eye, - look: this._look, - up: this._up, - orthoScale: savedProjection.scale, - projection: savedProjection.projection - }, () => { - restoreProjection(); - done(); - }); - } else { - camera.eye = this._eye; - camera.look = this._look; - camera.up = this._up; - restoreProjection(); - camera.projection = savedProjection.projection; - } - } +function getNoValidLoaderMessage(data) { + const { + url, + type + } = getResourceUrlAndType(data); + let message = 'No valid loader found ('; + message += url ? "".concat(filename(url), ", ") : 'no url provided, '; + message += "MIME type: ".concat(type ? "\"".concat(type, "\"") : 'not provided', ", "); + const firstCharacters = data ? getFirstCharacters(data) : ''; + message += firstCharacters ? " first bytes: \"".concat(firstCharacters, "\"") : 'first bytes: not available'; + message += ')'; + return message; } -/** - * @desc A 2D plan view image of an ````IfcBuildingStorey````. - * - * These are created by a {@link StoreyViewsPlugin}. - */ -class StoreyMap { +function normalizeLoaders(loaders) { + for (const loader of loaders) { + normalizeLoader(loader); + } +} - /** - * @private - */ - constructor(storeyId, imageData, format, width, height, padding) { +function findLoaderByUrl(loaders, url) { + const match = url && EXT_PATTERN.exec(url); + const extension = match && match[1]; + return extension ? findLoaderByExtension(loaders, extension) : null; +} - /** - * ID of the IfcBuildingStorey. - * - * This matches IDs of the IfcBuildingStorey's {@link MetaObject} and {@link Entity}. - * - * @property storeyId - * @type {String} - */ - this.storeyId = storeyId; +function findLoaderByExtension(loaders, extension) { + extension = extension.toLowerCase(); - /** - * Base64-encoded plan view image. - * - * @property imageData - * @type {String} - */ - this.imageData = imageData; + for (const loader of loaders) { + for (const loaderExtension of loader.extensions) { + if (loaderExtension.toLowerCase() === extension) { + return loader; + } + } + } - /** - * The image format - "png" or "jpeg". - * - * @property format - * @type {String} - */ - this.format = format; + return null; +} - /** - * Width of the image, in pixels. - * - * @property width - * @type {Number} - */ - this.width = width; +function findLoaderByMIMEType(loaders, mimeType) { + for (const loader of loaders) { + if (loader.mimeTypes && loader.mimeTypes.includes(mimeType)) { + return loader; + } - /** - * Height of the image, in pixels. - * - * @property height - * @type {Number} - */ - this.height = height; + if (mimeType === "application/x.".concat(loader.id)) { + return loader; } + } + + return null; } -const tempVec3a$6 = math.vec3(); -const tempMat4 = math.mat4(); +function findLoaderByInitialBytes(loaders, data) { + if (!data) { + return null; + } -const EMPTY_IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="; + for (const loader of loaders) { + if (typeof data === 'string') { + if (testDataAgainstText(data, loader)) { + return loader; + } + } else if (ArrayBuffer.isView(data)) { + if (testDataAgainstBinary(data.buffer, data.byteOffset, loader)) { + return loader; + } + } else if (data instanceof ArrayBuffer) { + const byteOffset = 0; + if (testDataAgainstBinary(data, byteOffset, loader)) { + return loader; + } + } + } -/** - * @desc A {@link Viewer} plugin that provides methods for visualizing IfcBuildingStoreys. - * - * - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_recipe2)] - * - * ## Overview - * - * StoreyViewsPlugin provides a flexible set of methods for visualizing building storeys in 3D and 2D. - * - * Use the first two methods to set up 3D views of storeys: - * - * * [showStoreyObjects](#instance-method-showStoreyObjects) - shows the {@link Entity}s within a storey, and - * * [gotoStoreyCamera](#instance-method-gotoStoreyCamera) - positions the {@link Camera} for a plan view of the Entitys within a storey. - *

- * - * Use the second two methods to create 2D plan view mini-map images: - * - * * [createStoreyMap](#instance-method-createStoreyMap) - creates a 2D plan view image of a storey, and - * * [pickStoreyMap](#instance-method-pickStoreyMap) - picks the {@link Entity} at the given 2D pixel coordinates within a plan view image. - * - * ## Usage - * - * Let's start by creating a {@link Viewer} with a StoreyViewsPlugin and an {@link XKTLoaderPlugin}. - * - * Then we'll load a BIM building model from an ```.xkt``` file. - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, StoreyViewsPlugin} from "xeokit-sdk.es.js"; - * - * // Create a Viewer, arrange the camera - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [-2.56, 8.38, 8.27]; - * viewer.camera.look = [13.44, 3.31, -14.83]; - * viewer.camera.up = [0.10, 0.98, -0.14]; - * - * // Add an XKTLoaderPlugin - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * // Add a StoreyViewsPlugin - * - * const storeyViewsPlugin = new StoreyViewsPlugin(viewer); - * - * // Load a BIM model from .xkt format - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/Schependomlaan.xkt", - * edges: true - * }); - * ```` - * - * ## Finding Storeys - * - * Getting information on a storey in our model: - * - * ````javascript - * const storey = storeyViewsPlugin.storeys["2SWZMQPyD9pfT9q87pgXa1"]; // ID of the IfcBuildingStorey - * - * const modelId = storey.modelId; // "myModel" - * const storeyId = storey.storeyId; // "2SWZMQPyD9pfT9q87pgXa1" - * const aabb = storey.aabb; // Axis-aligned 3D World-space boundary of the IfcBuildingStorey - * ```` - * - * We can also get a "storeys" event every time the set of storeys changes, ie. every time a storey is created or destroyed: - * - * ````javascript - * storeyViewsPlugin.on("storeys", ()=> { - * const storey = storeyViewsPlugin.storeys["2SWZMQPyD9pfT9q87pgXa1"]; - * //... - * }); - * ```` - * - * ## Showing Entitys within Storeys - * - * Showing the {@link Entity}s within a storey: - * - * ````javascript - * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1"); - * ```` - * - * Showing **only** the Entitys in a storey, hiding all others: - * - * ````javascript - * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { - * hideOthers: true - * }); - * ```` - * Showing only the storey Entitys, applying custom appearances configured on {@link StoreyViewsPlugin#objectStates}: - * - * ````javascript - * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { - * hideOthers: true, - * useObjectStates: true - * }); - * ```` - * - * - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_showStoreyObjects)] - * - * When using this option, at some point later you'll probably want to restore all Entitys to their original visibilities and - * appearances. - * - * To do that, save their visibility and appearance states in an {@link ObjectsMemento} beforehand, from - * which you can restore them later: - * - * ````javascript - * const objectsMemento = new ObjectsMemento(); - * - * // Save all Entity visibility and appearance states - * - * objectsMemento.saveObjects(viewer.scene); - * - * // Show storey view Entitys, with custom appearances as configured for IFC types - * - * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { - * useObjectStates: true // <<--------- Apply custom appearances - * }); - * - * //... - * - * // Later, restore all Entitys to their saved visibility and appearance states - * objectsMemento.restoreObjects(viewer.scene); - * ```` - * - * ## Arranging the Camera for Storey Plan Views - * - * The {@link StoreyViewsPlugin#gotoStoreyCamera} method positions the {@link Camera} for a plan view of - * the {@link Entity}s within the given storey. - * - * - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_gotoStoreyCamera)] - * - * Let's fly the {@link Camera} to a downward-looking orthographic view of the Entitys within our storey. - * - * ````javascript - * storeyViewsPlugin.gotoStoreyCamera("2SWZMQPyD9pfT9q87pgXa1", { - * projection: "ortho", // Orthographic projection - * duration: 2.5, // 2.5 second transition - * done: () => { - * viewer.cameraControl.planView = true; // Disable rotation - * } - * }); - * ```` - * - * Note that we also set {@link CameraControl#planView} ````true````, which prevents the CameraControl from rotating - * or orbiting. In orthographic mode, this effectively makes the {@link Viewer} behave as if it were a 2D viewer, with - * picking, panning and zooming still enabled. - * - * If you need to be able to restore the Camera to its previous state, you can save it to a {@link CameraMemento} - * beforehand, from which you can restore it later: - * - * ````javascript - * const cameraMemento = new CameraMemento(); - * - * // Save camera state - * - * cameraMemento.saveCamera(viewer.scene); - * - * // Position camera for a downward-looking orthographic view of our storey - * - * storeyViewsPlugin.gotoStoreyCamera("2SWZMQPyD9pfT9q87pgXa1", { - * projection: "ortho", - * duration: 2.5, - * done: () => { - * viewer.cameraControl.planView = true; // Disable rotation - * } - * }); - * - * //... - * - * // Later, restore the Camera to its saved state - * cameraMemento.restoreCamera(viewer.scene); - * ```` - * - * ## Creating StoreyMaps - * - * The {@link StoreyViewsPlugin#createStoreyMap} method creates a 2D orthographic plan image of the given storey. - * - * - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_createStoreyMap)] - * - * This method creates a {@link StoreyMap}, which provides the plan image as a Base64-encoded string. - * - * Let's create a 2D plan image of our building storey: - * - * ````javascript - * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { - * width: 300, - * format: "png" - * }); - * - * const imageData = storeyMap.imageData; // Base64-encoded image data string - * const width = storeyMap.width; // 300 - * const height = storeyMap.height; // Automatically derived from width - * const format = storeyMap.format; // "png" - * ```` - * - * As with ````showStoreyEntitys````, We also have the option to customize the appearance of the Entitys in our plan - * images according to their IFC types, using the lookup table configured on {@link StoreyViewsPlugin#objectStates}. - * - * For example, we usually want to show only element types like ````IfcWall````, ````IfcDoor```` and - * ````IfcFloor```` in our plan images. - * - * Let's create another StoreyMap, this time applying the custom appearances: - * - * ````javascript - * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { - * width: 300, - * format: "png", - * useObjectStates: true // <<--------- Apply custom appearances - * }); - *```` - * - * We can also specify a ````height```` for the plan image, as an alternative to ````width````: - * - * ````javascript - * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { - * height: 200, - * format: "png", - * useObjectStates: true - * }); - * ```` - * - * ## Picking Entities in StoreyMaps - * - * We can use {@link StoreyViewsPlugin#pickStoreyMap} to pick Entities in our building storey, using 2D coordinates from mouse or touch events on our {@link StoreyMap}'s 2D plan image. - * - * - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_recipe2)] - * - * Let's programmatically pick the Entity at the given 2D pixel coordinates within our image: - * - * ````javascript - * const mouseCoords = [65, 120]; // Mouse coords within the image extents - * - * const pickResult = storeyViewsPlugin.pickStoreyMap(storeyMap, mouseCoords); - * - * if (pickResult && pickResult.entity) { - * pickResult.entity.highlighted = true; - * } - * ```` - */ -class StoreyViewsPlugin extends Plugin { + return null; +} - /** - * @constructor - * - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="StoreyViews"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Object} [cfg.objectStates] Map of visual states for the {@link Entity}s as rendered within each {@link Storey}. Default value is {@link IFCStoreyPlanObjectStates}. - */ - constructor(viewer, cfg = {}) { +function testDataAgainstText(data, loader) { + if (loader.testText) { + return loader.testText(data); + } - super("StoreyViews", viewer); + const tests = Array.isArray(loader.tests) ? loader.tests : [loader.tests]; + return tests.some(test => data.startsWith(test)); +} - this._objectsMemento = new ObjectsMemento(); - this._cameraMemento = new CameraMemento(); +function testDataAgainstBinary(data, byteOffset, loader) { + const tests = Array.isArray(loader.tests) ? loader.tests : [loader.tests]; + return tests.some(test => testBinary(data, byteOffset, loader, test)); +} - /** - * A {@link Storey} for each ````IfcBuildingStorey```. - * - * There will be a {@link Storey} for every existing {@link MetaObject} whose {@link MetaObject#type} equals "IfcBuildingStorey". - * - * These are created and destroyed automatically as models are loaded and destroyed. - * - * @type {{String:Storey}} - */ - this.storeys = {}; +function testBinary(data, byteOffset, loader, test) { + if (test instanceof ArrayBuffer) { + return compareArrayBuffers(test, data, test.byteLength); + } - /** - * A set of {@link Storey}s for each {@link MetaModel}. - * - * These are created and destroyed automatically as models are loaded and destroyed. - * - * @type {{String: {String:Storey}}} - */ - this.modelStoreys = {}; + switch (typeof test) { + case 'function': + return test(data, loader); - this.objectStates = cfg.objectStates; + case 'string': + const magic = getMagicString$1(data, byteOffset, test.length); + return test === magic; - this._onModelLoaded = this.viewer.scene.on("modelLoaded", (modelId) => { - this._registerModelStoreys(modelId); - this.fire("storeys", this.storeys); - }); - } + default: + return false; + } +} - _registerModelStoreys(modelId) { - const viewer = this.viewer; - const scene = viewer.scene; - const metaScene = viewer.metaScene; - const metaModel = metaScene.metaModels[modelId]; - const model = scene.models[modelId]; - if (!metaModel || !metaModel.rootMetaObject) { - return; - } - const storeyIds = metaModel.rootMetaObject.getObjectIDsInSubtreeByType(["IfcBuildingStorey"]); - for (let i = 0, len = storeyIds.length; i < len; i++) { - const storeyId = storeyIds[i]; - const metaObject = metaScene.metaObjects[storeyId]; - const childObjectIds = metaObject.getObjectIDsInSubtree(); - const aabb = scene.getAABB(childObjectIds); - const numObjects = (Math.random() > 0.5) ? childObjectIds.length : 0; - const storey = new Storey(this, aabb, modelId, storeyId, numObjects); - storey._onModelDestroyed = model.once("destroyed", () => { - this._deregisterModelStoreys(modelId); - this.fire("storeys", this.storeys); - }); - this.storeys[storeyId] = storey; - if (!this.modelStoreys[modelId]) { - this.modelStoreys[modelId] = {}; - } - this.modelStoreys[modelId][storeyId] = storey; - } - } +function getFirstCharacters(data, length = 5) { + if (typeof data === 'string') { + return data.slice(0, length); + } else if (ArrayBuffer.isView(data)) { + return getMagicString$1(data.buffer, data.byteOffset, length); + } else if (data instanceof ArrayBuffer) { + const byteOffset = 0; + return getMagicString$1(data, byteOffset, length); + } - _deregisterModelStoreys(modelId) { - const storeys = this.modelStoreys[modelId]; - if (storeys) { - const scene = this.viewer.scene; - for (let storyObjectId in storeys) { - if (storeys.hasOwnProperty(storyObjectId)) { - const storey = storeys[storyObjectId]; - const model = scene.models[storey.modelId]; - if (model) { - model.off(storey._onModelDestroyed); - } - delete this.storeys[storyObjectId]; - } - } - delete this.modelStoreys[modelId]; - } - } + return ''; +} - /** - * Sets map of visual states for the {@link Entity}s as rendered within each {@link Storey}. - * - * Default value is {@link IFCStoreyPlanObjectStates}. - * - * @type {{String: Object}} - */ - set objectStates(value) { - this._objectStates = value || IFCStoreyPlanObjectStates; - } +function getMagicString$1(arrayBuffer, byteOffset, length) { + if (arrayBuffer.byteLength < byteOffset + length) { + return ''; + } - /** - * Gets map of visual states for the {@link Entity}s as rendered within each {@link Storey}. - * - * Default value is {@link IFCStoreyPlanObjectStates}. - * - * @type {{String: Object}} - */ - get objectStates() { - return this._objectStates; - } + const dataView = new DataView(arrayBuffer); + let magic = ''; - /** - * Arranges the {@link Camera} for a 3D orthographic view of the {@link Entity}s within the given storey. - * - * See also: {@link CameraMemento}, which saves and restores the state of the {@link Scene}'s {@link Camera} - * - * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. - * @param {*} [options] Options for arranging the Camera. - * @param {String} [options.projection] Projection type to transition the Camera to. Accepted values are "perspective" and "ortho". - * @param {Function} [options.done] Callback to fire when the Camera has arrived. When provided, causes an animated flight to the saved state. Otherwise jumps to the saved state. - */ - gotoStoreyCamera(storeyId, options = {}) { + for (let i = 0; i < length; i++) { + magic += String.fromCharCode(dataView.getUint8(byteOffset + i)); + } - const storey = this.storeys[storeyId]; + return magic; +} - if (!storey) { - this.error("IfcBuildingStorey not found with this ID: " + storeyId); - if (options.done) { - options.done(); - } - return; - } +const DEFAULT_CHUNK_SIZE$2 = 256 * 1024; +function* makeStringIterator(string, options) { + const chunkSize = (options === null || options === void 0 ? void 0 : options.chunkSize) || DEFAULT_CHUNK_SIZE$2; + let offset = 0; + const textEncoder = new TextEncoder(); - const viewer = this.viewer; - const scene = viewer.scene; - const camera = scene.camera; - const aabb = storey.aabb; + while (offset < string.length) { + const chunkLength = Math.min(string.length - offset, chunkSize); + const chunk = string.slice(offset, offset + chunkLength); + offset += chunkLength; + yield textEncoder.encode(chunk); + } +} - if (aabb[3] < aabb[0] || aabb[4] < aabb[1] || aabb[5] < aabb[2]) { // Don't fly to an inverted boundary - if (options.done) { - options.done(); - } - return; - } - if (aabb[3] === aabb[0] && aabb[4] === aabb[1] && aabb[5] === aabb[2]) { // Don't fly to an empty boundary - if (options.done) { - options.done(); - } - return; - } - const look2 = math.getAABB3Center(aabb); - const diag = math.getAABB3Diag(aabb); - const fitFOV = 45; // fitFOV; - const sca = Math.abs(diag / Math.tan(fitFOV * math.DEGTORAD)); +const DEFAULT_CHUNK_SIZE$1 = 256 * 1024; +function* makeArrayBufferIterator(arrayBuffer, options = {}) { + const { + chunkSize = DEFAULT_CHUNK_SIZE$1 + } = options; + let byteOffset = 0; - const orthoScale2 = diag * 1.3; + while (byteOffset < arrayBuffer.byteLength) { + const chunkByteLength = Math.min(arrayBuffer.byteLength - byteOffset, chunkSize); + const chunk = new ArrayBuffer(chunkByteLength); + const sourceArray = new Uint8Array(arrayBuffer, byteOffset, chunkByteLength); + const chunkArray = new Uint8Array(chunk); + chunkArray.set(sourceArray); + byteOffset += chunkByteLength; + yield chunk; + } +} - const eye2 = tempVec3a$6; +const DEFAULT_CHUNK_SIZE = 1024 * 1024; +async function* makeBlobIterator(blob, options) { + const chunkSize = (options === null || options === void 0 ? void 0 : options.chunkSize) || DEFAULT_CHUNK_SIZE; + let offset = 0; - eye2[0] = look2[0] + (camera.worldUp[0] * sca); - eye2[1] = look2[1] + (camera.worldUp[1] * sca); - eye2[2] = look2[2] + (camera.worldUp[2] * sca); + while (offset < blob.size) { + const end = offset + chunkSize; + const chunk = await blob.slice(offset, end).arrayBuffer(); + offset = end; + yield chunk; + } +} - const up2 = camera.worldForward; +function makeStreamIterator(stream, options) { + return isBrowser$4 ? makeBrowserStreamIterator(stream, options) : makeNodeStreamIterator(stream); +} - if (options.done) { +async function* makeBrowserStreamIterator(stream, options) { + const reader = stream.getReader(); + let nextBatchPromise; - viewer.cameraFlight.flyTo(utils.apply(options, { - eye: eye2, - look: look2, - up: up2, - orthoScale: orthoScale2 - }), () => { - options.done(); - }); + try { + while (true) { + const currentBatchPromise = nextBatchPromise || reader.read(); - } else { + if (options !== null && options !== void 0 && options._streamReadAhead) { + nextBatchPromise = reader.read(); + } - viewer.cameraFlight.jumpTo(utils.apply(options, { - eye: eye2, - look: look2, - up: up2, - orthoScale: orthoScale2 - })); + const { + done, + value + } = await currentBatchPromise; - viewer.camera.ortho.scale = orthoScale2; - } + if (done) { + return; + } + + yield toArrayBuffer(value); } + } catch (error) { + reader.releaseLock(); + } +} - /** - * Shows the {@link Entity}s within the given storey. - * - * Optionally hides all other Entitys. - * - * Optionally sets the visual appearance of each of the Entitys according to its IFC type. The appearance of - * IFC types in plan views is configured by {@link StoreyViewsPlugin#objectStates}. - * - * See also: {@link ObjectsMemento}, which saves and restores a memento of the visual state - * of the {@link Entity}'s that represent objects within a {@link Scene}. - * - * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. - * @param {*} [options] Options for showing the Entitys within the storey. - * @param {Boolean} [options.hideOthers=false] When ````true````, hide all other {@link Entity}s. - * @param {Boolean} [options.useObjectStates=false] When ````true````, apply the custom visibilities and appearances configured for IFC types in {@link StoreyViewsPlugin#objectStates}. - */ - showStoreyObjects(storeyId, options = {}) { +async function* makeNodeStreamIterator(stream, options) { + for await (const chunk of stream) { + yield toArrayBuffer(chunk); + } +} - const storey = this.storeys[storeyId]; +function makeIterator(data, options) { + if (typeof data === 'string') { + return makeStringIterator(data, options); + } - if (!storey) { - this.error("IfcBuildingStorey not found with this ID: " + storeyId); - return; - } + if (data instanceof ArrayBuffer) { + return makeArrayBufferIterator(data, options); + } - const viewer = this.viewer; - const scene = viewer.scene; - const metaScene = viewer.metaScene; - const storeyMetaObject = metaScene.metaObjects[storeyId]; + if (isBlob(data)) { + return makeBlobIterator(data, options); + } - if (!storeyMetaObject) { - return; - } + if (isReadableStream(data)) { + return makeStreamIterator(data, options); + } - if (options.hideOthers) { - scene.setObjectsVisible(viewer.scene.visibleObjectIds, false); - } + if (isResponse(data)) { + const response = data; + return makeStreamIterator(response.body, options); + } - this.withStoreyObjects(storeyId, (entity, metaObject) => { - if (entity) { - if (options.useObjectStates) { - const props = this._objectStates[metaObject.type] || this._objectStates["DEFAULT"]; - if (props) { - entity.visible = props.visible; - entity.edges = props.edges; - // entity.xrayed = props.xrayed; // FIXME: Buggy - // entity.highlighted = props.highlighted; - // entity.selected = props.selected; - if (props.colorize) { - entity.colorize = props.colorize; - } - if (props.opacity !== null && props.opacity !== undefined) { - entity.opacity = props.opacity; - } - } - } else { - entity.visible = true; - } - } - }); + throw new Error('makeIterator'); +} + +const ERR_DATA = 'Cannot convert supplied data type'; +function getArrayBufferOrStringFromDataSync(data, loader, options) { + if (loader.text && typeof data === 'string') { + return data; + } + + if (isBuffer(data)) { + data = data.buffer; + } + + if (data instanceof ArrayBuffer) { + const arrayBuffer = data; + + if (loader.text && !loader.binary) { + const textDecoder = new TextDecoder('utf8'); + return textDecoder.decode(arrayBuffer); } - /** - * Executes a callback on each of the objects within the given storey. - * - * ## Usage - * - * In the example below, we'll show all the {@link Entity}s, within the given ````IfcBuildingStorey````, - * that have {@link MetaObject}s with type ````IfcSpace````. Note that the callback will only be given - * an {@link Entity} when one exists for the given {@link MetaObject}. - * - * ````JavaScript - * myStoreyViewsPlugin.withStoreyObjects(storeyId, (entity, metaObject) => { - * if (entity && metaObject && metaObject.type === "IfcSpace") { - * entity.visible = true; - * } - * }); - * ```` - * - * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. - * @param {Function} callback The callback. - */ - withStoreyObjects(storeyId, callback) { - const viewer = this.viewer; - const scene = viewer.scene; - const metaScene = viewer.metaScene; - const rootMetaObject = metaScene.metaObjects[storeyId]; - if (!rootMetaObject) { - return; - } - const storeySubObjects = rootMetaObject.getObjectIDsInSubtree(); - for (var i = 0, len = storeySubObjects.length; i < len; i++) { - const objectId = storeySubObjects[i]; - const metaObject = metaScene.metaObjects[objectId]; - const entity = scene.objects[objectId]; - if (entity) { - callback(entity, metaObject); - } - } + return arrayBuffer; + } + + if (ArrayBuffer.isView(data)) { + if (loader.text && !loader.binary) { + const textDecoder = new TextDecoder('utf8'); + return textDecoder.decode(data); } - /** - * Creates a 2D map of the given storey. - * - * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. - * @param {*} [options] Options for creating the image. - * @param {Number} [options.width=300] Image width in pixels. Height will be automatically determined from this, if not given. - * @param {Number} [options.height=300] Image height in pixels, as an alternative to width. Width will be automatically determined from this, if not given. - * @param {String} [options.format="png"] Image format. Accepted values are "png" and "jpeg". - * @returns {StoreyMap} The StoreyMap. - */ - createStoreyMap(storeyId, options = {}) { + let arrayBuffer = data.buffer; + const byteLength = data.byteLength || data.length; - const storey = this.storeys[storeyId]; - if (!storey) { - this.error("IfcBuildingStorey not found with this ID: " + storeyId); - return EMPTY_IMAGE; - } + if (data.byteOffset !== 0 || byteLength !== arrayBuffer.byteLength) { + arrayBuffer = arrayBuffer.slice(data.byteOffset, data.byteOffset + byteLength); + } - const viewer = this.viewer; - const scene = viewer.scene; - const format = options.format || "png"; - const aabb = storey.aabb; - const aspect = (aabb[5] - aabb[2]) / (aabb[3] - aabb[0]); - const padding = options.padding || 0; + return arrayBuffer; + } - let width; - let height; + throw new Error(ERR_DATA); +} +async function getArrayBufferOrStringFromData(data, loader, options) { + const isArrayBuffer = data instanceof ArrayBuffer || ArrayBuffer.isView(data); - if (options.width && options.height) { - width = options.width; - height = options.height; + if (typeof data === 'string' || isArrayBuffer) { + return getArrayBufferOrStringFromDataSync(data, loader); + } - } else if (options.height) { - height = options.height; - width = height / aspect; + if (isBlob(data)) { + data = await makeResponse(data); + } - } else if (options.width) { - width = options.width; - height = width * aspect; + if (isResponse(data)) { + const response = data; + await checkResponse(response); + return loader.binary ? await response.arrayBuffer() : await response.text(); + } - } else { - width = 300; - height = width * aspect; - } + if (isReadableStream(data)) { + data = makeIterator(data, options); + } - this._objectsMemento.saveObjects(scene); - this._cameraMemento.saveCamera(scene); + if (isIterable(data) || isAsyncIterable(data)) { + return concatenateArrayBuffersAsync(data); + } - viewer.beginSnapshot(); + throw new Error(ERR_DATA); +} - this.showStoreyObjects(storeyId, utils.apply(options, { - useObjectStates: true, - hideOthers: true - })); +function getLoaderContext(context, options, previousContext = null) { + if (previousContext) { + return previousContext; + } - this._arrangeStoreyMapCamera(storey); + const resolvedContext = { + fetch: getFetchFunction(options, context), + ...context + }; - const src = viewer.getSnapshot({ - width: width, - height: height, - format: format, - }); + if (!Array.isArray(resolvedContext.loaders)) { + resolvedContext.loaders = null; + } - this._objectsMemento.restoreObjects(scene); - this._cameraMemento.restoreCamera(scene); + return resolvedContext; +} +function getLoadersFromContext(loaders, context) { + if (!context && loaders && !Array.isArray(loaders)) { + return loaders; + } - viewer.endSnapshot(); + let candidateLoaders; - return new StoreyMap(storeyId, src, format, width, height, padding); - } + if (loaders) { + candidateLoaders = Array.isArray(loaders) ? loaders : [loaders]; + } - _arrangeStoreyMapCamera(storey) { - const viewer = this.viewer; - const scene = viewer.scene; - const camera = scene.camera; - const aabb = storey.aabb; - const look = math.getAABB3Center(aabb); - const sca = 0.5; - const eye = tempVec3a$6; - eye[0] = look[0] + (camera.worldUp[0] * sca); - eye[1] = look[1] + (camera.worldUp[1] * sca); - eye[2] = look[2] + (camera.worldUp[2] * sca); - const up = camera.worldForward; - viewer.cameraFlight.jumpTo({eye: eye, look: look, up: up}); - const xHalfSize = (aabb[3] - aabb[0]) / 2; - const yHalfSize = (aabb[4] - aabb[1]) / 2; - const zHalfSize = (aabb[5] - aabb[2]) / 2; - const xmin = -xHalfSize; - const xmax = +xHalfSize; - const ymin = -yHalfSize; - const ymax = +yHalfSize; - const zmin = -zHalfSize; - const zmax = +zHalfSize; - viewer.camera.customProjection.matrix = math.orthoMat4c(xmin, xmax, zmin, zmax, ymin, ymax, tempMat4); - viewer.camera.projection = "customProjection"; - } + if (context && context.loaders) { + const contextLoaders = Array.isArray(context.loaders) ? context.loaders : [context.loaders]; + candidateLoaders = candidateLoaders ? [...candidateLoaders, ...contextLoaders] : contextLoaders; + } - /** - * Attempts to pick an {@link Entity} at the given pixel coordinates within a StoreyMap image. - * - * @param {StoreyMap} storeyMap The StoreyMap. - * @param {Number[]} imagePos 2D pixel coordinates within the bounds of {@link StoreyMap#imageData}. - * @param {*} [options] Picking options. - * @param {Boolean} [options.pickSurface=false] Whether to return the picked position on the surface of the Entity. - * @returns {PickResult} The pick result, if an Entity was successfully picked, else null. - */ - pickStoreyMap(storeyMap, imagePos, options = {}) { + return candidateLoaders && candidateLoaders.length ? candidateLoaders : null; +} - const storeyId = storeyMap.storeyId; - const storey = this.storeys[storeyId]; +async function parse$3(data, loaders, options, context) { + assert$4(!context || typeof context === 'object'); - if (!storey) { - this.error("IfcBuildingStorey not found with this ID: " + storeyId); - return null - } + if (loaders && !Array.isArray(loaders) && !isLoaderObject(loaders)) { + context = undefined; + options = loaders; + loaders = undefined; + } - const normX = 1.0 - (imagePos[0] / storeyMap.width); - const normZ = 1.0 - (imagePos[1] / storeyMap.height); + data = await data; + options = options || {}; + const { + url + } = getResourceUrlAndType(data); + const typedLoaders = loaders; + const candidateLoaders = getLoadersFromContext(typedLoaders, context); + const loader = await selectLoader(data, candidateLoaders, options); - const aabb = storey.aabb; + if (!loader) { + return null; + } - const xmin = aabb[0]; - const ymin = aabb[1]; - const zmin = aabb[2]; - const xmax = aabb[3]; - const ymax = aabb[4]; - const zmax = aabb[5]; + options = normalizeOptions(options, loader, candidateLoaders, url); + context = getLoaderContext({ + url, + parse: parse$3, + loaders: candidateLoaders + }, options, context); + return await parseWithLoader(loader, data, options, context); +} - const xWorldSize = xmax - xmin; - const yWorldSize = ymax - ymin; - const zWorldSize = zmax - zmin; +async function parseWithLoader(loader, data, options, context) { + validateWorkerVersion(loader); - const origin = math.vec3([xmin + (xWorldSize * normX), ymin + (yWorldSize * 0.5), zmin + (zWorldSize * normZ)]); - const direction = math.vec3([0, -1, 0]); - const look = math.addVec3(origin, direction, tempVec3a$6); - const worldForward = this.viewer.camera.worldForward; - const matrix = math.lookAtMat4v(origin, look, worldForward, tempMat4); + if (isResponse(data)) { + const response = data; + const { + ok, + redirected, + status, + statusText, + type, + url + } = response; + const headers = Object.fromEntries(response.headers.entries()); + context.response = { + headers, + ok, + redirected, + status, + statusText, + type, + url + }; + } - const pickResult = this.viewer.scene.pick({ // Picking with arbitrarily-positioned ray - pickSurface: options.pickSurface, - pickInvisible: true, - matrix: matrix - }); + data = await getArrayBufferOrStringFromData(data, loader, options); - if (pickResult) { - const metaObject = this.viewer.metaScene.metaObjects[pickResult.entity.id]; - const objectState = this.objectStates[metaObject.type]; - if (!objectState || !objectState.visible) { - return null; - } - } + if (loader.parseTextSync && typeof data === 'string') { + options.dataType = 'text'; + return loader.parseTextSync(data, options, context, loader); + } - return pickResult; - } + if (canParseWithWorker(loader, options)) { + return await parseWithWorker(loader, data, options, context, parse$3); + } - /** - * Gets the ID of the storey that contains the given 3D World-space position. - *. - * @param {Number[]} worldPos 3D World-space position. - * @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys. - */ - getStoreyContainingWorldPos(worldPos) { - for (var storeyId in this.storeys) { - const storey = this.storeys[storeyId]; - if (math.point3AABB3Intersect(storey.aabb, worldPos)) { - return storeyId; - } - } - return null; - } + if (loader.parseText && typeof data === 'string') { + return await loader.parseText(data, options, context, loader); + } - /** - * Converts a 3D World-space position to a 2D position within a StoreyMap image. - * - * Use {@link StoreyViewsPlugin#pickStoreyMap} to convert 2D image positions to 3D world-space. - * - * @param {StoreyMap} storeyMap The StoreyMap. - * @param {Number[]} worldPos 3D World-space position within the storey. - * @param {Number[]} imagePos 2D pixel position within the {@link StoreyMap#imageData}. - * @returns {Boolean} True if ````imagePos```` is within the bounds of the {@link StoreyMap#imageData}, else ````false```` if it falls outside. - */ - worldPosToStoreyMap(storeyMap, worldPos, imagePos) { + if (loader.parse) { + return await loader.parse(data, options, context, loader); + } - const storeyId = storeyMap.storeyId; - const storey = this.storeys[storeyId]; + assert$4(!loader.parseSync); + throw new Error("".concat(loader.id, " loader - no parser found and worker is disabled")); +} - if (!storey) { - this.error("IfcBuildingStorey not found with this ID: " + storeyId); - return false - } +const VERSION$5 = "3.2.6" ; - const aabb = storey.aabb; +const VERSION$4 = "3.2.6" ; - const xmin = aabb[0]; - const ymin = aabb[1]; - const zmin = aabb[2]; +const VERSION$3 = "3.2.6" ; +const BASIS_CDN_ENCODER_WASM = "https://unpkg.com/@loaders.gl/textures@".concat(VERSION$3, "/dist/libs/basis_encoder.wasm"); +const BASIS_CDN_ENCODER_JS = "https://unpkg.com/@loaders.gl/textures@".concat(VERSION$3, "/dist/libs/basis_encoder.js"); +let loadBasisTranscoderPromise; +async function loadBasisTrascoderModule(options) { + const modules = options.modules || {}; - const xmax = aabb[3]; - const ymax = aabb[4]; - const zmax = aabb[5]; + if (modules.basis) { + return modules.basis; + } - const xWorldSize = xmax - xmin; - const yWorldSize = ymax - ymin; - const zWorldSize = zmax - zmin; + loadBasisTranscoderPromise = loadBasisTranscoderPromise || loadBasisTrascoder(options); + return await loadBasisTranscoderPromise; +} - const camera = this.viewer.camera; - const worldUp = camera.worldUp; +async function loadBasisTrascoder(options) { + let BASIS = null; + let wasmBinary = null; + [BASIS, wasmBinary] = await Promise.all([await loadLibrary('basis_transcoder.js', 'textures', options), await loadLibrary('basis_transcoder.wasm', 'textures', options)]); + BASIS = BASIS || globalThis.BASIS; + return await initializeBasisTrascoderModule(BASIS, wasmBinary); +} - const xUp = worldUp[0] > worldUp[1] && worldUp[0] > worldUp[2]; - const yUp = !xUp && worldUp[1] > worldUp[0] && worldUp[1] > worldUp[2]; - !xUp && !yUp && worldUp[2] > worldUp[0] && worldUp[2] > worldUp[1]; +function initializeBasisTrascoderModule(BasisModule, wasmBinary) { + const options = {}; - const ratioX = (storeyMap.width / xWorldSize); - const ratioY = yUp ? (storeyMap.height / zWorldSize) : (storeyMap.height / yWorldSize); // Assuming either Y or Z is "up", but never X + if (wasmBinary) { + options.wasmBinary = wasmBinary; + } - imagePos[0] = Math.floor(storeyMap.width - ((worldPos[0] - xmin) * ratioX)); - imagePos[1] = Math.floor(storeyMap.height - ((worldPos[2] - zmin) * ratioY)); + return new Promise(resolve => { + BasisModule(options).then(module => { + const { + BasisFile, + initializeBasis + } = module; + initializeBasis(); + resolve({ + BasisFile + }); + }); + }); +} - return (imagePos[0] >= 0 && imagePos[0] < storeyMap.width && imagePos[1] >= 0 && imagePos[1] <= storeyMap.height); - } +let loadBasisEncoderPromise; +async function loadBasisEncoderModule(options) { + const modules = options.modules || {}; - /** - * Converts a 3D World-space direction vector to a 2D vector within a StoreyMap image. - * - * @param {StoreyMap} storeyMap The StoreyMap. - * @param {Number[]} worldDir 3D World-space direction vector. - * @param {Number[]} imageDir Normalized 2D direction vector. - */ - worldDirToStoreyMap(storeyMap, worldDir, imageDir) { - const camera = this.viewer.camera; - const eye = camera.eye; - const look = camera.look; - const eyeLookDir = math.subVec3(look, eye, tempVec3a$6); - const worldUp = camera.worldUp; - const xUp = worldUp[0] > worldUp[1] && worldUp[0] > worldUp[2]; - const yUp = !xUp && worldUp[1] > worldUp[0] && worldUp[1] > worldUp[2]; - !xUp && !yUp && worldUp[2] > worldUp[0] && worldUp[2] > worldUp[1]; - if (xUp) { - imageDir[0] = eyeLookDir[1]; - imageDir[1] = eyeLookDir[2]; - } else if (yUp) { - imageDir[0] = eyeLookDir[0]; - imageDir[1] = eyeLookDir[2]; - } else { - imageDir[0] = eyeLookDir[0]; - imageDir[1] = eyeLookDir[1]; + if (modules.basisEncoder) { + return modules.basisEncoder; + } + + loadBasisEncoderPromise = loadBasisEncoderPromise || loadBasisEncoder(options); + return await loadBasisEncoderPromise; +} + +async function loadBasisEncoder(options) { + let BASIS_ENCODER = null; + let wasmBinary = null; + [BASIS_ENCODER, wasmBinary] = await Promise.all([await loadLibrary(BASIS_CDN_ENCODER_JS, 'textures', options), await loadLibrary(BASIS_CDN_ENCODER_WASM, 'textures', options)]); + BASIS_ENCODER = BASIS_ENCODER || globalThis.BASIS; + return await initializeBasisEncoderModule(BASIS_ENCODER, wasmBinary); +} + +function initializeBasisEncoderModule(BasisEncoderModule, wasmBinary) { + const options = {}; + + if (wasmBinary) { + options.wasmBinary = wasmBinary; + } + + return new Promise(resolve => { + BasisEncoderModule(options).then(module => { + const { + BasisFile, + KTX2File, + initializeBasis, + BasisEncoder + } = module; + initializeBasis(); + resolve({ + BasisFile, + KTX2File, + BasisEncoder + }); + }); + }); +} + +const GL_EXTENSIONS_CONSTANTS = { + COMPRESSED_RGB_S3TC_DXT1_EXT: 0x83f0, + COMPRESSED_RGBA_S3TC_DXT1_EXT: 0x83f1, + COMPRESSED_RGBA_S3TC_DXT3_EXT: 0x83f2, + COMPRESSED_RGBA_S3TC_DXT5_EXT: 0x83f3, + COMPRESSED_R11_EAC: 0x9270, + COMPRESSED_SIGNED_R11_EAC: 0x9271, + COMPRESSED_RG11_EAC: 0x9272, + COMPRESSED_SIGNED_RG11_EAC: 0x9273, + COMPRESSED_RGB8_ETC2: 0x9274, + COMPRESSED_RGBA8_ETC2_EAC: 0x9275, + COMPRESSED_SRGB8_ETC2: 0x9276, + COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: 0x9277, + COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: 0x9278, + COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: 0x9279, + COMPRESSED_RGB_PVRTC_4BPPV1_IMG: 0x8c00, + COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: 0x8c02, + COMPRESSED_RGB_PVRTC_2BPPV1_IMG: 0x8c01, + COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: 0x8c03, + COMPRESSED_RGB_ETC1_WEBGL: 0x8d64, + COMPRESSED_RGB_ATC_WEBGL: 0x8c92, + COMPRESSED_RGBA_ATC_EXPLICIT_ALPHA_WEBGL: 0x8c93, + COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL: 0x87ee, + COMPRESSED_RGBA_ASTC_4X4_KHR: 0x93b0, + COMPRESSED_RGBA_ASTC_5X4_KHR: 0x93b1, + COMPRESSED_RGBA_ASTC_5X5_KHR: 0x93b2, + COMPRESSED_RGBA_ASTC_6X5_KHR: 0x93b3, + COMPRESSED_RGBA_ASTC_6X6_KHR: 0x93b4, + COMPRESSED_RGBA_ASTC_8X5_KHR: 0x93b5, + COMPRESSED_RGBA_ASTC_8X6_KHR: 0x93b6, + COMPRESSED_RGBA_ASTC_8X8_KHR: 0x93b7, + COMPRESSED_RGBA_ASTC_10X5_KHR: 0x93b8, + COMPRESSED_RGBA_ASTC_10X6_KHR: 0x93b9, + COMPRESSED_RGBA_ASTC_10X8_KHR: 0x93ba, + COMPRESSED_RGBA_ASTC_10X10_KHR: 0x93bb, + COMPRESSED_RGBA_ASTC_12X10_KHR: 0x93bc, + COMPRESSED_RGBA_ASTC_12X12_KHR: 0x93bd, + COMPRESSED_SRGB8_ALPHA8_ASTC_4X4_KHR: 0x93d0, + COMPRESSED_SRGB8_ALPHA8_ASTC_5X4_KHR: 0x93d1, + COMPRESSED_SRGB8_ALPHA8_ASTC_5X5_KHR: 0x93d2, + COMPRESSED_SRGB8_ALPHA8_ASTC_6X5_KHR: 0x93d3, + COMPRESSED_SRGB8_ALPHA8_ASTC_6X6_KHR: 0x93d4, + COMPRESSED_SRGB8_ALPHA8_ASTC_8X5_KHR: 0x93d5, + COMPRESSED_SRGB8_ALPHA8_ASTC_8X6_KHR: 0x93d6, + COMPRESSED_SRGB8_ALPHA8_ASTC_8X8_KHR: 0x93d7, + COMPRESSED_SRGB8_ALPHA8_ASTC_10X5_KHR: 0x93d8, + COMPRESSED_SRGB8_ALPHA8_ASTC_10X6_KHR: 0x93d9, + COMPRESSED_SRGB8_ALPHA8_ASTC_10X8_KHR: 0x93da, + COMPRESSED_SRGB8_ALPHA8_ASTC_10X10_KHR: 0x93db, + COMPRESSED_SRGB8_ALPHA8_ASTC_12X10_KHR: 0x93dc, + COMPRESSED_SRGB8_ALPHA8_ASTC_12X12_KHR: 0x93dd, + COMPRESSED_RED_RGTC1_EXT: 0x8dbb, + COMPRESSED_SIGNED_RED_RGTC1_EXT: 0x8dbc, + COMPRESSED_RED_GREEN_RGTC2_EXT: 0x8dbd, + COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: 0x8dbe, + COMPRESSED_SRGB_S3TC_DXT1_EXT: 0x8c4c, + COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: 0x8c4d, + COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: 0x8c4e, + COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: 0x8c4f +}; + +const BROWSER_PREFIXES = ['', 'WEBKIT_', 'MOZ_']; +const WEBGL_EXTENSIONS = { + WEBGL_compressed_texture_s3tc: 'dxt', + WEBGL_compressed_texture_s3tc_srgb: 'dxt-srgb', + WEBGL_compressed_texture_etc1: 'etc1', + WEBGL_compressed_texture_etc: 'etc2', + WEBGL_compressed_texture_pvrtc: 'pvrtc', + WEBGL_compressed_texture_atc: 'atc', + WEBGL_compressed_texture_astc: 'astc', + EXT_texture_compression_rgtc: 'rgtc' +}; +let formats = null; +function getSupportedGPUTextureFormats(gl) { + if (!formats) { + gl = gl || getWebGLContext() || undefined; + formats = new Set(); + + for (const prefix of BROWSER_PREFIXES) { + for (const extension in WEBGL_EXTENSIONS) { + if (gl && gl.getExtension("".concat(prefix).concat(extension))) { + const gpuTextureFormat = WEBGL_EXTENSIONS[extension]; + formats.add(gpuTextureFormat); } - math.normalizeVec2(imageDir); + } } + } - /** - * Destroys this StoreyViewsPlugin. - */ - destroy() { - this.viewer.scene.off(this._onModelLoaded); - super.destroy(); - } + return formats; } -/** - * Tests if {@link TreeViewPlugin} would be able to create a "types" hierarchy for the given {@link MetaModel}. - * - * @param {MetaModel} metaModel The MetaModel. - * @param {String[]} errors Accumulates messages for validation errors. - * @return {boolean} Returns ````true```` if no errors found, else ````false````. - */ -function validateMetaModelForTreeViewTypesHierarchy(metaModel, errors) { - const rootMetaObject = metaModel.rootMetaObject; - if (!rootMetaObject) { - errors.push("Can't build types hierarchy: model is empty"); - return false; - } - return true; +function getWebGLContext() { + try { + const canvas = document.createElement('canvas'); + return canvas.getContext('webgl'); + } catch (error) { + return null; + } } -/** - * Tests if {@link TreeViewPlugin} would be able to create a "storeys" hierarchy for the given {@link MetaModel}. - * - * @param {MetaModel} metaModel The MetaModel. - * @param {String[]} errors Accumulates messages for validation errors. - * @return {boolean} Returns ````true```` if no errors found, else ````false````. - */ -function validateMetaModelForTreeViewStoreysHierarchy(metaModel, errors) { - const rootMetaObject = metaModel.rootMetaObject; - if (!rootMetaObject) { - errors.push("Can't build storeys hierarchy: model is empty"); - return false; - } - return _validateMetaModelForStoreysHierarchy(rootMetaObject, errors); +var n,i,s,a,r,o,l,f;!function(t){t[t.NONE=0]="NONE",t[t.BASISLZ=1]="BASISLZ",t[t.ZSTD=2]="ZSTD",t[t.ZLIB=3]="ZLIB";}(n||(n={})),function(t){t[t.BASICFORMAT=0]="BASICFORMAT";}(i||(i={})),function(t){t[t.UNSPECIFIED=0]="UNSPECIFIED",t[t.ETC1S=163]="ETC1S",t[t.UASTC=166]="UASTC";}(s||(s={})),function(t){t[t.UNSPECIFIED=0]="UNSPECIFIED",t[t.SRGB=1]="SRGB";}(a||(a={})),function(t){t[t.UNSPECIFIED=0]="UNSPECIFIED",t[t.LINEAR=1]="LINEAR",t[t.SRGB=2]="SRGB",t[t.ITU=3]="ITU",t[t.NTSC=4]="NTSC",t[t.SLOG=5]="SLOG",t[t.SLOG2=6]="SLOG2";}(r||(r={})),function(t){t[t.ALPHA_STRAIGHT=0]="ALPHA_STRAIGHT",t[t.ALPHA_PREMULTIPLIED=1]="ALPHA_PREMULTIPLIED";}(o||(o={})),function(t){t[t.RGB=0]="RGB",t[t.RRR=3]="RRR",t[t.GGG=4]="GGG",t[t.AAA=15]="AAA";}(l||(l={})),function(t){t[t.RGB=0]="RGB",t[t.RGBA=3]="RGBA",t[t.RRR=4]="RRR",t[t.RRRG=5]="RRRG";}(f||(f={})); + +const KTX2_ID = [0xab, 0x4b, 0x54, 0x58, 0x20, 0x32, 0x30, 0xbb, 0x0d, 0x0a, 0x1a, 0x0a]; +function isKTX(data) { + const id = new Uint8Array(data); + const notKTX = id.byteLength < KTX2_ID.length || id[0] !== KTX2_ID[0] || id[1] !== KTX2_ID[1] || id[2] !== KTX2_ID[2] || id[3] !== KTX2_ID[3] || id[4] !== KTX2_ID[4] || id[5] !== KTX2_ID[5] || id[6] !== KTX2_ID[6] || id[7] !== KTX2_ID[7] || id[8] !== KTX2_ID[8] || id[9] !== KTX2_ID[9] || id[10] !== KTX2_ID[10] || id[11] !== KTX2_ID[11]; + return !notKTX; } -/** - * Tests if {@link TreeViewPlugin} would be able to create a "containment" hierarchy for the given {@link MetaModel}. - * - * @param {MetaModel} metaModel The MetaModel. - * @param {String[]} errors Accumulates messages for validation errors. - * @return {boolean} Returns ````true```` if no errors found, else ````false````. - */ -function validateMetaModelForTreeViewContainmentHierarchy(metaModel, errors) { - const rootMetaObject = metaModel.rootMetaObject; - if (!rootMetaObject) { - errors.push("Can't build containment hierarchy: model is empty"); - return false; +const OutputFormat = { + etc1: { + basisFormat: 0, + compressed: true, + format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_ETC1_WEBGL + }, + etc2: { + basisFormat: 1, + compressed: true + }, + bc1: { + basisFormat: 2, + compressed: true, + format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_S3TC_DXT1_EXT + }, + bc3: { + basisFormat: 3, + compressed: true, + format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_S3TC_DXT5_EXT + }, + bc4: { + basisFormat: 4, + compressed: true + }, + bc5: { + basisFormat: 5, + compressed: true + }, + 'bc7-m6-opaque-only': { + basisFormat: 6, + compressed: true + }, + 'bc7-m5': { + basisFormat: 7, + compressed: true + }, + 'pvrtc1-4-rgb': { + basisFormat: 8, + compressed: true, + format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGB_PVRTC_4BPPV1_IMG + }, + 'pvrtc1-4-rgba': { + basisFormat: 9, + compressed: true, + format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG + }, + 'astc-4x4': { + basisFormat: 10, + compressed: true, + format: GL_EXTENSIONS_CONSTANTS.COMPRESSED_RGBA_ASTC_4X4_KHR + }, + 'atc-rgb': { + basisFormat: 11, + compressed: true + }, + 'atc-rgba-interpolated-alpha': { + basisFormat: 12, + compressed: true + }, + rgba32: { + basisFormat: 13, + compressed: false + }, + rgb565: { + basisFormat: 14, + compressed: false + }, + bgr565: { + basisFormat: 15, + compressed: false + }, + rgba4444: { + basisFormat: 16, + compressed: false + } +}; +async function parseBasis(data, options) { + if (options.basis.containerFormat === 'auto') { + if (isKTX(data)) { + const fileConstructors = await loadBasisEncoderModule(options); + return parseKTX2File(fileConstructors.KTX2File, data, options); } - return true; + + const { + BasisFile + } = await loadBasisTrascoderModule(options); + return parseBasisFile(BasisFile, data, options); + } + + switch (options.basis.module) { + case 'encoder': + const fileConstructors = await loadBasisEncoderModule(options); + + switch (options.basis.containerFormat) { + case 'ktx2': + return parseKTX2File(fileConstructors.KTX2File, data, options); + + case 'basis': + default: + return parseBasisFile(fileConstructors.BasisFile, data, options); + } + + case 'transcoder': + default: + const { + BasisFile + } = await loadBasisTrascoderModule(options); + return parseBasisFile(BasisFile, data, options); + } } -/** - * @private - */ -function _validateMetaModelForStoreysHierarchy(metaObject, errors, level = 0, ctx, buildingNode) { - ctx = ctx || { - foundIFCBuildingStoreys: false - }; - const metaObjectType = metaObject.type; - const children = metaObject.children; - if (metaObjectType === "IfcBuilding") { - buildingNode = true; - } else if (metaObjectType === "IfcBuildingStorey") { - if (!buildingNode) { - errors.push("Can't build storeys hierarchy: IfcBuildingStorey found without parent IfcBuilding"); - return false; - } - ctx.foundIFCBuildingStoreys = true; - } - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - const childMetaObject = children[i]; - if (!_validateMetaModelForStoreysHierarchy(childMetaObject, errors, level + 1, ctx, buildingNode)) { - return false; - } - } +function parseBasisFile(BasisFile, data, options) { + const basisFile = new BasisFile(new Uint8Array(data)); + + try { + if (!basisFile.startTranscoding()) { + throw new Error('Failed to start basis transcoding'); } - if (level === 0) { - if (!ctx.foundIFCBuildingStoreys) ; + + const imageCount = basisFile.getNumImages(); + const images = []; + + for (let imageIndex = 0; imageIndex < imageCount; imageIndex++) { + const levelsCount = basisFile.getNumLevels(imageIndex); + const levels = []; + + for (let levelIndex = 0; levelIndex < levelsCount; levelIndex++) { + levels.push(transcodeImage(basisFile, imageIndex, levelIndex, options)); + } + + images.push(levels); } - return true; + + return images; + } finally { + basisFile.close(); + basisFile.delete(); + } } -const idMap = new Map$1(); +function transcodeImage(basisFile, imageIndex, levelIndex, options) { + const width = basisFile.getImageWidth(imageIndex, levelIndex); + const height = basisFile.getImageHeight(imageIndex, levelIndex); + const hasAlpha = basisFile.getHasAlpha(); + const { + compressed, + format, + basisFormat + } = getBasisOptions(options, hasAlpha); + const decodedSize = basisFile.getImageTranscodedSizeInBytes(imageIndex, levelIndex, basisFormat); + const decodedData = new Uint8Array(decodedSize); -/** - * @desc Represents a model tree view within a {@link TreeViewPlugin}. - * - * * Stored in {@link treeViewPlugin#modelTreeViews}, mapped to the model ID. - * * Created by each call to {@link TreeViewPlugin#addModel}. - */ -class ModelTreeView { + if (!basisFile.transcodeImage(decodedData, imageIndex, levelIndex, basisFormat, 0, 0)) { + throw new Error('failed to start Basis transcoding'); + } - /** - * @private - */ - constructor(viewer, treeViewPlugin, model, metaModel, cfg) { + return { + width, + height, + data: decodedData, + compressed, + format, + hasAlpha + }; +} - if (!cfg.containerElement) { - throw "Config expected: containerElement"; - } +function parseKTX2File(KTX2File, data, options) { + const ktx2File = new KTX2File(new Uint8Array(data)); - const rootMetaObject = metaModel.rootMetaObject; - if (!rootMetaObject) { - return; - } + try { + if (!ktx2File.startTranscoding()) { + throw new Error('failed to start KTX2 transcoding'); + } - /** - * Contains messages for any errors found in the MetaModel for this ModelTreeView. - * @type {String[]} - */ - this.errors = []; + const levelsCount = ktx2File.getLevels(); + const levels = []; - /** - * True if errors were found in the MetaModel for this ModelTreeView. - * @type {boolean} - */ - this.valid = true; + for (let levelIndex = 0; levelIndex < levelsCount; levelIndex++) { + levels.push(transcodeKTX2Image(ktx2File, levelIndex, options)); + break; + } - /** - * The MetaModel corresponding to this ModelTreeView. - * @type {MetaModel} - */ - this.metaModel = metaModel; + return [levels]; + } finally { + ktx2File.close(); + ktx2File.delete(); + } +} - this._id = idMap.addItem(); - this._baseId = "" + this._id; - this._viewer = viewer; - this._treeViewPlugin = treeViewPlugin; - this._rootMetaObject = rootMetaObject; - this._containerElement = cfg.containerElement; - this._rootElement = null; - this._muteSceneEvents = false; - this._muteTreeEvents = false; - this._rootNodes = []; - this._objectNodes = {}; - this._rootName = cfg.rootName; - this._sortNodes = cfg.sortNodes; - this._pruneEmptyNodes = cfg.pruneEmptyNodes; +function transcodeKTX2Image(ktx2File, levelIndex, options) { + const { + alphaFlag, + height, + width + } = ktx2File.getImageLevelInfo(levelIndex, 0, 0); + const { + compressed, + format, + basisFormat + } = getBasisOptions(options, alphaFlag); + const decodedSize = ktx2File.getImageTranscodedSizeInBytes(levelIndex, 0, 0, basisFormat); + const decodedData = new Uint8Array(decodedSize); - this._showListItemElementId = null; + if (!ktx2File.transcodeImage(decodedData, levelIndex, 0, 0, basisFormat, 0, -1, -1)) { + throw new Error('Failed to transcode KTX2 image'); + } - this._containerElement.oncontextmenu = (e) => { - e.preventDefault(); - }; + return { + width, + height, + data: decodedData, + compressed, + hasAlpha: alphaFlag, + format + }; +} - this._onObjectVisibility = this._viewer.scene.on("objectVisibility", (entity) => { - if (this._muteSceneEvents) { - return; - } - const objectId = entity.id; - const node = this._objectNodes[objectId]; - if (!node) { - return; // Not in this tree - } - const visible = entity.visible; - const updated = (visible !== node.checked); - if (!updated) { - return; - } - this._muteTreeEvents = true; - node.checked = visible; - if (visible) { - node.numVisibleEntities++; - } else { - node.numVisibleEntities--; - } - const checkbox = document.getElementById(node.nodeId); - if (checkbox) { - checkbox.checked = visible; - } - let parent = node.parent; - while (parent) { - parent.checked = visible; - if (visible) { - parent.numVisibleEntities++; - } else { - parent.numVisibleEntities--; - } - const parentCheckbox = document.getElementById(parent.nodeId); - if (parentCheckbox) { - const newChecked = (parent.numVisibleEntities > 0); - if (newChecked !== parentCheckbox.checked) { - parentCheckbox.checked = newChecked; - } - } - parent = parent.parent; - } - this._muteTreeEvents = false; - }); +function getBasisOptions(options, hasAlpha) { + let format = options && options.basis && options.basis.format; - this.switchExpandHandler = (event) => { - event.preventDefault(); - event.stopPropagation(); - const switchElement = event.target; - this._expandSwitchElement(switchElement); - }; + if (format === 'auto') { + format = selectSupportedBasisFormat(); + } - this.switchCollapseHandler = (event) => { - event.preventDefault(); - event.stopPropagation(); - const switchElement = event.target; - this._collapseSwitchElement(switchElement); - }; + if (typeof format === 'object') { + format = hasAlpha ? format.alpha : format.noAlpha; + } - this._checkboxChangeHandler = (event) => { - if (this._muteTreeEvents) { - return; - } - this._muteSceneEvents = true; - const checkbox = event.target; - const visible = checkbox.checked; - const nodeId = checkbox.id; - const checkedObjectId = this._nodeToObjectID(nodeId); - const checkedNode = this._objectNodes[checkedObjectId]; - const objects = this._viewer.scene.objects; - let numUpdated = 0; - this._withNodeTree(checkedNode, (node) => { - const objectId = node.objectId; - const checkBoxId = node.nodeId; - const entity = objects[objectId]; - const isLeaf = (node.children.length === 0); - node.numVisibleEntities = visible ? node.numEntities : 0; - if (isLeaf && (visible !== node.checked)) { - numUpdated++; - } - node.checked = visible; - const checkbox2 = document.getElementById(checkBoxId); - if (checkbox2) { - checkbox2.checked = visible; - } - if (entity) { - entity.visible = visible; - } - }); - let parent = checkedNode.parent; - while (parent) { - parent.checked = visible; - const checkbox2 = document.getElementById(parent.nodeId); // Parent checkboxes are always in DOM - if (visible) { - parent.numVisibleEntities += numUpdated; - } else { - parent.numVisibleEntities -= numUpdated; - } - const newChecked = (parent.numVisibleEntities > 0); - if (newChecked !== checkbox2.checked) { - checkbox2.checked = newChecked; - } - parent = parent.parent; - } - this._muteSceneEvents = false; - }; + format = format.toLowerCase(); + return OutputFormat[format]; +} - this._hierarchy = cfg.hierarchy || "containment"; - this._autoExpandDepth = cfg.autoExpandDepth || 0; +function selectSupportedBasisFormat() { + const supportedFormats = getSupportedGPUTextureFormats(); - this._createNodes(); - } + if (supportedFormats.has('astc')) { + return 'astc-4x4'; + } else if (supportedFormats.has('dxt')) { + return { + alpha: 'bc3', + noAlpha: 'bc1' + }; + } else if (supportedFormats.has('pvrtc')) { + return { + alpha: 'pvrtc1-4-rgba', + noAlpha: 'pvrtc1-4-rgb' + }; + } else if (supportedFormats.has('etc1')) { + return 'etc1'; + } else if (supportedFormats.has('etc2')) { + return 'etc2'; + } - _nodeToObjectID(nodeId) { - return nodeId.substring(this._baseId.length); - } + return 'rgb565'; +} - _objectToNodeID(objectId) { - return this._baseId + objectId; +const BasisWorkerLoader = { + name: 'Basis', + id: 'basis', + module: 'textures', + version: VERSION$4, + worker: true, + extensions: ['basis', 'ktx2'], + mimeTypes: ['application/octet-stream', 'image/ktx2'], + tests: ['sB'], + binary: true, + options: { + basis: { + format: 'auto', + libraryPath: 'libs/', + containerFormat: 'auto', + module: 'transcoder' } + } +}; +const BasisLoader = { ...BasisWorkerLoader, + parse: parseBasis +}; - /** - * @private - * @param depth - */ - setAutoExpandDepth(depth = 0) { - this._autoExpandDepth = depth; - } +const VERSION$2 = "3.2.6" ; - /** - * @private - * @param hierarchy - */ - setHierarchy(hierarchy) { - if (this._hierarchy === hierarchy) { - return; - } - this._hierarchy = hierarchy; - this._createNodes(); - } +const { + _parseImageNode +} = globalThis; +const IMAGE_SUPPORTED = typeof Image !== 'undefined'; +const IMAGE_BITMAP_SUPPORTED = typeof ImageBitmap !== 'undefined'; +const NODE_IMAGE_SUPPORTED = Boolean(_parseImageNode); +const DATA_SUPPORTED = isBrowser$4 ? true : NODE_IMAGE_SUPPORTED; +function isImageTypeSupported(type) { + switch (type) { + case 'auto': + return IMAGE_BITMAP_SUPPORTED || IMAGE_SUPPORTED || DATA_SUPPORTED; - _createNodes() { - if (this._rootElement) { - this._rootElement.parentNode.removeChild(this._rootElement); - this._rootElement = null; - } - this._rootNodes = []; - this._objectNodes = {}; - this._validate(); - if (this.valid || (this._hierarchy !== "storeys")) { - this._createEnabledNodes(); - } else { - this._createDisabledNodes(); - } - } + case 'imagebitmap': + return IMAGE_BITMAP_SUPPORTED; - _validate() { - this.errors = []; - switch (this._hierarchy) { - case "storeys": - this.valid = validateMetaModelForTreeViewStoreysHierarchy(this.metaModel, this.errors); - break; - case "types": - this.valid = validateMetaModelForTreeViewTypesHierarchy(this.metaModel, this.errors); - break; - case "containment": - default: - this.valid = validateMetaModelForTreeViewContainmentHierarchy(this.metaModel, this.errors); - break; - } - return this.valid; - } + case 'image': + return IMAGE_SUPPORTED; - _createEnabledNodes() { - if (this._pruneEmptyNodes) { - this._findEmptyNodes(); - } - switch (this._hierarchy) { - case "storeys": - this._createStoreysNodes(); - if (this._rootNodes.length === 0) { - this._treeViewPlugin.error("Failed to build storeys hierarchy for model '" + this.metaModel.id + "' - perhaps this model is not an IFC model?"); - } - break; - case "types": - this._createTypesNodes(); - break; - case "containment": - default: - this._createContainmentNodes(); - } - if (this._sortNodes) { - this._doSortNodes(); - } - this._synchNodesToEntities(); - this._createTrees(); - this.expandToDepth(this._autoExpandDepth); - } + case 'data': + return DATA_SUPPORTED; - _createDisabledNodes() { + default: + throw new Error("@loaders.gl/images: image ".concat(type, " not supported in this environment")); + } +} +function getDefaultImageType() { + if (IMAGE_BITMAP_SUPPORTED) { + return 'imagebitmap'; + } - const metaObject = this._rootMetaObject; - const metaObjectType = metaObject.type; - const metaObjectName = metaObject.name; + if (IMAGE_SUPPORTED) { + return 'image'; + } - const rootName = ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType); + if (DATA_SUPPORTED) { + return 'data'; + } - const ul = document.createElement('ul'); - const li = document.createElement('li'); - ul.appendChild(li); - this._containerElement.appendChild(ul); - this._rootElement = ul; + throw new Error('Install \'@loaders.gl/polyfills\' to parse images under Node.js'); +} - const switchElement = document.createElement('a'); - switchElement.href = '#'; - switchElement.textContent = '!'; - switchElement.classList.add('warn'); - switchElement.classList.add('warning'); - li.appendChild(switchElement); +function getImageType(image) { + const format = getImageTypeOrNull(image); - const span = document.createElement('span'); - span.textContent = rootName; - li.appendChild(span); + if (!format) { + throw new Error('Not an image'); + } + + return format; +} +function getImageData(image) { + switch (getImageType(image)) { + case 'data': + return image; + + case 'image': + case 'imagebitmap': + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + + if (!context) { + throw new Error('getImageData'); + } + + canvas.width = image.width; + canvas.height = image.height; + context.drawImage(image, 0, 0); + return context.getImageData(0, 0, image.width, image.height); + + default: + throw new Error('getImageData'); + } +} + +function getImageTypeOrNull(image) { + if (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) { + return 'imagebitmap'; + } + + if (typeof Image !== 'undefined' && image instanceof Image) { + return 'image'; + } + + if (image && typeof image === 'object' && image.data && image.width && image.height) { + return 'data'; + } + + return null; +} + +const SVG_DATA_URL_PATTERN = /^data:image\/svg\+xml/; +const SVG_URL_PATTERN = /\.svg((\?|#).*)?$/; +function isSVG(url) { + return url && (SVG_DATA_URL_PATTERN.test(url) || SVG_URL_PATTERN.test(url)); +} +function getBlobOrSVGDataUrl(arrayBuffer, url) { + if (isSVG(url)) { + const textDecoder = new TextDecoder(); + let xmlText = textDecoder.decode(arrayBuffer); + + try { + if (typeof unescape === 'function' && typeof encodeURIComponent === 'function') { + xmlText = unescape(encodeURIComponent(xmlText)); + } + } catch (error) { + throw new Error(error.message); } - _findEmptyNodes(metaObject = this._rootMetaObject, countEntities = 0) { - const viewer = this._treeViewPlugin.viewer; - const scene = viewer.scene; - const children = metaObject.children; - const objectId = metaObject.id; - const entity = scene.objects[objectId]; - metaObject._countEntities = 0; - if (entity) { - metaObject._countEntities++; - } - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - const childMetaObject = children[i]; - childMetaObject._countEntities = this._findEmptyNodes(childMetaObject); - metaObject._countEntities += childMetaObject._countEntities; - } - } - return metaObject._countEntities; + const src = "data:image/svg+xml;base64,".concat(btoa(xmlText)); + return src; + } + + return getBlob(arrayBuffer, url); +} +function getBlob(arrayBuffer, url) { + if (isSVG(url)) { + throw new Error('SVG cannot be parsed directly to imagebitmap'); + } + + return new Blob([new Uint8Array(arrayBuffer)]); +} + +async function parseToImage(arrayBuffer, options, url) { + const blobOrDataUrl = getBlobOrSVGDataUrl(arrayBuffer, url); + const URL = self.URL || self.webkitURL; + const objectUrl = typeof blobOrDataUrl !== 'string' && URL.createObjectURL(blobOrDataUrl); + + try { + return await loadToImage(objectUrl || blobOrDataUrl, options); + } finally { + if (objectUrl) { + URL.revokeObjectURL(objectUrl); } + } +} +async function loadToImage(url, options) { + const image = new Image(); + image.src = url; - _createStoreysNodes( - metaObject = this._rootMetaObject, - buildingNode, - storeyNode, - typeNodes) { - if (this._pruneEmptyNodes && (metaObject._countEntities === 0)) { - return; - } - const metaObjectType = metaObject.type; - const metaObjectName = metaObject.name; - const children = metaObject.children; - const objectId = metaObject.id; - if (metaObjectType === "IfcBuilding") { - buildingNode = { - nodeId: this._objectToNodeID(objectId), - objectId: objectId, - title: this._rootName || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType), - type: metaObjectType, - parent: null, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - this._rootNodes.push(buildingNode); - this._objectNodes[buildingNode.objectId] = buildingNode; - } else if (metaObjectType === "IfcBuildingStorey") { - if (!buildingNode) { - this._treeViewPlugin.error("Failed to build storeys hierarchy for model '" + this.metaModel.id + "' - model does not have an IfcBuilding object, or is not an IFC model"); - return; - } - storeyNode = { - nodeId: this._objectToNodeID(objectId), - objectId: objectId, - title: (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, - type: metaObjectType, - parent: buildingNode, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - buildingNode.children.push(storeyNode); - this._objectNodes[storeyNode.objectId] = storeyNode; - typeNodes = {}; - } else { - if (storeyNode) { - const objects = this._viewer.scene.objects; - const object = objects[objectId]; - if (object) { - typeNodes = typeNodes || {}; - let typeNode = typeNodes[metaObjectType]; - if (!typeNode) { - const typeNodeObjectId = storeyNode.objectId + "." + metaObjectType; - const typeNodeNodeId = this._objectToNodeID(typeNodeObjectId); - typeNode = { - nodeId: typeNodeNodeId, - objectId: typeNodeObjectId, - title: metaObjectType, - type: metaObjectType, - parent: storeyNode, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - storeyNode.children.push(typeNode); - this._objectNodes[typeNodeObjectId] = typeNode; - typeNodes[metaObjectType] = typeNode; - } - const node = { - nodeId: this._objectToNodeID(objectId), - objectId: objectId, - title: (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, - type: metaObjectType, - parent: typeNode, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - typeNode.children.push(node); - this._objectNodes[node.objectId] = node; - } - } - } - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - const childMetaObject = children[i]; - this._createStoreysNodes(childMetaObject, buildingNode, storeyNode, typeNodes); - } - } - } - - _createTypesNodes(metaObject = this._rootMetaObject, rootNode, typeNodes) { - if (this._pruneEmptyNodes && (metaObject._countEntities === 0)) { - return; - } - const metaObjectType = metaObject.type; - const metaObjectName = metaObject.name; - const children = metaObject.children; - const objectId = metaObject.id; - if (metaObject.id === this._rootMetaObject.id) { - rootNode = { - nodeId: this._objectToNodeID(objectId), - objectId: objectId, - title: this._rootName || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType), - type: metaObjectType, - parent: null, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - this._rootNodes.push(rootNode); - this._objectNodes[rootNode.objectId] = rootNode; - typeNodes = {}; - } else { - if (rootNode) { - const objects = this._viewer.scene.objects; - const object = objects[objectId]; - if (object) { - let typeNode = typeNodes[metaObjectType]; - if (!typeNode) { - typeNode = { - nodeId: this._objectToNodeID(rootNode.objectId + "." + metaObjectType), - objectId: rootNode.objectId + "." + metaObjectType, - title: metaObjectType, - type: metaObjectType, - parent: rootNode, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - rootNode.children.push(typeNode); - this._objectNodes[typeNode.objectId] = typeNode; - typeNodes[metaObjectType] = typeNode; - } - const node = { - nodeId: this._objectToNodeID(objectId), - objectId: objectId, - title: (metaObjectName && metaObjectName !== "" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, - type: metaObjectType, - parent: typeNode, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - typeNode.children.push(node); - this._objectNodes[node.objectId] = node; - } - } - } - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - const childMetaObject = children[i]; - this._createTypesNodes(childMetaObject, rootNode, typeNodes); - } - } - } - - _createContainmentNodes(metaObject = this._rootMetaObject, parent) { - if (this._pruneEmptyNodes && (metaObject._countEntities === 0)) { - return; - } - const metaObjectType = metaObject.type; - const metaObjectName = metaObject.name || metaObjectType; - const children = metaObject.children; - const objectId = metaObject.id; - const node = { - nodeId: this._objectToNodeID(objectId), - objectId: objectId, - title: (!parent) ? (this._rootName || metaObjectName) : (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, - type: metaObjectType, - parent: parent, - numEntities: 0, - numVisibleEntities: 0, - checked: false, - children: [] - }; - if (parent) { - parent.children.push(node); - } else { - this._rootNodes.push(node); - } - this._objectNodes[node.objectId] = node; + if (options.image && options.image.decode && image.decode) { + await image.decode(); + return image; + } - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - const childMetaObject = children[i]; - this._createContainmentNodes(childMetaObject, node); - } - } - } + return await new Promise((resolve, reject) => { + try { + image.onload = () => resolve(image); - _doSortNodes() { - for (let i = 0, len = this._rootNodes.length; i < len; i++) { - const rootNode = this._rootNodes[i]; - this._sortChildren(rootNode); - } + image.onerror = err => reject(new Error("Could not load image ".concat(url, ": ").concat(err))); + } catch (error) { + reject(error); } + }); +} - _sortChildren(node) { - const children = node.children; - if (!children || children.length === 0) { - return; - } - if (this._hierarchy === "storeys" && node.type === "IfcBuilding") { - // Assumes that children of an IfcBuilding will always be IfcBuildingStoreys - children.sort(this._getSpatialSortFunc()); - } else { - children.sort(this._alphaSortFunc); - } - for (let i = 0, len = children.length; i < len; i++) { - const node = children[i]; - this._sortChildren(node); - } - } +const EMPTY_OBJECT = {}; +let imagebitmapOptionsSupported = true; +async function parseToImageBitmap(arrayBuffer, options, url) { + let blob; - _getSpatialSortFunc() { // Creates cached sort func with Viewer in scope - const viewer = this._treeViewPlugin.viewer; - const scene = viewer.scene; - const camera = scene.camera; - const metaScene = viewer.metaScene; - return this._spatialSortFunc || (this._spatialSortFunc = (node1, node2) => { - if (!node1.aabb || !node2.aabb) { - // Sorting on lowest point of the AABB is likely more more robust when objects could overlap storeys - if (!node1.aabb) { - node1.aabb = scene.getAABB(metaScene.getObjectIDsInSubtree(node1.objectId)); - } - if (!node2.aabb) { - node2.aabb = scene.getAABB(metaScene.getObjectIDsInSubtree(node2.objectId)); - } - } - let idx = 0; - if (camera.xUp) { - idx = 0; - } else if (camera.yUp) { - idx = 1; - } else { - idx = 2; - } - if (node1.aabb[idx] > node2.aabb[idx]) { - return -1; - } - if (node1.aabb[idx] < node2.aabb[idx]) { - return 1; - } - return 0; - }); - } + if (isSVG(url)) { + const image = await parseToImage(arrayBuffer, options, url); + blob = image; + } else { + blob = getBlob(arrayBuffer, url); + } - _alphaSortFunc(node1, node2) { - const title1 = node1.title.toUpperCase(); // FIXME: Should be case sensitive? - const title2 = node2.title.toUpperCase(); - if (title1 < title2) { - return -1; - } - if (title1 > title2) { - return 1; - } - return 0; - } + const imagebitmapOptions = options && options.imagebitmap; + return await safeCreateImageBitmap(blob, imagebitmapOptions); +} - _synchNodesToEntities() { - const rootMetaObject = this._rootMetaObject; - const objectIds = rootMetaObject.getObjectIDsInSubtree(); - const metaObjects = this._viewer.metaScene.metaObjects; - const objects = this._viewer.scene.objects; - for (let i = 0, len = objectIds.length; i < len; i++) { - const objectId = objectIds[i]; - const metaObject = metaObjects[objectId]; - if (metaObject) { - const node = this._objectNodes[objectId]; - if (node) { - const entity = objects[objectId]; - if (entity) { - const visible = entity.visible; - node.numEntities = 1; - if (visible) { - node.numVisibleEntities = 1; - node.checked = true; - } else { - node.numVisibleEntities = 0; - node.checked = false; - } - let parent = node.parent; // Synch parents - while (parent) { - parent.numEntities++; - if (visible) { - parent.numVisibleEntities++; - parent.checked = true; - } - parent = parent.parent; - } - } - } - } - } - } +async function safeCreateImageBitmap(blob, imagebitmapOptions = null) { + if (isEmptyObject(imagebitmapOptions) || !imagebitmapOptionsSupported) { + imagebitmapOptions = null; + } - _withNodeTree(node, callback) { - callback(node); - const children = node.children; - if (!children) { - return; - } - for (let i = 0, len = children.length; i < len; i++) { - this._withNodeTree(children[i], callback); - } + if (imagebitmapOptions) { + try { + return await createImageBitmap(blob, imagebitmapOptions); + } catch (error) { + console.warn(error); + imagebitmapOptionsSupported = false; } + } - _createTrees() { - if (this._rootNodes.length === 0) { - return; - } - const rootNodeElements = this._rootNodes.map((rootNode) => { - return this._createNodeElement(rootNode); - }); - const ul = document.createElement('ul'); - rootNodeElements.forEach((nodeElement) => { - ul.appendChild(nodeElement); - }); - this._containerElement.appendChild(ul); - this._rootElement = ul; - } + return await createImageBitmap(blob); +} - _createNodeElement(node) { - const nodeElement = document.createElement('li'); - //const nodeId = this._objectToNodeID(node.objectId); - const nodeId = node.nodeId; - nodeElement.id = 'node-' + nodeId; - if (node.children.length > 0) { - const switchElementId = "switch-" + nodeId; - const switchElement = document.createElement('a'); - switchElement.href = '#'; - switchElement.id = switchElementId; - switchElement.textContent = '+'; - switchElement.classList.add('plus'); - switchElement.addEventListener('click', this.switchExpandHandler); - nodeElement.appendChild(switchElement); - } - const checkbox = document.createElement('input'); - checkbox.id = nodeId; - checkbox.type = "checkbox"; - checkbox.checked = node.checked; - checkbox.style["pointer-events"] = "all"; - checkbox.addEventListener("change", this._checkboxChangeHandler); - nodeElement.appendChild(checkbox); - const span = document.createElement('span'); - span.textContent = node.title; - nodeElement.appendChild(span); - span.oncontextmenu = (e) => { - this._treeViewPlugin.fire("contextmenu", { - event: e, - viewer: this._viewer, - treeViewPlugin: this._treeViewPlugin, - treeViewNode: node - }); - e.preventDefault(); - }; - span.onclick = (e) => { - this._treeViewPlugin.fire("nodeTitleClicked", { - event: e, - viewer: this._viewer, - treeViewPlugin: this._treeViewPlugin, - treeViewNode: node - }); - e.preventDefault(); - }; - return nodeElement; - } +function isEmptyObject(object) { + for (const key in object || EMPTY_OBJECT) { + return false; + } - /** - * @private - * @param depth - */ - expandToDepth(depth) { - const expand = (node, countDepth) => { - if (countDepth === depth) { - return; - } - const nodeId = node.nodeId; - const switchElementId = "switch-" + nodeId; - const switchElement = document.getElementById(switchElementId); - if (switchElement) { - this._expandSwitchElement(switchElement); - const childNodes = node.children; - for (var i = 0, len = childNodes.length; i < len; i++) { - const childNode = childNodes[i]; - expand(childNode, countDepth + 1); - } - } - }; - for (let i = 0, len = this._rootNodes.length; i < len; i++) { - const rootNode = this._rootNodes[i]; - expand(rootNode, 0); - } - } + return true; +} - /** - * @private - */ - collapse() { - for (let i = 0, len = this._rootNodes.length; i < len; i++) { - const rootNode = this._rootNodes[i]; - const objectId = rootNode.objectId; - this._collapseNode(objectId); - } - } +const BIG_ENDIAN = false; +const LITTLE_ENDIAN = true; +function getBinaryImageMetadata(binaryData) { + const dataView = toDataView(binaryData); + return getPngMetadata(dataView) || getJpegMetadata(dataView) || getGifMetadata(dataView) || getBmpMetadata(dataView); +} - /** - * @private - * @param objectId - */ - showNode(objectId) { - if (this._showListItemElementId) { - this.unShowNode(); - } - const node = this._objectNodes[objectId]; - if (!node) { - return; // Node may not exist for the given object if (this._pruneEmptyNodes == true) - } - const nodeId = node.nodeId; - const switchElementId = "switch-" + nodeId; - const switchElement = document.getElementById(switchElementId); - if (switchElement) { - this._expandSwitchElement(switchElement); - switchElement.scrollIntoView(); - return; - } - const path = []; - path.unshift(node); - let parent = node.parent; - while (parent) { - path.unshift(parent); - parent = parent.parent; - } - for (let i = 0, len = path.length; i < len; i++) { - const node = path[i]; - const nodeId = node.nodeId; - const switchElementId = "switch-" + nodeId; - const switchElement = document.getElementById(switchElementId); - if (switchElement) { - this._expandSwitchElement(switchElement); - } - } - const listItemElementId = 'node-' + nodeId; - const listItemElement = document.getElementById(listItemElementId); - listItemElement.scrollIntoView({block: "center"}); - listItemElement.classList.add("highlighted-node"); - this._showListItemElementId = listItemElementId; - } +function getPngMetadata(binaryData) { + const dataView = toDataView(binaryData); + const isPng = dataView.byteLength >= 24 && dataView.getUint32(0, BIG_ENDIAN) === 0x89504e47; - /** - * @private - */ - unShowNode() { - if (!this._showListItemElementId) { - return; - } - const listItemElement = document.getElementById(this._showListItemElementId); - if (!listItemElement) { - this._showListItemElementId = null; - return; - } - listItemElement.classList.remove("highlighted-node"); - this._showListItemElementId = null; - } + if (!isPng) { + return null; + } - _expandSwitchElement(switchElement) { - const parentElement = switchElement.parentElement; - const expanded = parentElement.getElementsByTagName('li')[0]; - if (expanded) { - return; - } - const nodeId = parentElement.id.replace('node-', ''); - const objectId = this._nodeToObjectID(nodeId); - const switchNode = this._objectNodes[objectId]; - const childNodes = switchNode.children; - const nodeElements = childNodes.map((node) => { - return this._createNodeElement(node); - }); - const ul = document.createElement('ul'); - nodeElements.forEach((nodeElement) => { - ul.appendChild(nodeElement); - }); - parentElement.appendChild(ul); - switchElement.classList.remove('plus'); - switchElement.classList.add('minus'); - switchElement.textContent = '-'; - switchElement.removeEventListener('click', this.switchExpandHandler); - switchElement.addEventListener('click', this.switchCollapseHandler); - } + return { + mimeType: 'image/png', + width: dataView.getUint32(16, BIG_ENDIAN), + height: dataView.getUint32(20, BIG_ENDIAN) + }; +} - _collapseNode(objectId) { - const nodeId = this._objectToNodeID(objectId); - const switchElementId = "switch-" + nodeId; - const switchElement = document.getElementById(switchElementId); - this._collapseSwitchElement(switchElement); - } +function getGifMetadata(binaryData) { + const dataView = toDataView(binaryData); + const isGif = dataView.byteLength >= 10 && dataView.getUint32(0, BIG_ENDIAN) === 0x47494638; - _collapseSwitchElement(switchElement) { - if (!switchElement) { - return; - } - const parent = switchElement.parentElement; - if (!parent) { - return; - } - const ul = parent.querySelector('ul'); - if (!ul) { - return; - } - parent.removeChild(ul); - switchElement.classList.remove('minus'); - switchElement.classList.add('plus'); - switchElement.textContent = '+'; - switchElement.removeEventListener('click', this.switchCollapseHandler); - switchElement.addEventListener('click', this.switchExpandHandler); - } + if (!isGif) { + return null; + } - /** - * Destroys this ModelTreeView. - * @private - */ - destroy() { - if (this._rootElement && !this._destroyed) { - this._rootElement.parentNode.removeChild(this._rootElement); - this._viewer.scene.off(this._onObjectVisibility); - this._destroyed = true; - idMap.removeItem(this._id); - } - } + return { + mimeType: 'image/gif', + width: dataView.getUint16(6, LITTLE_ENDIAN), + height: dataView.getUint16(8, LITTLE_ENDIAN) + }; } -/** - * @desc A {@link Viewer} plugin that provides an HTML tree view to navigate the IFC elements in models. - *
- * - * - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_WestRiverSideHospital)] - * - * ## Overview - * - * * A fast HTML tree view, with zero external dependencies, that works with huge numbers of objects. - * * Each tree node has a checkbox to control the visibility of its object. - * * Has three hierarchy modes: "containment", "types" and "storeys". - * * Automatically contains all models (that have metadata) that are currently in the {@link Scene}. - * * Sorts tree nodes by default - spatially, from top-to-bottom for ````IfcBuildingStorey```` nodes, and alphanumerically for other nodes. - * * Allows custom CSS styling. - * * Use {@link ContextMenu} to create a context menu for the tree nodes. - * - * ## Credits - * - * TreeViewPlugin is based on techniques described in [*Super Fast Tree View in JavaScript*](https://chrissmith.xyz/super-fast-tree-view-in-javascript/) by [Chris Smith](https://twitter.com/chris22smith). - * - * ## Usage - * - * In the example below, we'll add a TreeViewPlugin which, by default, will automatically show the structural - * hierarchy of the IFC elements in each model we load. - * - * Then we'll use an {@link XKTLoaderPlugin} to load the Schependomlaan model from an - * [.xkt file](https://github.com/xeokit/xeokit-sdk/tree/master/examples/models/xkt/schependomlaan). - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_Schependomlaan)] - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, TreeViewPlugin} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [-2.56, 8.38, 8.27]; - * viewer.camera.look = [13.44, 3.31, -14.83]; - * viewer.camera.up = [0.10, 0.98, -0.14]; - * - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer") - * }); - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/Schependomlaan.xkt", - * edges: true - * }); - * ```` - * - * ## Manually Adding Models - * - * Instead of adding models automatically, we can control which models appear in our TreeViewPlugin by adding them manually. - * - * In the next example, we'll configure the TreeViewPlugin to not add models automatically. Then, once the model - * has loaded, we'll add it manually using {@link TreeViewPlugin#addModel}. - * - * ````javascript - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer"), - * autoAddModels: false // <<---------------- Don't auto-add models - * }); - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/Schependomlaan.xkt", - * edges: true - * }); - * - * model.on("loaded", () => { - * treeView.addModel(model.id); - * }); - * ```` - * - * Adding models manually also allows us to set some options for the model. For example, the ````rootName```` option allows us to provide a custom name for - * the root node, which is sometimes desirable when the model's "IfcProject" element's name is not suitable: - * - * ````javascript - * model.on("loaded", () => { - * treeView.addModel(model.id, { - * rootName: "Schependomlaan Model" - * }); - * }); - * ```` - * - * ## Initially Expanding the Hierarchy - * - * We can also configure TreeViewPlugin to initially expand each model's nodes to a given depth. - * - * Let's automatically expand the first three nodes from the root, for every model added: - * - * ````javascript - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer"), - * autoExpandDepth: 3 - * }); - * ```` - * - * ## Showing a Node by ID - * - * We can show a given node using its ID. This causes the TreeViewPlugin to collapse, then expand and scroll the node into view, then highlight the node. - * - * See the documentation for the {@link TreeViewPlugin#showNode} method for more information, including how to define a custom highlighted appearance for the node using CSS. - * - * Let's make the TreeViewPlugin show the node corresponding to whatever object {@link Entity} that we pick: - * - * ````javascript - * viewer.cameraControl.on("picked", function (e) { - * var objectId = e.entity.id; - * treeView.showNode(objectId); - * }); - * ```` - * - * This will de-highlight any node that was previously shown by this method. - * - * Note that this method only works if the picked {@link Entity} is an object that belongs to a model that's represented in the TreeViewPlugin. - * - * ## Customizing Appearance - * - * We can customize the appearance of our TreeViewPlugin by defining custom CSS for its HTML - * elements. See our example's [source code](https://github.com/xeokit/xeokit-sdk/blob/master/examples/BIMOffline_XKT_Schependomlaan.html) - * for an example of custom CSS rules. - * - * ## Model Hierarchies - * - * TreeViewPlugin has three hierarchies for organizing its nodes: - * - * * "containment" - organizes the tree nodes to indicate the containment hierarchy of the {@link MetaObject}s. - * * "types" - groups nodes by their IFC types. - * * "storeys" - groups nodes within their ````IfcBuildingStoreys````, and sub-groups them by their IFC types. - * - *
- * The table below shows what the hierarchies look like: - *
- * - * | 1. Containment Hierarchy | 2. Types Hierarchy | 3. Storeys Hierarchy | - * |---|---|---| - * | | | | - *
- * - * Let's create a TreeViewPlugin that groups nodes by their building stories and IFC types: - * - * ````javascript - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer"), - * hierarchy: "stories" - * }); - * ```` - * - * ## Sorting Nodes - * - * TreeViewPlugin sorts its tree nodes by default. For a "storeys" hierarchy, it orders ````IfcBuildingStorey```` nodes - * spatially, with the node for the highest story at the top, down to the lowest at the bottom. - * - * For all the hierarchy types ("containment", "classes" and "storeys"), TreeViewPlugin sorts the other node types - * alphanumerically on their titles. - * - * If for some reason you need to prevent sorting, create your TreeViewPlugin with the option disabled, like so: - * - * ````javascript - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer"), - * hierarchy: "stories", - * sortNodes: false // <<------ Disable node sorting - * }); - * ```` - * - * Note that, for all hierarchy modes, node sorting is only done for each model at the time that it is added to the TreeViewPlugin, and will not - * update dynamically if we later transform the {@link Entity}s corresponding to the nodes. - * - * ## Pruning empty nodes - * - * Sometimes a model contains subtrees of objects that don't have any geometry. These are models whose - * {@link MetaModel} contains trees of {@link MetaObject}s that don't have any {@link Entity}s in the {@link Scene}. - * - * For these models, the tree view would contain nodes that don't do anything in the Scene when we interact with them, - * which is undesirable. - * - * By default, TreeViewPlugin will not create nodes for those objects. However, we can override that behaviour if we want - * to have nodes for those objects (perhaps for debugging the model): - * - * ````javascript - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer"), - * hierarchy: "stories", - * pruneEmptyNodes: false // <<------ Create nodes for object subtrees without geometry - * }); - * ```` - * - * ## Context Menu - * - * TreeViewPlugin fires a "contextmenu" event whenever we right-click on a tree node. - * - * The event contains: - * - * * ````event```` - the original [contextmenu](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event) [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) - * * ````viewer```` - the {@link Viewer} - * * ````treeViewPlugin```` - the TreeViewPlugin - * * ````treeViewNode```` - the {@link TreeViewNode} representing the tree node - *

- * - * Let's use {@link ContextMenu} to show a simple context menu for the node we clicked. - * - * [[Run an example](https://xeokit.github.io/xeokit-sdk/examples/#ContextMenu_Canvas_TreeViewPlugin_Custom)] - * - * ````javascript - * import {ContextMenu} from "../src/extras/ContextMenu/ContextMenu.js"; - * - * const treeViewContextMenu = new ContextMenu({ - * items: [ - * [ - * [ - * { - * title: "Hide", - * doAction: function (context) { - * context.treeViewPlugin.withNodeTree(context.treeViewNode, (treeViewNode) => { - * if (treeViewNode.objectId) { - * const entity = context.viewer.scene.objects[treeViewNode.objectId]; - * if (entity) { - * entity.visible = false; - * } - * } - * }); - * } - * }, - * { - * title: "Hide all", - * doAction: function (context) { - * context.viewer.scene.setObjectsVisible(context.viewer.scene.visibleObjectIds, false); - * } - * } - * ], - * [ - * { - * title: "Show", - * doAction: function (context) { - * context.treeViewPlugin.withNodeTree(context.treeViewNode, (treeViewNode) => { - * if (treeViewNode.objectId) { - * const entity = context.viewer.scene.objects[treeViewNode.objectId]; - * if (entity) { - * entity.visible = true; - * entity.xrayed = false; - * entity.selected = false; - * } - * } - * }); - * } - * }, - * { - * title: "Show all", - * doAction: function (context) { - * const scene = context.viewer.scene; - * scene.setObjectsVisible(scene.objectIds, true); - * scene.setObjectsXRayed(scene.xrayedObjectIds, false); - * scene.setObjectsSelected(scene.selectedObjectIds, false); - * } - * } - * ] - * ] - * ] - * }); - * - * treeView.on("contextmenu", (e) => { - * - * const event = e.event; // MouseEvent - * const viewer = e.viewer; // Viewer - * const treeViewPlugin = e.treeViewPlugin; // TreeViewPlugin - * const treeViewNode = e.treeViewNode; // TreeViewNode - * - * treeViewContextMenu.show(e.event.pageX, e.event.pageY); - * - * treeViewContextMenu.context = { - * viewer: e.viewer, - * treeViewPlugin: e.treeViewPlugin, - * treeViewNode: e.treeViewNode - * }; - * }); - * ```` - * - * ## Clicking Node Titles - * - * TreeViewPlugin fires a "nodeTitleClicked" event whenever we left-click on a tree node. - * - * Like the "contextmenu" event, this event contains: - * - * * ````event```` - the original [click](https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event) [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) - * * ````viewer```` - the {@link Viewer} - * * ````treeViewPlugin```` - the TreeViewPlugin - * * ````treeViewNode```` - the {@link TreeViewNode} representing the tree node - *

- * - * Let's register a callback to isolate and fit-to-view the {@link Entity}(s) represented by the node. This callback is - * going to X-ray all the other Entitys, fly the camera to fit the Entity(s) for the clicked node, then hide the other Entitys. - * - * [[Run an example](https://xeokit.github.io/xeokit-sdk/examples/#ContextMenu_Canvas_TreeViewPlugin_Custom)] - * - * ````javascript - * treeView.on("nodeTitleClicked", (e) => { - * const scene = viewer.scene; - * const objectIds = []; - * e.treeViewPlugin.withNodeTree(e.treeViewNode, (treeViewNode) => { - * if (treeViewNode.objectId) { - * objectIds.push(treeViewNode.objectId); - * } - * }); - * scene.setObjectsXRayed(scene.objectIds, true); - * scene.setObjectsVisible(scene.objectIds, true); - * scene.setObjectsXRayed(objectIds, false); - * viewer.cameraFlight.flyTo({ - * aabb: scene.getAABB(objectIds), - * duration: 0.5 - * }, () => { - * setTimeout(function () { - * scene.setObjectsVisible(scene.xrayedObjectIds, false); - * scene.setObjectsXRayed(scene.xrayedObjectIds, false); - * }, 500); - * }); - * }); - * ```` - * - * To make the cursor change to a pointer when we hover over the node titles, and also to make the titles change to blue, we'll also define this CSS for the ```````` elements - * that represent the titles of our TreeViewPlugin nodes: - * - * ````css - * #treeViewContainer ul li span:hover { - * color: blue; - * cursor: pointer; - * } - * ```` - * - * @class TreeViewPlugin - */ -class TreeViewPlugin extends Plugin { +function getBmpMetadata(binaryData) { + const dataView = toDataView(binaryData); + const isBmp = dataView.byteLength >= 14 && dataView.getUint16(0, BIG_ENDIAN) === 0x424d && dataView.getUint32(2, LITTLE_ENDIAN) === dataView.byteLength; - /** - * @constructor - * - * @param {Viewer} viewer The Viewer. - * @param {*} cfg Plugin configuration. - * @param {HTMLElement} cfg.containerElement DOM element to contain the TreeViewPlugin. - * @param {Boolean} [cfg.autoAddModels=true] When ````true```` (default), will automatically add each model as it's created. Set this ````false```` if you want to manually add models using {@link TreeViewPlugin#addModel} instead. - * @param {Number} [cfg.autoExpandDepth] Optional depth to which to initially expand the tree. - * @param {String} [cfg.hierarchy="containment"] How to organize the tree nodes: "containment", "storeys" or "types". See the class documentation for details. - * @param {Boolean} [cfg.sortNodes=true] When true, will sort the children of each node. For a "storeys" hierarchy, the - * ````IfcBuildingStorey```` nodes will be ordered spatially, from the highest storey down to the lowest, on the - * vertical World axis. For all hierarchy types, other node types will be ordered in the ascending alphanumeric order of their titles. - * @param {Boolean} [cfg.pruneEmptyNodes=true] When true, will not contain nodes that don't have content in the {@link Scene}. These are nodes whose {@link MetaObject}s don't have {@link Entity}s. - */ - constructor(viewer, cfg = {}) { + if (!isBmp) { + return null; + } - super("TreeViewPlugin", viewer); + return { + mimeType: 'image/bmp', + width: dataView.getUint32(18, LITTLE_ENDIAN), + height: dataView.getUint32(22, LITTLE_ENDIAN) + }; +} - if (!cfg.containerElement) { - this.error("Config expected: containerElement"); - return; - } +function getJpegMetadata(binaryData) { + const dataView = toDataView(binaryData); + const isJpeg = dataView.byteLength >= 3 && dataView.getUint16(0, BIG_ENDIAN) === 0xffd8 && dataView.getUint8(2) === 0xff; - this._containerElement = cfg.containerElement; - this._modelTreeViews = {}; - this._autoAddModels = (cfg.autoAddModels !== false); - this._autoExpandDepth = (cfg.autoExpandDepth || 0); - this._sortNodes = (cfg.sortNodes !== false); - this._pruneEmptyNodes = (cfg.pruneEmptyNodes !== false); + if (!isJpeg) { + return null; + } - if (this._autoAddModels) { - const modelIds = Object.keys(this.viewer.metaScene.metaModels); - for (let i = 0, len = modelIds.length; i < len; i++) { - const modelId = modelIds[i]; - this.addModel(modelId); - } - this.viewer.scene.on("modelLoaded", (modelId) => { - if (this.viewer.metaScene.metaModels[modelId]) { - this.addModel(modelId); - } - }); - } + const { + tableMarkers, + sofMarkers + } = getJpegMarkers(); + let i = 2; - this.hierarchy = cfg.hierarchy; - } + while (i + 9 < dataView.byteLength) { + const marker = dataView.getUint16(i, BIG_ENDIAN); - /** - * Returns the map of {@link ModelTreeView}s. - * - * Each ModelTreeView is mapped to the ID of its model. - * - * @return {*|{}} - */ - get modelTreeViews() { - return this._modelTreeViews; + if (sofMarkers.has(marker)) { + return { + mimeType: 'image/jpeg', + height: dataView.getUint16(i + 5, BIG_ENDIAN), + width: dataView.getUint16(i + 7, BIG_ENDIAN) + }; } - /** - * Sets how the nodes are organized within this tree view. - * - * Accepted values are: - * - * * "containment" - organizes the nodes to indicate the containment hierarchy of the IFC objects. - * * "types" - groups the nodes within their IFC types. - * * "storeys" - groups the nodes within ````IfcBuildingStoreys```` and sub-groups them by their IFC types. - * - *
- * This can be updated dynamically. - * - * Default value is "containment". - * - * @type {String} - */ - set hierarchy(hierarchy) { - hierarchy = hierarchy || "containment"; - if (hierarchy !== "containment" && hierarchy !== "storeys" && hierarchy !== "types") { - this.error("Unsupported value for `hierarchy' - defaulting to 'containment'"); - hierarchy = "containment"; - } - this._hierarchy = hierarchy; - for (let modelId in this._modelTreeViews) { - if (this._modelTreeViews.hasOwnProperty(modelId)) { - this._modelTreeViews[modelId].setHierarchy(this._hierarchy); - } - } + if (!tableMarkers.has(marker)) { + return null; } - /** - * Gets how the nodes are organized within this tree view. - * - * @type {String} - */ - get hierarchy() { - return this._hierarchy; - } + i += 2; + i += dataView.getUint16(i, BIG_ENDIAN); + } - /** - * Adds a model to this tree view. - * - * The model will be automatically removed when destroyed. - * - * To automatically add each model as it's created, instead of manually calling this method each time, - * provide a ````autoAddModels: true```` to the TreeViewPlugin constructor. - * - * @param {String} modelId ID of a model {@link Entity} in {@link Scene#models}. - * @param {Object} [options] Options for model in the tree view. - * @param {String} [options.rootName] Optional display name for the root node. Ordinary, for "containment" - * and "storeys" hierarchy types, the tree would derive the root node name from the model's "IfcProject" element - * name. This option allows to override that name when it is not suitable as a display name. - * @returns {ModelTreeView} ModelTreeView for the newly-added model. If this method succeeded in adding the model, - * then {@link ModelTreeView#valid} will equal ````true````. Otherwise, that property will be ````false```` - * and {@link ModelTreeView#errors} will contain error messages. - */ - addModel(modelId, options = {}) { - if (!this._containerElement) { - return; - } - const model = this.viewer.scene.models[modelId]; - if (!model) { - throw "Model not found: " + modelId; - } - const metaModel = this.viewer.metaScene.metaModels[modelId]; - if (!metaModel) { - this.error("MetaModel not found: " + modelId); - return; - } - if (this._modelTreeViews[modelId]) { - this.warn("Model already added: " + modelId); - return; - } - const modelTreeView = new ModelTreeView(this.viewer, this, model, metaModel, { - containerElement: this._containerElement, - autoExpandDepth: this._autoExpandDepth, - hierarchy: this._hierarchy, - sortNodes: this._sortNodes, - pruneEmptyNodes: this._pruneEmptyNodes, - rootName: options.rootName - }); - this._modelTreeViews[modelId] = modelTreeView; - model.on("destroyed", () => { - this.removeModel(model.id); - }); - return modelTreeView; - } + return null; +} - /** - * Removes a model from this tree view. - * - * Does nothing if model not currently in tree view. - * - * @param {String} modelId ID of a model {@link Entity} in {@link Scene#models}. - */ - removeModel(modelId) { - if (!this._containerElement) { - return; - } - const modelTreeView = this._modelTreeViews[modelId]; - if (!modelTreeView) { - return; - } - modelTreeView.destroy(); - delete this._modelTreeViews[modelId]; - } +function getJpegMarkers() { + const tableMarkers = new Set([0xffdb, 0xffc4, 0xffcc, 0xffdd, 0xfffe]); - /** - * Collapses all trees within this tree view. - */ - collapse() { - for (let modelId in this._modelTreeViews) { - if (this._modelTreeViews.hasOwnProperty(modelId)) { - const modelTreeView = this._modelTreeViews[modelId]; - modelTreeView.collapse(); - } - } - } + for (let i = 0xffe0; i < 0xfff0; ++i) { + tableMarkers.add(i); + } - /** - * Highlights the tree view node that represents the given object {@link Entity}. - * - * This causes the tree view to collapse, then expand to reveal the node, then highlight the node. - * - * If a node is previously highlighted, de-highlights that node and collapses the tree first. - * - * Note that if the TreeViewPlugin was configured with ````pruneEmptyNodes: true```` (default configuration), then the - * node won't exist in the tree if it has no Entitys in the {@link Scene}. in that case, nothing will happen. - * - * Within the DOM, the node is represented by an ````
  • ```` element. This method will add a ````.highlighted-node```` class to - * the element to make it appear highlighted, removing that class when de-highlighting it again. See the CSS rules - * in the TreeViewPlugin examples for an example of that class. - * - * @param {String} objectId ID of the {@link Entity}. - */ - showNode(objectId) { - this.unShowNode(); - const metaObject = this.viewer.metaScene.metaObjects[objectId]; - if (!metaObject) { - this.error("MetaObject not found: " + objectId); - return; - } - const metaModel = metaObject.metaModel; - const modelId = metaModel.id; - const modelTreeView = this._modelTreeViews[modelId]; - if (!modelTreeView) { - this.error("Object not in this TreeView: " + objectId); - return; - } - modelTreeView.showNode(objectId); - } + const sofMarkers = new Set([0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc9, 0xffca, 0xffcb, 0xffcd, 0xffce, 0xffcf, 0xffde]); + return { + tableMarkers, + sofMarkers + }; +} - /** - * De-highlights the node previously shown with {@link TreeViewPlugin#showNode}. - * - * Does nothing if no node is currently shown. - * - * If the node is currently scrolled into view, keeps the node in view. - */ - unShowNode() { - for (let modelId in this._modelTreeViews) { - if (this._modelTreeViews.hasOwnProperty(modelId)) { - const modelTreeView = this._modelTreeViews[modelId]; - modelTreeView.unShowNode(); - } - } - } +function toDataView(data) { + if (data instanceof DataView) { + return data; + } - /** - * Expands the tree to the given depth. - * - * Collapses the tree first. - * - * @param {Number} depth Depth to expand to. - */ - expandToDepth(depth) { - for (let modelId in this._modelTreeViews) { - if (this._modelTreeViews.hasOwnProperty(modelId)) { - const modelTreeView = this._modelTreeViews[modelId]; - modelTreeView.collapse(); - modelTreeView.expandToDepth(depth); - } - } - } + if (ArrayBuffer.isView(data)) { + return new DataView(data.buffer); + } - /** - * Iterates over a subtree of the tree view's {@link TreeViewNode}s, calling the given callback for each - * node in depth-first pre-order. - * - * @param {TreeViewNode} node Root of the subtree. - * @param {Function} callback Callback called at each {@link TreeViewNode}, with the TreeViewNode given as the argument. - */ - withNodeTree(node, callback) { - callback(node); - const children = node.children; - if (!children) { - return; - } - for (let i = 0, len = children.length; i < len; i++) { - this.withNodeTree(children[i], callback); - } - } + if (data instanceof ArrayBuffer) { + return new DataView(data); + } - /** - * Destroys this TreeViewPlugin. - */ - destroy() { - if (!this._containerElement) { - return; - } - for (let modelId in this._modelTreeViews) { - if (this._modelTreeViews.hasOwnProperty(modelId)) { - this._modelTreeViews[modelId].destroy(); - } - } - this._modelTreeViews = {}; - super.destroy(); - } + throw new Error('toDataView'); } -const tempVec3a$5 = math.vec3(); -const tempVec3b$5 = math.vec3(); -const tempMat4a = math.mat4(); +async function parseToNodeImage(arrayBuffer, options) { + const { + mimeType + } = getBinaryImageMetadata(arrayBuffer) || {}; + const _parseImageNode = globalThis._parseImageNode; + assert$5(_parseImageNode); + return await _parseImageNode(arrayBuffer, mimeType); +} -/** - * @private - */ -class FrustumPlane { +async function parseImage(arrayBuffer, options, context) { + options = options || {}; + const imageOptions = options.image || {}; + const imageType = imageOptions.type || 'auto'; + const { + url + } = context || {}; + const loadType = getLoadableImageType(imageType); + let image; - constructor() { - this.normal = math.vec3(); - this.offset = 0; - this.testVertex = math.vec3(); - } + switch (loadType) { + case 'imagebitmap': + image = await parseToImageBitmap(arrayBuffer, options, url); + break; - set(nx, ny, nz, offset) { - const s = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz); - this.normal[0] = nx * s; - this.normal[1] = ny * s; - this.normal[2] = nz * s; - this.offset = offset * s; - this.testVertex[0] = (this.normal[0] >= 0.0) ? 1 : 0; - this.testVertex[1] = (this.normal[1] >= 0.0) ? 1 : 0; - this.testVertex[2] = (this.normal[2] >= 0.0) ? 1 : 0; - } -} + case 'image': + image = await parseToImage(arrayBuffer, options, url); + break; -/** - * @private - */ -class Frustum { - constructor() { - this.planes = [ - new FrustumPlane(), new FrustumPlane(), new FrustumPlane(), - new FrustumPlane(), new FrustumPlane(), new FrustumPlane() - ]; - } -} + case 'data': + image = await parseToNodeImage(arrayBuffer); + break; -Frustum.INSIDE = 0; -Frustum.INTERSECT = 1; -Frustum.OUTSIDE = 2; + default: + assert$5(false); + } -/** @private */ -function setFrustum(frustum, viewMat, projMat) { + if (imageType === 'data') { + image = getImageData(image); + } - const m = math.mulMat4(projMat, viewMat, tempMat4a); + return image; +} - const m0 = m[0]; - const m1 = m[1]; - const m2 = m[2]; - const m3 = m[3]; - const m4 = m[4]; - const m5 = m[5]; - const m6 = m[6]; - const m7 = m[7]; - const m8 = m[8]; - const m9 = m[9]; - const m10 = m[10]; - const m11 = m[11]; - const m12 = m[12]; - const m13 = m[13]; - const m14 = m[14]; - const m15 = m[15]; +function getLoadableImageType(type) { + switch (type) { + case 'auto': + case 'data': + return getDefaultImageType(); - frustum.planes[0].set(m3 - m0, m7 - m4, m11 - m8, m15 - m12); - frustum.planes[1].set(m3 + m0, m7 + m4, m11 + m8, m15 + m12); - frustum.planes[2].set(m3 - m1, m7 - m5, m11 - m9, m15 - m13); - frustum.planes[3].set(m3 + m1, m7 + m5, m11 + m9, m15 + m13); - frustum.planes[4].set(m3 - m2, m7 - m6, m11 - m10, m15 - m14); - frustum.planes[5].set(m3 + m2, m7 + m6, m11 + m10, m15 + m14); + default: + isImageTypeSupported(type); + return type; + } } -/** @private */ -function frustumIntersectsAABB3(frustum, aabb) { - - let ret = Frustum.INSIDE; +const EXTENSIONS$1 = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp', 'ico', 'svg']; +const MIME_TYPES = ['image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/bmp', 'image/vnd.microsoft.icon', 'image/svg+xml']; +const DEFAULT_IMAGE_LOADER_OPTIONS = { + image: { + type: 'auto', + decode: true + } +}; +const ImageLoader = { + id: 'image', + module: 'images', + name: 'Images', + version: VERSION$2, + mimeTypes: MIME_TYPES, + extensions: EXTENSIONS$1, + parse: parseImage, + tests: [arrayBuffer => Boolean(getBinaryImageMetadata(new DataView(arrayBuffer)))], + options: DEFAULT_IMAGE_LOADER_OPTIONS +}; - const min = tempVec3a$5; - const max = tempVec3b$5; +const NODE_FORMAT_SUPPORT = ['image/png', 'image/jpeg', 'image/gif']; +const mimeTypeSupported = {}; +function _isImageFormatSupported(mimeType) { + if (mimeTypeSupported[mimeType] === undefined) { + mimeTypeSupported[mimeType] = checkFormatSupport(mimeType); + } - min[0] = aabb[0]; - min[1] = aabb[1]; - min[2] = aabb[2]; - max[0] = aabb[3]; - max[1] = aabb[4]; - max[2] = aabb[5]; + return mimeTypeSupported[mimeType]; +} - const bminmax = [min, max]; +function checkFormatSupport(mimeType) { + switch (mimeType) { + case 'image/webp': + return checkWebPSupport(); - for (let i = 0; i < 6; ++i) { - const plane = frustum.planes[i]; - if (((plane.normal[0] * bminmax[plane.testVertex[0]][0]) + - (plane.normal[1] * bminmax[plane.testVertex[1]][1]) + - (plane.normal[2] * bminmax[plane.testVertex[2]][2]) + - (plane.offset)) < 0.0) { - return Frustum.OUTSIDE; - } + case 'image/svg': + return isBrowser$4; - if (((plane.normal[0] * bminmax[1 - plane.testVertex[0]][0]) + - (plane.normal[1] * bminmax[1 - plane.testVertex[1]][1]) + - (plane.normal[2] * bminmax[1 - plane.testVertex[2]][2]) + - (plane.offset)) < 0.0) { - ret = Frustum.INTERSECT; - } - } + default: + if (!isBrowser$4) { + const { + _parseImageNode + } = globalThis; + return Boolean(_parseImageNode) && NODE_FORMAT_SUPPORT.includes(mimeType); + } - return ret; + return true; + } } -/** - * For each Entity in its Scene, efficiently combines updates from multiple culling systems into a single "culled" state. - * - * Two culling systems are supported: - * - * * View culling - culls Entities when they fall outside the current view frustum, and - * * Detail culling - momentarily culls less visually-significant Entities while we are moving the camera. - * - * @private - */ -class ObjectCullStates { +function checkWebPSupport() { + if (!isBrowser$4) { + return false; + } - /** - * @private - * @param scene - */ - constructor(scene) { + try { + const element = document.createElement('canvas'); + return element.toDataURL('image/webp').indexOf('data:image/webp') === 0; + } catch { + return false; + } +} - this._scene = scene; +function assert$1(condition, message) { + if (!condition) { + throw new Error(message || 'assert failed: gltf'); + } +} - this._objects = []; // Array of all Entity instances that represent objects - this._objectsViewCulled = []; // A flag for each object to indicate its view-cull status - this._objectsDetailCulled = []; // A flag for each object to indicate its detail-cull status - this._objectsChanged = []; // A flag for each object, set whenever its cull status has changed since last _applyChanges() - this._objectsChangedList = []; // A list of objects whose cull status has changed, applied and cleared by _applyChanges() +function resolveUrl(url, options) { + const absolute = url.startsWith('data:') || url.startsWith('http:') || url.startsWith('https:'); - this._modelInfos = {}; + if (absolute) { + return url; + } - this._numObjects = 0; - this._lenObjectsChangedList = 0; + const baseUrl = options.baseUri || options.uri; - this._dirty = true; + if (!baseUrl) { + throw new Error("'baseUri' must be provided to resolve relative url ".concat(url)); + } - this._onModelLoaded = scene.on("modelLoaded", (modelId) => { - const model = scene.models[modelId]; - if (model) { - this._addModel(model); - } - }); + return baseUrl.substr(0, baseUrl.lastIndexOf('/') + 1) + url; +} - this._onTick = scene.on("tick", () => { - if (this._dirty) { - this._build(); - } - this._applyChanges(); - }); - } +function getTypedArrayForBufferView(json, buffers, bufferViewIndex) { + const bufferView = json.bufferViews[bufferViewIndex]; + assert$1(bufferView); + const bufferIndex = bufferView.buffer; + const binChunk = buffers[bufferIndex]; + assert$1(binChunk); + const byteOffset = (bufferView.byteOffset || 0) + binChunk.byteOffset; + return new Uint8Array(binChunk.arrayBuffer, byteOffset, bufferView.byteLength); +} - _addModel(model) { - const modelInfo = { - model: model, - onDestroyed: model.on("destroyed", () => { - this._removeModel(model); - }) - }; - this._modelInfos[model.id] = modelInfo; - this._dirty = true; - } +const TYPES = ['SCALAR', 'VEC2', 'VEC3', 'VEC4']; +const ARRAY_CONSTRUCTOR_TO_WEBGL_CONSTANT = [[Int8Array, 5120], [Uint8Array, 5121], [Int16Array, 5122], [Uint16Array, 5123], [Uint32Array, 5125], [Float32Array, 5126], [Float64Array, 5130]]; +const ARRAY_TO_COMPONENT_TYPE = new Map(ARRAY_CONSTRUCTOR_TO_WEBGL_CONSTANT); +const ATTRIBUTE_TYPE_TO_COMPONENTS = { + SCALAR: 1, + VEC2: 2, + VEC3: 3, + VEC4: 4, + MAT2: 4, + MAT3: 9, + MAT4: 16 +}; +const ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE = { + 5120: 1, + 5121: 1, + 5122: 2, + 5123: 2, + 5125: 4, + 5126: 4 +}; +const ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = { + 5120: Int8Array, + 5121: Uint8Array, + 5122: Int16Array, + 5123: Uint16Array, + 5125: Uint32Array, + 5126: Float32Array +}; +function getAccessorTypeFromSize(size) { + const type = TYPES[size - 1]; + return type || TYPES[0]; +} +function getComponentTypeFromArray(typedArray) { + const componentType = ARRAY_TO_COMPONENT_TYPE.get(typedArray.constructor); - _removeModel(model) { - const modelInfo = this._modelInfos[model.id]; - if (modelInfo) { - modelInfo.model.off(modelInfo.onDestroyed); - delete this._modelInfos[model.id]; - this._dirty = true; - } - } + if (!componentType) { + throw new Error('Illegal typed array'); + } - _build() { - if (!this._dirty) { - return; - } - this._applyChanges(); - const objects = this._scene.objects; - for (let i = 0; i < this._numObjects; i++) { - this._objects[i] = null; - } - this._numObjects = 0; - for (let objectId in objects) { - const entity = objects[objectId]; - this._objects[this._numObjects++] = entity; - } - this._lenObjectsChangedList = 0; - this._dirty = false; - } + return componentType; +} +function getAccessorArrayTypeAndLength(accessor, bufferView) { + const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType]; + const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type]; + const bytesPerComponent = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[accessor.componentType]; + const length = accessor.count * components; + const byteLength = accessor.count * components * bytesPerComponent; + assert$1(byteLength >= 0 && byteLength <= bufferView.byteLength); + return { + ArrayType, + length, + byteLength + }; +} - _applyChanges() { - if (this._lenObjectsChangedList > 0) { - for (let i = 0; i < this._lenObjectsChangedList; i++) { - const objectIdx = this._objectsChangedList[i]; - const object = this._objects[objectIdx]; - const viewCulled = this._objectsViewCulled[objectIdx]; - const detailCulled = this._objectsDetailCulled[objectIdx]; - const culled = (viewCulled || detailCulled); - object.culled = culled; - this._objectsChanged[objectIdx] = false; - } - this._lenObjectsChangedList = 0; - } - } +const DEFAULT_GLTF_JSON = { + asset: { + version: '2.0', + generator: 'loaders.gl' + }, + buffers: [] +}; +class GLTFScenegraph { + constructor(gltf) { + _defineProperty(this, "gltf", void 0); - /** - * Array of {@link Entity} instances that represent objects in the {@link Scene}. - * - * ObjectCullStates rebuilds this from {@link Scene#objects} whenever ````Scene```` fires a ````modelLoaded```` event. - * - * @returns {Entity[]} - */ - get objects() { - if (this._dirty) { - this._build(); - } - return this._objects; - } + _defineProperty(this, "sourceBuffers", void 0); - /** - * Number of objects in {@link ObjectCullStates#objects}, - * - * Updated whenever ````Scene```` fires a ````modelLoaded```` event. - * - * @returns {Number} - */ - get numObjects() { - if (this._dirty) { - this._build(); - } - return this._numObjects; - } + _defineProperty(this, "byteLength", void 0); - /** - * Updates an object's view-cull status. - * - * @param {Number} objectIdx Index of the object in {@link ObjectCullStates#objects} - * @param {boolean} culled Whether to view-cull or not. - */ - setObjectViewCulled(objectIdx, culled) { - if (this._dirty) { - this._build(); - } - if (this._objectsViewCulled[objectIdx] === culled) { - return; - } - this._objectsViewCulled[objectIdx] = culled; - if (!this._objectsChanged[objectIdx]) { - this._objectsChanged[objectIdx] = true; - this._objectsChangedList[this._lenObjectsChangedList++] = objectIdx; - } - } + this.gltf = gltf || { + json: { ...DEFAULT_GLTF_JSON + }, + buffers: [] + }; + this.sourceBuffers = []; + this.byteLength = 0; - /** - * Updates an object's detail-cull status. - * - * @param {Number} objectIdx Index of the object in {@link ObjectCullStates#objects} - * @param {boolean} culled Whether to detail-cull or not. - */ - setObjectDetailCulled(objectIdx, culled) { - if (this._dirty) { - this._build(); - } - if (this._objectsDetailCulled[objectIdx] === culled) { - return; - } - this._objectsDetailCulled[objectIdx] = culled; - if (!this._objectsChanged[objectIdx]) { - this._objectsChanged[objectIdx] = true; - this._objectsChangedList[this._lenObjectsChangedList++] = objectIdx; - } + if (this.gltf.buffers && this.gltf.buffers[0]) { + this.byteLength = this.gltf.buffers[0].byteLength; + this.sourceBuffers = [this.gltf.buffers[0]]; } + } - /** - * Destroys this ObjectCullStAtes. - */ - _destroy() { - this._clear(); - this._scene.off(this._onModelLoaded); - this._scene.off(this._onTick); - } + get json() { + return this.gltf.json; + } - _clear() { - for (let modelId in this._modelInfos) { - const modelInfo = this._modelInfos[modelId]; - modelInfo.model.off(modelInfo.onDestroyed); - } - this._modelInfos = {}; - this._dirty = true; - } -} + getApplicationData(key) { + const data = this.json[key]; + return data; + } -const sceneObjectCullStates = {}; + getExtraData(key) { + const extras = this.json.extras || {}; + return extras[key]; + } -/** - * @private - */ -function getObjectCullStates(scene) { - const sceneId = scene.id; - let objectCullStates = sceneObjectCullStates[sceneId]; - if (!objectCullStates) { - objectCullStates = new ObjectCullStates(scene); - sceneObjectCullStates[sceneId] = objectCullStates; - scene.on("destroyed", () => { - delete sceneObjectCullStates[sceneId]; - objectCullStates._destroy(); - }); - } - return objectCullStates; -} + getExtension(extensionName) { + const isExtension = this.getUsedExtensions().find(name => name === extensionName); + const extensions = this.json.extensions || {}; + return isExtension ? extensions[extensionName] || true : null; + } -const MAX_KD_TREE_DEPTH = 8; // Increase if greater precision needed + getRequiredExtension(extensionName) { + const isRequired = this.getRequiredExtensions().find(name => name === extensionName); + return isRequired ? this.getExtension(extensionName) : null; + } -const kdTreeDimLength = new Float32Array(3); + getRequiredExtensions() { + return this.json.extensionsRequired || []; + } -/** - * {@link Viewer} plugin that performs view frustum culling to accelerate rendering performance. - * - * For each {@link Entity} that represents an object, ````ViewCullPlugin```` will automatically - * set {@link Entity#culled}````false```` whenever it falls outside our field of view. - * - * When culled, an ````Entity```` is not processed by xeokit's renderer. - * - * Internally, ````ViewCullPlugin```` organizes {@link Entity}s in - * a [bounding volume hierarchy](https://en.wikipedia.org/wiki/Bounding_volume_hierarchy), implemented as - * a [kd-tree](https://en.wikipedia.org/wiki/K-d_tree). - * - * On each {@link Scene} "tick" event, ````ViewCullPlugin```` searches the kd-tree using a frustum generated from - * the {@link Camera}, marking each ````Entity```` **culled** if it falls outside the frustum. - * - * Use ````ViewCullPlugin```` by simply adding it to your ````Viewer````: - * - * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * const viewCullPlugin = new ViewCullPlugin(viewer, { - * maxTreeDepth: 20 - * }); - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/OTCConferenceCenter.xkt" - * }); - * ```` - */ -class ViewCullPlugin extends Plugin { + getUsedExtensions() { + return this.json.extensionsUsed || []; + } - /** - * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="ViewCull"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Number} [cfg.maxTreeDepth=8] Maximum depth of the kd-tree. - */ - constructor(viewer, cfg = {}) { + getObjectExtension(object, extensionName) { + const extensions = object.extensions || {}; + return extensions[extensionName]; + } - super("ViewCull", viewer); + getScene(index) { + return this.getObject('scenes', index); + } - this._objectCullStates = getObjectCullStates(viewer.scene); // Combines updates from multiple culling systems for its Scene's Entities + getNode(index) { + return this.getObject('nodes', index); + } - this._maxTreeDepth = cfg.maxTreeDepth || MAX_KD_TREE_DEPTH; - this._modelInfos = {}; - this._frustum = new Frustum(); - this._kdRoot = null; + getSkin(index) { + return this.getObject('skins', index); + } - this._frustumDirty = false; - this._kdTreeDirty = false; + getMesh(index) { + return this.getObject('meshes', index); + } - this._onViewMatrix = viewer.scene.camera.on("viewMatrix", () => { - this._frustumDirty = true; - }); + getMaterial(index) { + return this.getObject('materials', index); + } - this._onProjMatrix = viewer.scene.camera.on("projMatMatrix", () => { - this._frustumDirty = true; - }); + getAccessor(index) { + return this.getObject('accessors', index); + } - this._onModelLoaded = viewer.scene.on("modelLoaded", (modelId) => { - const model = this.viewer.scene.models[modelId]; - if (model) { - this._addModel(model); - } - }); + getTexture(index) { + return this.getObject('textures', index); + } - this._onSceneTick = viewer.scene.on("tick", () => { - this._doCull(); - }); - } + getSampler(index) { + return this.getObject('samplers', index); + } - /** - * Sets whether view culling is enabled. - * - * @param {Boolean} enabled Whether to enable view culling. - */ - set enabled(enabled) { - this._enabled = enabled; - } + getImage(index) { + return this.getObject('images', index); + } - /** - * Gets whether view culling is enabled. - * - * @retutns {Boolean} Whether view culling is enabled. - */ - get enabled() { - return this._enabled; - } + getBufferView(index) { + return this.getObject('bufferViews', index); + } - _addModel(model) { - const modelInfo = { - model: model, - onDestroyed: model.on("destroyed", () => { - this._removeModel(model); - }) - }; - this._modelInfos[model.id] = modelInfo; - this._kdTreeDirty = true; - } + getBuffer(index) { + return this.getObject('buffers', index); + } - _removeModel(model) { - const modelInfo = this._modelInfos[model.id]; - if (modelInfo) { - modelInfo.model.off(modelInfo.onDestroyed); - delete this._modelInfos[model.id]; - this._kdTreeDirty = true; - } + getObject(array, index) { + if (typeof index === 'object') { + return index; } - _doCull() { - const cullDirty = (this._frustumDirty || this._kdTreeDirty); - if (this._frustumDirty) { - this._buildFrustum(); - } - if (this._kdTreeDirty) { - this._buildKDTree(); - } - if (cullDirty) { - const kdNode = this._kdRoot; - if (kdNode) { - this._visitKDNode(kdNode); - } - } - } + const object = this.json[array] && this.json[array][index]; - _buildFrustum() { - const camera = this.viewer.scene.camera; - setFrustum(this._frustum, camera.viewMatrix, camera.projMatrix); - this._frustumDirty = false; + if (!object) { + throw new Error("glTF file error: Could not find ".concat(array, "[").concat(index, "]")); } - _buildKDTree() { - const viewer = this.viewer; - const scene = viewer.scene; - const depth = 0; - if (this._kdRoot) ; - this._kdRoot = { - aabb: scene.getAABB(), - intersection: Frustum.INTERSECT - }; - for (let objectIdx = 0, len = this._objectCullStates.numObjects; objectIdx < len; objectIdx++) { - const entity = this._objectCullStates.objects[objectIdx]; - this._insertEntityIntoKDTree(this._kdRoot, entity, objectIdx, depth + 1); - } - this._kdTreeDirty = false; - } + return object; + } - _insertEntityIntoKDTree(kdNode, entity, objectIdx, depth) { + getTypedArrayForBufferView(bufferView) { + bufferView = this.getBufferView(bufferView); + const bufferIndex = bufferView.buffer; + const binChunk = this.gltf.buffers[bufferIndex]; + assert$1(binChunk); + const byteOffset = (bufferView.byteOffset || 0) + binChunk.byteOffset; + return new Uint8Array(binChunk.arrayBuffer, byteOffset, bufferView.byteLength); + } - const entityAABB = entity.aabb; + getTypedArrayForAccessor(accessor) { + accessor = this.getAccessor(accessor); + const bufferView = this.getBufferView(accessor.bufferView); + const buffer = this.getBuffer(bufferView.buffer); + const arrayBuffer = buffer.data; + const { + ArrayType, + length + } = getAccessorArrayTypeAndLength(accessor, bufferView); + const byteOffset = bufferView.byteOffset + accessor.byteOffset; + return new ArrayType(arrayBuffer, byteOffset, length); + } - if (depth >= this._maxTreeDepth) { - kdNode.objects = kdNode.objects || []; - kdNode.objects.push(objectIdx); - math.expandAABB3(kdNode.aabb, entityAABB); - return; - } + getTypedArrayForImageData(image) { + image = this.getAccessor(image); + const bufferView = this.getBufferView(image.bufferView); + const buffer = this.getBuffer(bufferView.buffer); + const arrayBuffer = buffer.data; + const byteOffset = bufferView.byteOffset || 0; + return new Uint8Array(arrayBuffer, byteOffset, bufferView.byteLength); + } - if (kdNode.left) { - if (math.containsAABB3(kdNode.left.aabb, entityAABB)) { - this._insertEntityIntoKDTree(kdNode.left, entity, objectIdx, depth + 1); - return; - } - } + addApplicationData(key, data) { + this.json[key] = data; + return this; + } - if (kdNode.right) { - if (math.containsAABB3(kdNode.right.aabb, entityAABB)) { - this._insertEntityIntoKDTree(kdNode.right, entity, objectIdx, depth + 1); - return; - } - } + addExtraData(key, data) { + this.json.extras = this.json.extras || {}; + this.json.extras[key] = data; + return this; + } - const nodeAABB = kdNode.aabb; + addObjectExtension(object, extensionName, data) { + object.extensions = object.extensions || {}; + object.extensions[extensionName] = data; + this.registerUsedExtension(extensionName); + return this; + } - kdTreeDimLength[0] = nodeAABB[3] - nodeAABB[0]; - kdTreeDimLength[1] = nodeAABB[4] - nodeAABB[1]; - kdTreeDimLength[2] = nodeAABB[5] - nodeAABB[2]; + setObjectExtension(object, extensionName, data) { + const extensions = object.extensions || {}; + extensions[extensionName] = data; + } - let dim = 0; + removeObjectExtension(object, extensionName) { + const extensions = object.extensions || {}; + const extension = extensions[extensionName]; + delete extensions[extensionName]; + return extension; + } - if (kdTreeDimLength[1] > kdTreeDimLength[dim]) { - dim = 1; - } + addExtension(extensionName, extensionData = {}) { + assert$1(extensionData); + this.json.extensions = this.json.extensions || {}; + this.json.extensions[extensionName] = extensionData; + this.registerUsedExtension(extensionName); + return extensionData; + } - if (kdTreeDimLength[2] > kdTreeDimLength[dim]) { - dim = 2; - } + addRequiredExtension(extensionName, extensionData = {}) { + assert$1(extensionData); + this.addExtension(extensionName, extensionData); + this.registerRequiredExtension(extensionName); + return extensionData; + } - if (!kdNode.left) { - const aabbLeft = nodeAABB.slice(); - aabbLeft[dim + 3] = ((nodeAABB[dim] + nodeAABB[dim + 3]) / 2.0); - kdNode.left = { - aabb: aabbLeft, - intersection: Frustum.INTERSECT - }; - if (math.containsAABB3(aabbLeft, entityAABB)) { - this._insertEntityIntoKDTree(kdNode.left, entity, objectIdx, depth + 1); - return; - } - } + registerUsedExtension(extensionName) { + this.json.extensionsUsed = this.json.extensionsUsed || []; - if (!kdNode.right) { - const aabbRight = nodeAABB.slice(); - aabbRight[dim] = ((nodeAABB[dim] + nodeAABB[dim + 3]) / 2.0); - kdNode.right = { - aabb: aabbRight, - intersection: Frustum.INTERSECT - }; - if (math.containsAABB3(aabbRight, entityAABB)) { - this._insertEntityIntoKDTree(kdNode.right, entity, objectIdx, depth + 1); - return; - } - } + if (!this.json.extensionsUsed.find(ext => ext === extensionName)) { + this.json.extensionsUsed.push(extensionName); + } + } - kdNode.objects = kdNode.objects || []; - kdNode.objects.push(objectIdx); + registerRequiredExtension(extensionName) { + this.registerUsedExtension(extensionName); + this.json.extensionsRequired = this.json.extensionsRequired || []; - math.expandAABB3(kdNode.aabb, entityAABB); + if (!this.json.extensionsRequired.find(ext => ext === extensionName)) { + this.json.extensionsRequired.push(extensionName); } + } - _visitKDNode(kdNode, intersects = Frustum.INTERSECT) { - if (intersects !== Frustum.INTERSECT && kdNode.intersects === intersects) { - return; - } - if (intersects === Frustum.INTERSECT) { - intersects = frustumIntersectsAABB3(this._frustum, kdNode.aabb); - kdNode.intersects = intersects; - } - const culled = (intersects === Frustum.OUTSIDE); - const objects = kdNode.objects; - if (objects && objects.length > 0) { - for (let i = 0, len = objects.length; i < len; i++) { - const objectIdx = objects[i]; - this._objectCullStates.setObjectViewCulled(objectIdx, culled); - } - } - if (kdNode.left) { - this._visitKDNode(kdNode.left, intersects); - } - if (kdNode.right) { - this._visitKDNode(kdNode.right, intersects); - } + removeExtension(extensionName) { + if (this.json.extensionsRequired) { + this._removeStringFromArray(this.json.extensionsRequired, extensionName); } - /** - * @private - */ - send(name, value) { - } - - /** - * Destroys this ViewCullPlugin. - */ - destroy() { - super.destroy(); - this._clear(); - const scene = this.viewer.scene; - const camera = scene.camera; - scene.off(this._onModelLoaded); - scene.off(this._onSceneTick); - camera.off(this._onViewMatrix); - camera.off(this._onProjMatrix); + if (this.json.extensionsUsed) { + this._removeStringFromArray(this.json.extensionsUsed, extensionName); } - _clear() { - for (let modelId in this._modelInfos) { - const modelInfo = this._modelInfos[modelId]; - modelInfo.model.off(modelInfo.onDestroyed); - } - this._modelInfos = {}; - this._kdRoot = null; - this._kdTreeDirty = true; + if (this.json.extensions) { + delete this.json.extensions[extensionName]; } -} + } -/** - * Default data access strategy for {@link XKTLoaderPlugin}. - */ -class XKTDefaultDataSource { + setDefaultScene(sceneIndex) { + this.json.scene = sceneIndex; + } - constructor() { - } + addScene(scene) { + const { + nodeIndices + } = scene; + this.json.scenes = this.json.scenes || []; + this.json.scenes.push({ + nodes: nodeIndices + }); + return this.json.scenes.length - 1; + } - /** - * Gets metamodel JSON. - * - * @param {String|Number} metaModelSrc Identifies the metamodel JSON asset. - * @param {Function} ok Fired on successful loading of the metamodel JSON asset. - * @param {Function} error Fired on error while loading the metamodel JSON asset. - */ - getMetaModel(metaModelSrc, ok, error) { - utils.loadJSON(metaModelSrc, - (json) => { - ok(json); - }, - function (errMsg) { - error(errMsg); - }); - } + addNode(node) { + const { + meshIndex, + matrix + } = node; + this.json.nodes = this.json.nodes || []; + const nodeData = { + mesh: meshIndex + }; - /** - * Gets the contents of the given ````.xkt```` file in an arraybuffer. - * - * @param {String|Number} src Path or ID of an ````.xkt```` file. - * @param {Function} ok Callback fired on success, argument is the ````.xkt```` file in an arraybuffer. - * @param {Function} error Callback fired on error. - */ - getXKT(src, ok, error) { - var defaultCallback = () => { - }; - ok = ok || defaultCallback; - error = error || defaultCallback; - const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; - const dataUriRegexResult = src.match(dataUriRegex); - if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest - const isBase64 = !!dataUriRegexResult[2]; - var data = dataUriRegexResult[3]; - data = window.decodeURIComponent(data); - if (isBase64) { - data = window.atob(data); - } - try { - const buffer = new ArrayBuffer(data.length); - const view = new Uint8Array(buffer); - for (var i = 0; i < data.length; i++) { - view[i] = data.charCodeAt(i); - } - ok(buffer); - } catch (errMsg) { - error(errMsg); - } - } else { - const request = new XMLHttpRequest(); - request.open('GET', src, true); - request.responseType = 'arraybuffer'; - request.onreadystatechange = function () { - if (request.readyState === 4) { - if (request.status === 200) { - ok(request.response); - } else { - error('getXKT error : ' + request.response); - } - } - }; - request.send(null); - } + if (matrix) { + nodeData.matrix = matrix; } -} - -/* pako 1.0.10 nodeca/pako */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f();}else if(typeof define==="function"&&define.amd){define([],f);}else {var g;if(typeof window!=="undefined"){g=window;}else if(typeof global!=="undefined"){g=global;}else if(typeof self!=="undefined"){g=self;}else {g=this;}g.pako = f();}})(function(){return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t);}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i Array - * - * Chunks of output data, if [[Deflate#onData]] not overridden. - **/ + addAccessor(bufferViewIndex, accessor) { + const glTFAccessor = { + bufferView: bufferViewIndex, + type: getAccessorTypeFromSize(accessor.size), + componentType: accessor.componentType, + count: accessor.count, + max: accessor.max, + min: accessor.min + }; + this.json.accessors = this.json.accessors || []; + this.json.accessors.push(glTFAccessor); + return this.json.accessors.length - 1; + } - /** - * Deflate.result -> Uint8Array|Array - * - * Compressed result, generated by default [[Deflate#onData]] - * and [[Deflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Deflate#push]] with `Z_FINISH` / `true` param) or if you - * push a chunk with explicit flush (call [[Deflate#push]] with - * `Z_SYNC_FLUSH` param). - **/ + addBinaryBuffer(sourceBuffer, accessor = { + size: 3 + }) { + const bufferViewIndex = this.addBufferView(sourceBuffer); + let minMax = { + min: accessor.min, + max: accessor.max + }; - /** - * Deflate.err -> Number - * - * Error code after deflate finished. 0 (Z_OK) on success. - * You will not need it in real life, because deflate errors - * are possible only on wrong options or bad `onData` / `onEnd` - * custom handlers. - **/ + if (!minMax.min || !minMax.max) { + minMax = this._getAccessorMinMax(sourceBuffer, accessor.size); + } - /** - * Deflate.msg -> String - * - * Error message, if [[Deflate.err]] != 0 - **/ + const accessorDefaults = { + size: accessor.size, + componentType: getComponentTypeFromArray(sourceBuffer), + count: Math.round(sourceBuffer.length / accessor.size), + min: minMax.min, + max: minMax.max + }; + return this.addAccessor(bufferViewIndex, Object.assign(accessorDefaults, accessor)); + } + addTexture(texture) { + const { + imageIndex + } = texture; + const glTFTexture = { + source: imageIndex + }; + this.json.textures = this.json.textures || []; + this.json.textures.push(glTFTexture); + return this.json.textures.length - 1; + } - /** - * new Deflate(options) - * - options (Object): zlib deflate options. - * - * Creates new deflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `level` - * - `windowBits` - * - `memLevel` - * - `strategy` - * - `dictionary` - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Additional options, for internal needs: - * - * - `chunkSize` - size of generated data chunks (16K by default) - * - `raw` (Boolean) - do raw deflate - * - `gzip` (Boolean) - create gzip wrapper - * - `to` (String) - if equal to 'string', then result will be "binary string" - * (each char code [0..255]) - * - `header` (Object) - custom header for gzip - * - `text` (Boolean) - true if compressed data believed to be text - * - `time` (Number) - modification time, unix timestamp - * - `os` (Number) - operation system code - * - `extra` (Array) - array of bytes with extra data (max 65536) - * - `name` (String) - file name (binary string) - * - `comment` (String) - comment (binary string) - * - `hcrc` (Boolean) - true if header crc should be added - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) - * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); - * - * var deflate = new pako.Deflate({ level: 3}); - * - * deflate.push(chunk1, false); - * deflate.push(chunk2, true); // true -> last chunk - * - * if (deflate.err) { throw new Error(deflate.err); } - * - * console.log(deflate.result); - * ``` - **/ - function Deflate(options) { - if (!(this instanceof Deflate)) return new Deflate(options); - - this.options = utils.assign({ - level: Z_DEFAULT_COMPRESSION, - method: Z_DEFLATED, - chunkSize: 16384, - windowBits: 15, - memLevel: 8, - strategy: Z_DEFAULT_STRATEGY, - to: '' - }, options || {}); - - var opt = this.options; - - if (opt.raw && (opt.windowBits > 0)) { - opt.windowBits = -opt.windowBits; - } - - else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { - opt.windowBits += 16; - } - - this.err = 0; // error code, if happens (0 = Z_OK) - this.msg = ''; // error message - this.ended = false; // used to avoid multiple onEnd() calls - this.chunks = []; // chunks of compressed data - - this.strm = new ZStream(); - this.strm.avail_out = 0; - - var status = zlib_deflate.deflateInit2( - this.strm, - opt.level, - opt.method, - opt.windowBits, - opt.memLevel, - opt.strategy - ); + addMaterial(pbrMaterialInfo) { + this.json.materials = this.json.materials || []; + this.json.materials.push(pbrMaterialInfo); + return this.json.materials.length - 1; + } - if (status !== Z_OK) { - throw new Error(msg[status]); - } + createBinaryChunk() { + var _this$json, _this$json$buffers; - if (opt.header) { - zlib_deflate.deflateSetHeader(this.strm, opt.header); - } + this.gltf.buffers = []; + const totalByteLength = this.byteLength; + const arrayBuffer = new ArrayBuffer(totalByteLength); + const targetArray = new Uint8Array(arrayBuffer); + let dstByteOffset = 0; - if (opt.dictionary) { - var dict; - // Convert data if needed - if (typeof opt.dictionary === 'string') { - // If we need to compress text, change encoding to utf8. - dict = strings.string2buf(opt.dictionary); - } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { - dict = new Uint8Array(opt.dictionary); - } else { - dict = opt.dictionary; - } + for (const sourceBuffer of this.sourceBuffers || []) { + dstByteOffset = copyToArray(sourceBuffer, targetArray, dstByteOffset); + } - status = zlib_deflate.deflateSetDictionary(this.strm, dict); + if ((_this$json = this.json) !== null && _this$json !== void 0 && (_this$json$buffers = _this$json.buffers) !== null && _this$json$buffers !== void 0 && _this$json$buffers[0]) { + this.json.buffers[0].byteLength = totalByteLength; + } else { + this.json.buffers = [{ + byteLength: totalByteLength + }]; + } - if (status !== Z_OK) { - throw new Error(msg[status]); - } + this.gltf.binary = arrayBuffer; + this.sourceBuffers = [arrayBuffer]; + } - this._dict_set = true; - } - } + _removeStringFromArray(array, string) { + let found = true; - /** - * Deflate#push(data[, mode]) -> Boolean - * - data (Uint8Array|Array|ArrayBuffer|String): input data. Strings will be - * converted to utf8 byte sequence. - * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. - * - * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with - * new compressed chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That will flush internal pending buffers and call - * [[Deflate#onEnd]]. For interim explicit flushes (without ending the stream) you - * can use mode Z_SYNC_FLUSH, keeping the compression context. - * - * On fail call [[Deflate#onEnd]] with error code and return false. - * - * We strongly recommend to use `Uint8Array` on input for best speed (output - * array format is detected automatically). Also, don't skip last param and always - * use the same type in your code (boolean or number). That will improve JS speed. - * - * For regular `Array`-s make sure all elements are [0..255]. - * - * ##### Example - * - * ```javascript - * push(chunk, false); // push one of data chunks - * ... - * push(chunk, true); // push last chunk - * ``` - **/ - Deflate.prototype.push = function (data, mode) { - var strm = this.strm; - var chunkSize = this.options.chunkSize; - var status, _mode; + while (found) { + const index = array.indexOf(string); - if (this.ended) { return false; } + if (index > -1) { + array.splice(index, 1); + } else { + found = false; + } + } + } - _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH); + _addAttributes(attributes = {}) { + const result = {}; - // Convert data if needed - if (typeof data === 'string') { - // If we need to compress text, change encoding to utf8. - strm.input = strings.string2buf(data); - } else if (toString.call(data) === '[object ArrayBuffer]') { - strm.input = new Uint8Array(data); - } else { - strm.input = data; - } + for (const attributeKey in attributes) { + const attributeData = attributes[attributeKey]; - strm.next_in = 0; - strm.avail_in = strm.input.length; + const attrName = this._getGltfAttributeName(attributeKey); - do { - if (strm.avail_out === 0) { - strm.output = new utils.Buf8(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } - status = zlib_deflate.deflate(strm, _mode); /* no bad return value */ + const accessor = this.addBinaryBuffer(attributeData.value, attributeData); + result[attrName] = accessor; + } - if (status !== Z_STREAM_END && status !== Z_OK) { - this.onEnd(status); - this.ended = true; - return false; - } - if (strm.avail_out === 0 || (strm.avail_in === 0 && (_mode === Z_FINISH || _mode === Z_SYNC_FLUSH))) { - if (this.options.to === 'string') { - this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out))); - } else { - this.onData(utils.shrinkBuf(strm.output, strm.next_out)); - } - } - } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END); + return result; + } - // Finalize on the last chunk. - if (_mode === Z_FINISH) { - status = zlib_deflate.deflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === Z_OK; - } + _addIndices(indices) { + return this.addBinaryBuffer(indices, { + size: 1 + }); + } - // callback interim results if Z_SYNC_FLUSH. - if (_mode === Z_SYNC_FLUSH) { - this.onEnd(Z_OK); - strm.avail_out = 0; - return true; - } + _getGltfAttributeName(attributeName) { + switch (attributeName.toLowerCase()) { + case 'position': + case 'positions': + case 'vertices': + return 'POSITION'; - return true; - }; + case 'normal': + case 'normals': + return 'NORMAL'; + case 'color': + case 'colors': + return 'COLOR_0'; - /** - * Deflate#onData(chunk) -> Void - * - chunk (Uint8Array|Array|String): output data. Type of array depends - * on js engine support. When string output requested, each chunk - * will be string. - * - * By default, stores data blocks in `chunks[]` property and glue - * those in `onEnd`. Override this handler, if you need another behaviour. - **/ - Deflate.prototype.onData = function (chunk) { - this.chunks.push(chunk); - }; + case 'texcoord': + case 'texcoords': + return 'TEXCOORD_0'; + default: + return attributeName; + } + } - /** - * Deflate#onEnd(status) -> Void - * - status (Number): deflate status. 0 (Z_OK) on success, - * other if not. - * - * Called once after you tell deflate that the input stream is - * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) - * or if an error happened. By default - join collected chunks, - * free memory and fill `results` / `err` properties. - **/ - Deflate.prototype.onEnd = function (status) { - // On success - join - if (status === Z_OK) { - if (this.options.to === 'string') { - this.result = this.chunks.join(''); - } else { - this.result = utils.flattenChunks(this.chunks); - } - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; - }; + _getAccessorMinMax(buffer, size) { + const result = { + min: null, + max: null + }; + if (buffer.length < size) { + return result; + } - /** - * deflate(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * Compress `data` with deflate algorithm and `options`. - * - * Supported options are: - * - * - level - * - windowBits - * - memLevel - * - strategy - * - dictionary - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Sugar (options): - * - * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify - * negative windowBits implicitly. - * - `to` (String) - if equal to 'string', then result will be "binary string" - * (each char code [0..255]) - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , data = Uint8Array([1,2,3,4,5,6,7,8,9]); - * - * console.log(pako.deflate(data)); - * ``` - **/ - function deflate(input, options) { - var deflator = new Deflate(options); + result.min = []; + result.max = []; + const initValues = buffer.subarray(0, size); - deflator.push(input, true); + for (const value of initValues) { + result.min.push(value); + result.max.push(value); + } - // That will never happens, if you don't cheat with options :) - if (deflator.err) { throw deflator.msg || msg[deflator.err]; } + for (let index = size; index < buffer.length; index += size) { + for (let componentIndex = 0; componentIndex < size; componentIndex++) { + result.min[0 + componentIndex] = Math.min(result.min[0 + componentIndex], buffer[index + componentIndex]); + result.max[0 + componentIndex] = Math.max(result.max[0 + componentIndex], buffer[index + componentIndex]); + } + } - return deflator.result; - } + return result; + } +} - /** - * deflateRaw(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * The same as [[deflate]], but creates raw data, without wrapper - * (header and adler32 crc). - **/ - function deflateRaw(input, options) { - options = options || {}; - options.raw = true; - return deflate(input, options); - } +const wasm_base = 'B9h9z9tFBBBF8fL9gBB9gLaaaaaFa9gEaaaB9gFaFa9gEaaaFaEMcBFFFGGGEIIILF9wFFFLEFBFKNFaFCx/IFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBF8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBGy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBEn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBIi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBKI9z9iqlBOc+x8ycGBM/qQFTa8jUUUUBCU/EBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAGTkUUUBRNCUoBAG9uC/wgBZHKCUGAKCUG9JyRVAECFJRICBRcGXEXAcAF9PQFAVAFAclAcAVJAF9JyRMGXGXAG9FQBAMCbJHKC9wZRSAKCIrCEJCGrRQANCUGJRfCBRbAIRTEXGXAOATlAQ9PQBCBRISEMATAQJRIGXAS9FQBCBRtCBREEXGXAOAIlCi9PQBCBRISLMANCU/CBJAEJRKGXGXGXGXGXATAECKrJ2BBAtCKZrCEZfIBFGEBMAKhB83EBAKCNJhB83EBSEMAKAI2BIAI2BBHmCKrHYAYCE6HYy86BBAKCFJAICIJAYJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCGJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCEJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCIJAYAmJHY2BBAI2BFHmCKrHPAPCE6HPy86BBAKCLJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCKJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCOJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCNJAYAmJHY2BBAI2BGHmCKrHPAPCE6HPy86BBAKCVJAYAPJHY2BBAmCIrCEZHPAPCE6HPy86BBAKCcJAYAPJHY2BBAmCGrCEZHPAPCE6HPy86BBAKCMJAYAPJHY2BBAmCEZHmAmCE6Hmy86BBAKCSJAYAmJHm2BBAI2BEHICKrHYAYCE6HYy86BBAKCQJAmAYJHm2BBAICIrCEZHYAYCE6HYy86BBAKCfJAmAYJHm2BBAICGrCEZHYAYCE6HYy86BBAKCbJAmAYJHK2BBAICEZHIAICE6HIy86BBAKAIJRISGMAKAI2BNAI2BBHmCIrHYAYCb6HYy86BBAKCFJAICNJAYJHY2BBAmCbZHmAmCb6Hmy86BBAKCGJAYAmJHm2BBAI2BFHYCIrHPAPCb6HPy86BBAKCEJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCIJAmAYJHm2BBAI2BGHYCIrHPAPCb6HPy86BBAKCLJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCKJAmAYJHm2BBAI2BEHYCIrHPAPCb6HPy86BBAKCOJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCNJAmAYJHm2BBAI2BIHYCIrHPAPCb6HPy86BBAKCVJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCcJAmAYJHm2BBAI2BLHYCIrHPAPCb6HPy86BBAKCMJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCSJAmAYJHm2BBAI2BKHYCIrHPAPCb6HPy86BBAKCQJAmAPJHm2BBAYCbZHYAYCb6HYy86BBAKCfJAmAYJHm2BBAI2BOHICIrHYAYCb6HYy86BBAKCbJAmAYJHK2BBAICbZHIAICb6HIy86BBAKAIJRISFMAKAI8pBB83BBAKCNJAICNJ8pBB83BBAICTJRIMAtCGJRtAECTJHEAS9JQBMMGXAIQBCBRISEMGXAM9FQBANAbJ2BBRtCBRKAfREEXAEANCU/CBJAKJ2BBHTCFrCBATCFZl9zAtJHt86BBAEAGJREAKCFJHKAM9HQBMMAfCFJRfAIRTAbCFJHbAG9HQBMMABAcAG9sJANCUGJAMAG9sTkUUUBpANANCUGJAMCaJAG9sJAGTkUUUBpMAMCBAIyAcJRcAIQBMC9+RKSFMCBC99AOAIlAGCAAGCA9Ly6yRKMALCU/EBJ8kUUUUBAKM+OmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUFT+JUUUBpALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM+lLKFaF99GaG99FaG99GXGXAGCI9HQBAF9FQFEXGXGX9DBBB8/9DBBB+/ABCGJHG1BB+yAB1BBHE+yHI+L+TABCFJHL1BBHK+yHO+L+THN9DBBBB9gHVyAN9DBB/+hANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE86BBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG86BBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG86BBABCIJRBAFCaJHFQBSGMMAF9FQBEXGXGX9DBBB8/9DBBB+/ABCIJHG8uFB+yAB8uFBHE+yHI+L+TABCGJHL8uFBHK+yHO+L+THN9DBBBB9gHVyAN9DB/+g6ANAN+U9DBBBBANAVyHcAc+MHMAECa3yAI+SHIAI+UAcAMAKCa3yAO+SHcAc+U+S+S+R+VHO+U+SHN+L9DBBB9P9d9FQBAN+oRESFMCUUUU94REMAGAE87FBGXGX9DBBB8/9DBBB+/Ac9DBBBB9gyAcAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMALAG87FBGXGX9DBBB8/9DBBB+/AI9DBBBB9gyAIAO+U+SHN+L9DBBB9P9d9FQBAN+oRGSFMCUUUU94RGMABAG87FBABCNJRBAFCaJHFQBMMM/SEIEaE99EaF99GXAF9FQBCBREABRIEXGXGX9D/zI818/AICKJ8uFBHLCEq+y+VHKAI8uFB+y+UHO9DB/+g6+U9DBBB8/9DBBB+/AO9DBBBB9gy+SHN+L9DBBB9P9d9FQBAN+oRVSFMCUUUU94RVMAICIJ8uFBRcAICGJ8uFBRMABALCFJCEZAEqCFWJAV87FBGXGXAKAM+y+UHN9DB/+g6+U9DBBB8/9DBBB+/AN9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRMSFMCUUUU94RMMABALCGJCEZAEqCFWJAM87FBGXGXAKAc+y+UHK9DB/+g6+U9DBBB8/9DBBB+/AK9DBBBB9gy+SHS+L9DBBB9P9d9FQBAS+oRcSFMCUUUU94RcMABALCaJCEZAEqCFWJAc87FBGXGX9DBBU8/AOAO+U+TANAN+U+TAKAK+U+THO9DBBBBAO9DBBBB9gy+R9DB/+g6+U9DBBB8/+SHO+L9DBBB9P9d9FQBAO+oRcSFMCUUUU94RcMABALCEZAEqCFWJAc87FBAICNJRIAECIJREAFCaJHFQBMMM9JBGXAGCGrAF9sHF9FQBEXABAB8oGBHGCNWCN91+yAGCi91CnWCUUU/8EJ+++U84GBABCIJRBAFCaJHFQBMMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEM/lFFFaGXGXAFABqCEZ9FQBABRESFMGXGXAGCT9PQBABRESFMABREEXAEAF8oGBjGBAECIJAFCIJ8oGBjGBAECNJAFCNJ8oGBjGBAECSJAFCSJ8oGBjGBAECTJREAFCTJRFAGC9wJHGCb9LQBMMAGCI9JQBEXAEAF8oGBjGBAFCIJRFAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF2BB86BBAECFJREAFCFJRFAGCaJHGQBMMABMoFFGaGXGXABCEZ9FQBABRESFMAFCgFZC+BwsN9sRIGXGXAGCT9PQBABRESFMABREEXAEAIjGBAECSJAIjGBAECNJAIjGBAECIJAIjGBAECTJREAGC9wJHGCb9LQBMMAGCI9JQBEXAEAIjGBAECIJREAGC98JHGCE9LQBMMGXAG9FQBEXAEAF86BBAECFJREAGCaJHGQBMMABMMMFBCUNMIT9kBB'; +const wasm_simd = 'B9h9z9tFBBBF8dL9gBB9gLaaaaaFa9gEaaaB9gGaaB9gFaFaEQSBBFBFFGEGEGIILF9wFFFLEFBFKNFaFCx/aFMO/LFVK9tv9t9vq95GBt9f9f939h9z9t9f9j9h9s9s9f9jW9vq9zBBp9tv9z9o9v9wW9f9kv9j9v9kv9WvqWv94h919m9mvqBG8Z9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv94h919m9mvqBIy9tv9z9o9v9wW9f9kv9j9v9kv9J9u9kv949TvZ91v9u9jvBLn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9P9jWBKi9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9R919hWBNn9tv9z9o9v9wW9f9kv9j9v9kv69p9sWvq9F949wBcI9z9iqlBMc/j9JSIBTEM9+FLa8jUUUUBCTlRBCBRFEXCBRGCBREEXABCNJAGJAECUaAFAGrCFZHIy86BBAEAIJREAGCFJHGCN9HQBMAFCx+YUUBJAE86BBAFCEWCxkUUBJAB8pEN83EBAFCFJHFCUG9HQBMMkRIbaG97FaK978jUUUUBCU/KBlHL8kUUUUBC9+RKGXAGCFJAI9LQBCaRKAE2BBC+gF9HQBALAEAIJHOAGlAG/8cBBCUoBAG9uC/wgBZHKCUGAKCUG9JyRNAECFJRKCBRVGXEXAVAF9PQFANAFAVlAVANJAF9JyRcGXGXAG9FQBAcCbJHIC9wZHMCE9sRSAMCFWRQAICIrCEJCGrRfCBRbEXAKRTCBRtGXEXGXAOATlAf9PQBCBRKSLMALCU/CBJAtAM9sJRmATAfJRKCBREGXAMCoB9JQBAOAKlC/gB9JQBCBRIEXAmAIJREGXGXGXGXGXATAICKrJ2BBHYCEZfIBFGEBMAECBDtDMIBSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAEAKDBBBDMIBAKCTJRKMGXGXGXGXGXAYCGrCEZfIBFGEBMAECBDtDMITSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMITAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAEAKDBBBDMITAKCTJRKMGXGXGXGXGXAYCIrCEZfIBFGEBMAECBDtDMIASEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIAAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAEAKDBBBDMIAAKCTJRKMGXGXGXGXGXAYCKrfIBFGEBMAECBDtDMI8wSEMAEAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCIJAnDeBJAYCx+YUUBJ2BBJRKSGMAEAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBAYCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HYCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMI8wAKCNJAnDeBJAYCx+YUUBJ2BBJRKSFMAEAKDBBBDMI8wAKCTJRKMAICoBJREAICUFJAM9LQFAERIAOAKlC/fB9LQBMMGXAEAM9PQBAECErRIEXGXAOAKlCi9PQBCBRKSOMAmAEJRYGXGXGXGXGXATAECKrJ2BBAICKZrCEZfIBFGEBMAYCBDtDMIBSEMAYAKDBBIAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnHPCGD+MFAPDQBTFtGmEYIPLdKeOnC0+G+MiDtD9OHdCEDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCIJAnDeBJAeCx+YUUBJ2BBJRKSGMAYAKDBBNAKDBBBHPCID+MFAPDQBTFtGmEYIPLdKeOnC+P+e+8/4BDtD9OHdCbDbD8jHPD8dBhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBAeCx+YUUBJDBBBHnAnDQBBBBBBBBBBBBBBBBAPD8dFhUg/8/4/w/goB9+h84k7HeCEWCxkUUBJDBEBD9uDQBFGEILKOTtmYPdenDfAdAPD9SDMIBAKCNJAnDeBJAeCx+YUUBJ2BBJRKSFMAYAKDBBBDMIBAKCTJRKMAICGJRIAECTJHEAM9JQBMMGXAK9FQBAKRTAtCFJHtCI6QGSFMMCBRKSEMGXAM9FQBALCUGJAbJREALAbJDBGBRnCBRYEXAEALCU/CBJAYJHIDBIBHdCFD9tAdCFDbHPD9OD9hD9RHdAIAMJDBIBHiCFD9tAiAPD9OD9hD9RHiDQBTFtGmEYIPLdKeOnH8ZAIAQJDBIBHpCFD9tApAPD9OD9hD9RHpAIASJDBIBHyCFD9tAyAPD9OD9hD9RHyDQBTFtGmEYIPLdKeOnH8cDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGEAnD9uHnDyBjGBAEAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJHIAnA8ZA8cDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHnDyBjGBAIAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJHIAnAdAiDQNiV8ZcpMyS8cQ8df8eb8fHdApAyDQNiV8ZcpMyS8cQ8df8eb8fHiDQBFTtGEmYILPdKOenHPAPDQBFGEBFGEBFGEBFGED9uHnDyBjGBAIAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJHIAnAdAiDQNVi8ZcMpySQ8c8dfb8e8fHPAPDQBFGEBFGEBFGEBFGED9uHnDyBjGBAIAGJHIAnAPAPDQILKOILKOILKOILKOD9uHnDyBjGBAIAGJHIAnAPAPDQNVcMNVcMNVcMNVcMD9uHnDyBjGBAIAGJHIAnAPAPDQSQfbSQfbSQfbSQfbD9uHnDyBjGBAIAGJREAYCTJHYAM9JQBMMAbCIJHbAG9JQBMMABAVAG9sJALCUGJAcAG9s/8cBBALALCUGJAcCaJAG9sJAG/8cBBMAcCBAKyAVJRVAKQBMC9+RKSFMCBC99AOAKlAGCAAGCA9Ly6yRKMALCU/KBJ8kUUUUBAKMNBT+BUUUBM+KmFTa8jUUUUBCoFlHL8kUUUUBC9+RKGXAFCE9uHOCtJAI9LQBCaRKAE2BBHNC/wFZC/gF9HQBANCbZHVCF9LQBALCoBJCgFCUF/8MBALC84Jha83EBALC8wJha83EBALC8oJha83EBALCAJha83EBALCiJha83EBALCTJha83EBALha83ENALha83EBAEAIJC9wJRcAECFJHNAOJRMGXAF9FQBCQCbAVCF6yRSABRECBRVCBRQCBRfCBRICBRKEXGXAMAcuQBC9+RKSEMGXGXAN2BBHOC/vF9LQBALCoBJAOCIrCa9zAKJCbZCEWJHb8oGIRTAb8oGBRtGXAOCbZHbAS9PQBALAOCa9zAIJCbZCGWJ8oGBAVAbyROAb9FRbGXGXAGCG9HQBABAt87FBABCIJAO87FBABCGJAT87FBSFMAEAtjGBAECNJAOjGBAECIJATjGBMAVAbJRVALCoBJAKCEWJHmAOjGBAmATjGIALAICGWJAOjGBALCoBJAKCFJCbZHKCEWJHTAtjGBATAOjGIAIAbJRIAKCFJRKSGMGXGXAbCb6QBAQAbJAbC989zJCFJRQSFMAM1BBHbCgFZROGXGXAbCa9MQBAMCFJRMSFMAM1BFHbCgBZCOWAOCgBZqROGXAbCa9MQBAMCGJRMSFMAM1BGHbCgBZCfWAOqROGXAbCa9MQBAMCEJRMSFMAM1BEHbCgBZCdWAOqROGXAbCa9MQBAMCIJRMSFMAM2BIC8cWAOqROAMCLJRMMAOCFrCBAOCFZl9zAQJRQMGXGXAGCG9HQBABAt87FBABCIJAQ87FBABCGJAT87FBSFMAEAtjGBAECNJAQjGBAECIJATjGBMALCoBJAKCEWJHOAQjGBAOATjGIALAICGWJAQjGBALCoBJAKCFJCbZHKCEWJHOAtjGBAOAQjGIAICFJRIAKCFJRKSFMGXAOCDF9LQBALAIAcAOCbZJ2BBHbCIrHTlCbZCGWJ8oGBAVCFJHtATyROALAIAblCbZCGWJ8oGBAtAT9FHmJHtAbCbZHTyRbAT9FRTGXGXAGCG9HQBABAV87FBABCIJAb87FBABCGJAO87FBSFMAEAVjGBAECNJAbjGBAECIJAOjGBMALAICGWJAVjGBALCoBJAKCEWJHYAOjGBAYAVjGIALAICFJHICbZCGWJAOjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAIAmJCbZHICGWJAbjGBALCoBJAKCGJCbZHKCEWJHOAVjGBAOAbjGIAKCFJRKAIATJRIAtATJRVSFMAVCBAM2BBHYyHTAOC/+F6HPJROAYCbZRtGXGXAYCIrHmQBAOCFJRbSFMAORbALAIAmlCbZCGWJ8oGBROMGXGXAtQBAbCFJRVSFMAbRVALAIAYlCbZCGWJ8oGBRbMGXGXAP9FQBAMCFJRYSFMAM1BFHYCgFZRTGXGXAYCa9MQBAMCGJRYSFMAM1BGHYCgBZCOWATCgBZqRTGXAYCa9MQBAMCEJRYSFMAM1BEHYCgBZCfWATqRTGXAYCa9MQBAMCIJRYSFMAM1BIHYCgBZCdWATqRTGXAYCa9MQBAMCLJRYSFMAMCKJRYAM2BLC8cWATqRTMATCFrCBATCFZl9zAQJHQRTMGXGXAmCb6QBAYRPSFMAY1BBHMCgFZROGXGXAMCa9MQBAYCFJRPSFMAY1BFHMCgBZCOWAOCgBZqROGXAMCa9MQBAYCGJRPSFMAY1BGHMCgBZCfWAOqROGXAMCa9MQBAYCEJRPSFMAY1BEHMCgBZCdWAOqROGXAMCa9MQBAYCIJRPSFMAYCLJRPAY2BIC8cWAOqROMAOCFrCBAOCFZl9zAQJHQROMGXGXAtCb6QBAPRMSFMAP1BBHMCgFZRbGXGXAMCa9MQBAPCFJRMSFMAP1BFHMCgBZCOWAbCgBZqRbGXAMCa9MQBAPCGJRMSFMAP1BGHMCgBZCfWAbqRbGXAMCa9MQBAPCEJRMSFMAP1BEHMCgBZCdWAbqRbGXAMCa9MQBAPCIJRMSFMAPCLJRMAP2BIC8cWAbqRbMAbCFrCBAbCFZl9zAQJHQRbMGXGXAGCG9HQBABAT87FBABCIJAb87FBABCGJAO87FBSFMAEATjGBAECNJAbjGBAECIJAOjGBMALCoBJAKCEWJHYAOjGBAYATjGIALAICGWJATjGBALCoBJAKCFJCbZCEWJHYAbjGBAYAOjGIALAICFJHICbZCGWJAOjGBALCoBJAKCGJCbZCEWJHOATjGBAOAbjGIALAIAm9FAmCb6qJHICbZCGWJAbjGBAIAt9FAtCb6qJRIAKCEJRKMANCFJRNABCKJRBAECSJREAKCbZRKAICbZRIAfCEJHfAF9JQBMMCBC99AMAc6yRKMALCoFJ8kUUUUBAKM/tIFGa8jUUUUBCTlRLC9+RKGXAFCLJAI9LQBCaRKAE2BBC/+FZC/QF9HQBALhB83ENAECFJRKAEAIJC98JREGXAF9FQBGXAGCG6QBEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMALCNJAICFZCGWqHGAICGrCBAICFrCFZl9zAG8oGBJHIjGBABAIjGBABCIJRBAFCaJHFQBSGMMEXGXAKAE9JQBC9+bMAK1BBHGCgFZRIGXGXAGCa9MQBAKCFJRKSFMAK1BFHGCgBZCOWAICgBZqRIGXAGCa9MQBAKCGJRKSFMAK1BGHGCgBZCfWAIqRIGXAGCa9MQBAKCEJRKSFMAK1BEHGCgBZCdWAIqRIGXAGCa9MQBAKCIJRKSFMAK2BIC8cWAIqRIAKCLJRKMABAICGrCBAICFrCFZl9zALCNJAICFZCGWqHI8oGBJHG87FBAIAGjGBABCGJRBAFCaJHFQBMMCBC99AKAE6yRKMAKM/xLGEaK978jUUUUBCAlHE8kUUUUBGXGXAGCI9HQBGXAFC98ZHI9FQBABRGCBRLEXAGAGDBBBHKCiD+rFCiD+sFD/6FHOAKCND+rFCiD+sFD/6FAOD/gFAKCTD+rFCiD+sFD/6FHND/gFD/kFD/lFHVCBDtD+2FHcAOCUUUU94DtHMD9OD9RD/kFHO9DBB/+hDYAOAOD/mFAVAVD/mFANAcANAMD9OD9RD/kFHOAOD/mFD/kFD/kFD/jFD/nFHND/mF9DBBX9LDYHcD/kFCgFDtD9OAKCUUU94DtD9OD9QAOAND/mFAcD/kFCND+rFCU/+EDtD9OD9QAVAND/mFAcD/kFCTD+rFCUU/8ODtD9OD9QDMBBAGCTJRGALCIJHLAI9JQBMMAIAF9PQFAEAFCEZHLCGWHGqCBCTAGl/8MBAEABAICGWJHIAG/8cBBGXAL9FQBAEAEDBIBHKCiD+rFCiD+sFD/6FHOAKCND+rFCiD+sFD/6FAOD/gFAKCTD+rFCiD+sFD/6FHND/gFD/kFD/lFHVCBDtD+2FHcAOCUUUU94DtHMD9OD9RD/kFHO9DBB/+hDYAOAOD/mFAVAVD/mFANAcANAMD9OD9RD/kFHOAOD/mFD/kFD/kFD/jFD/nFHND/mF9DBBX9LDYHcD/kFCgFDtD9OAKCUUU94DtD9OD9QAOAND/mFAcD/kFCND+rFCU/+EDtD9OD9QAVAND/mFAcD/kFCTD+rFCUU/8ODtD9OD9QDMIBMAIAEAG/8cBBSFMABAFC98ZHGT+HUUUBAGAF9PQBAEAFCEZHICEWHLJCBCAALl/8MBAEABAGCEWJHGAL/8cBBAEAIT+HUUUBAGAEAL/8cBBMAECAJ8kUUUUBM+yEGGaO97GXAF9FQBCBRGEXABCTJHEAEDBBBHICBDtHLCUU98D8cFCUU98D8cEHKD9OABDBBBHOAIDQILKOSQfbPden8c8d8e8fCggFDtD9OD/6FAOAIDQBFGENVcMTtmYi8ZpyHICTD+sFD/6FHND/gFAICTD+rFCTD+sFD/6FHVD/gFD/kFD/lFHI9DB/+g6DYAVAIALD+2FHLAVCUUUU94DtHcD9OD9RD/kFHVAVD/mFAIAID/mFANALANAcD9OD9RD/kFHIAID/mFD/kFD/kFD/jFD/nFHND/mF9DBBX9LDYHLD/kFCTD+rFAVAND/mFALD/kFCggEDtD9OD9QHVAIAND/mFALD/kFCaDbCBDnGCBDnECBDnKCBDnOCBDncCBDnMCBDnfCBDnbD9OHIDQNVi8ZcMpySQ8c8dfb8e8fD9QDMBBABAOAKD9OAVAIDQBFTtGEmYILPdKOenD9QDMBBABCAJRBAGCIJHGAF9JQBMMM94FEa8jUUUUBCAlHE8kUUUUBABAFC98ZHIT+JUUUBGXAIAF9PQBAEAFCEZHLCEWHFJCBCAAFl/8MBAEABAICEWJHBAF/8cBBAEALT+JUUUBABAEAF/8cBBMAECAJ8kUUUUBM/hEIGaF97FaL978jUUUUBCTlRGGXAF9FQBCBREEXAGABDBBBHIABCTJHLDBBBHKDQILKOSQfbPden8c8d8e8fHOCTD+sFHNCID+rFDMIBAB9DBBU8/DY9D/zI818/DYANCEDtD9QD/6FD/nFHNAIAKDQBFGENVcMTtmYi8ZpyHICTD+rFCTD+sFD/6FD/mFHKAKD/mFANAICTD+sFD/6FD/mFHVAVD/mFANAOCTD+rFCTD+sFD/6FD/mFHOAOD/mFD/kFD/kFD/lFCBDtD+4FD/jF9DB/+g6DYHND/mF9DBBX9LDYHID/kFCggEDtHcD9OAVAND/mFAID/kFCTD+rFD9QHVAOAND/mFAID/kFCTD+rFAKAND/mFAID/kFAcD9OD9QHNDQBFTtGEmYILPdKOenHID8dBAGDBIBDyB+t+J83EBABCNJAID8dFAGDBIBDyF+t+J83EBALAVANDQNVi8ZcMpySQ8c8dfb8e8fHND8dBAGDBIBDyG+t+J83EBABCiJAND8dFAGDBIBDyE+t+J83EBABCAJRBAECIJHEAF9JQBMMM/3FGEaF978jUUUUBCoBlREGXAGCGrAF9sHIC98ZHL9FQBCBRGABRFEXAFAFDBBBHKCND+rFCND+sFD/6FAKCiD+sFCnD+rFCUUU/8EDtD+uFD/mFDMBBAFCTJRFAGCIJHGAL9JQBMMGXALAI9PQBAEAICEZHGCGWHFqCBCoBAFl/8MBAEABALCGWJHLAF/8cBBGXAG9FQBAEAEDBIBHKCND+rFCND+sFD/6FAKCiD+sFCnD+rFCUUU/8EDtD+uFD/mFDMIBMALAEAF/8cBBMM9TFEaCBCB8oGUkUUBHFABCEJC98ZJHBjGUkUUBGXGXAB8/BCTWHGuQBCaREABAGlCggEJCTrXBCa6QFMAFREMAEMMMFBCUNMIT9tBB'; +const detector = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 3, 2, 0, 0, 5, 3, 1, 0, 1, 12, 1, 0, 10, 22, 2, 12, 0, 65, 0, 65, 0, 65, 0, 252, 10, 0, 0, 11, 7, 0, 65, 0, 253, 15, 26, 11]); +const wasmpack = new Uint8Array([32, 0, 65, 253, 3, 1, 2, 34, 4, 106, 6, 5, 11, 8, 7, 20, 13, 33, 12, 16, 128, 9, 116, 64, 19, 113, 127, 15, 10, 21, 22, 14, 255, 66, 24, 54, 136, 107, 18, 23, 192, 26, 114, 118, 132, 17, 77, 101, 130, 144, 27, 87, 131, 44, 45, 74, 156, 154, 70, 167]); +const FILTERS = { + 0: '', + 1: 'meshopt_decodeFilterOct', + 2: 'meshopt_decodeFilterQuat', + 3: 'meshopt_decodeFilterExp', + NONE: '', + OCTAHEDRAL: 'meshopt_decodeFilterOct', + QUATERNION: 'meshopt_decodeFilterQuat', + EXPONENTIAL: 'meshopt_decodeFilterExp' +}; +const DECODERS = { + 0: 'meshopt_decodeVertexBuffer', + 1: 'meshopt_decodeIndexBuffer', + 2: 'meshopt_decodeIndexSequence', + ATTRIBUTES: 'meshopt_decodeVertexBuffer', + TRIANGLES: 'meshopt_decodeIndexBuffer', + INDICES: 'meshopt_decodeIndexSequence' +}; +async function meshoptDecodeGltfBuffer(target, count, size, source, mode, filter = 'NONE') { + const instance = await loadWasmInstance(); + decode$5(instance, instance.exports[DECODERS[mode]], target, count, size, source, instance.exports[FILTERS[filter || 'NONE']]); +} +let wasmPromise; +async function loadWasmInstance() { + if (!wasmPromise) { + wasmPromise = loadWasmModule(); + } - /** - * gzip(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to compress. - * - options (Object): zlib deflate options. - * - * The same as [[deflate]], but create gzip wrapper instead of - * deflate one. - **/ - function gzip(input, options) { - options = options || {}; - options.gzip = true; - return deflate(input, options); - } + return wasmPromise; +} +async function loadWasmModule() { + let wasm = wasm_base; - exports.Deflate = Deflate; - exports.deflate = deflate; - exports.deflateRaw = deflateRaw; - exports.gzip = gzip; + if (WebAssembly.validate(detector)) { + wasm = wasm_simd; + console.log('Warning: meshopt_decoder is using experimental SIMD support'); + } - },{"./utils/common":3,"./utils/strings":4,"./zlib/deflate":8,"./zlib/messages":13,"./zlib/zstream":15}],2:[function(require,module,exports){ + const result = await WebAssembly.instantiate(unpack(wasm), {}); + await result.instance.exports.__wasm_call_ctors(); + return result.instance; +} +function unpack(data) { + const result = new Uint8Array(data.length); - var zlib_inflate = require('./zlib/inflate'); - var utils = require('./utils/common'); - var strings = require('./utils/strings'); - var c = require('./zlib/constants'); - var msg = require('./zlib/messages'); - var ZStream = require('./zlib/zstream'); - var GZheader = require('./zlib/gzheader'); + for (let i = 0; i < data.length; ++i) { + const ch = data.charCodeAt(i); + result[i] = ch > 96 ? ch - 71 : ch > 64 ? ch - 65 : ch > 47 ? ch + 4 : ch > 46 ? 63 : 62; + } - var toString = Object.prototype.toString; + let write = 0; - /** - * class Inflate - * - * Generic JS-style wrapper for zlib calls. If you don't need - * streaming behaviour - use more simple functions: [[inflate]] - * and [[inflateRaw]]. - **/ + for (let i = 0; i < data.length; ++i) { + result[write++] = result[i] < 60 ? wasmpack[result[i]] : (result[i] - 60) * 64 + result[++i]; + } - /* internal - * inflate.chunks -> Array - * - * Chunks of output data, if [[Inflate#onData]] not overridden. - **/ + return result.buffer.slice(0, write); +} - /** - * Inflate.result -> Uint8Array|Array|String - * - * Uncompressed result, generated by default [[Inflate#onData]] - * and [[Inflate#onEnd]] handlers. Filled after you push last chunk - * (call [[Inflate#push]] with `Z_FINISH` / `true` param) or if you - * push a chunk with explicit flush (call [[Inflate#push]] with - * `Z_SYNC_FLUSH` param). - **/ +function decode$5(instance, fun, target, count, size, source, filter) { + const sbrk = instance.exports.sbrk; + const count4 = count + 3 & ~3; + const tp = sbrk(count4 * size); + const sp = sbrk(source.length); + const heap = new Uint8Array(instance.exports.memory.buffer); + heap.set(source, sp); + const res = fun(tp, count, size, sp, source.length); - /** - * Inflate.err -> Number - * - * Error code after inflate finished. 0 (Z_OK) on success. - * Should be checked if broken data possible. - **/ + if (res === 0 && filter) { + filter(tp, count4, size); + } - /** - * Inflate.msg -> String - * - * Error message, if [[Inflate.err]] != 0 - **/ + target.set(heap.subarray(tp, tp + count * size)); + sbrk(tp - sbrk(0)); + if (res !== 0) { + throw new Error("Malformed buffer data: ".concat(res)); + } +} - /** - * new Inflate(options) - * - options (Object): zlib inflate options. - * - * Creates new inflator instance with specified params. Throws exception - * on bad params. Supported options: - * - * - `windowBits` - * - `dictionary` - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information on these. - * - * Additional options, for internal needs: - * - * - `chunkSize` - size of generated data chunks (16K by default) - * - `raw` (Boolean) - do raw inflate - * - `to` (String) - if equal to 'string', then result will be converted - * from utf8 to utf16 (javascript) string. When string output requested, - * chunk length can differ from `chunkSize`, depending on content. - * - * By default, when no options set, autodetect deflate/gzip data format via - * wrapper header. - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9]) - * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]); - * - * var inflate = new pako.Inflate({ level: 3}); - * - * inflate.push(chunk1, false); - * inflate.push(chunk2, true); // true -> last chunk - * - * if (inflate.err) { throw new Error(inflate.err); } - * - * console.log(inflate.result); - * ``` - **/ - function Inflate(options) { - if (!(this instanceof Inflate)) return new Inflate(options); +const EXT_MESHOPT_COMPRESSION = 'EXT_meshopt_compression'; +const name$6 = EXT_MESHOPT_COMPRESSION; +async function decode$4(gltfData, options) { + var _options$gltf; - this.options = utils.assign({ - chunkSize: 16384, - windowBits: 0, - to: '' - }, options || {}); + const scenegraph = new GLTFScenegraph(gltfData); - var opt = this.options; + if (!(options !== null && options !== void 0 && (_options$gltf = options.gltf) !== null && _options$gltf !== void 0 && _options$gltf.decompressMeshes)) { + return; + } - // Force window size for `raw` data, if not set directly, - // because we have no header for autodetect. - if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { - opt.windowBits = -opt.windowBits; - if (opt.windowBits === 0) { opt.windowBits = -15; } - } + const promises = []; - // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate - if ((opt.windowBits >= 0) && (opt.windowBits < 16) && - !(options && options.windowBits)) { - opt.windowBits += 32; - } + for (const bufferViewIndex of gltfData.json.bufferViews || []) { + promises.push(decodeMeshoptBufferView(scenegraph, bufferViewIndex)); + } - // Gzip header has no info about windows size, we can do autodetect only - // for deflate. So, if window size not set, force it to max when gzip possible - if ((opt.windowBits > 15) && (opt.windowBits < 48)) { - // bit 3 (16) -> gzipped data - // bit 4 (32) -> autodetect gzip/deflate - if ((opt.windowBits & 15) === 0) { - opt.windowBits |= 15; - } - } + await Promise.all(promises); + scenegraph.removeExtension(EXT_MESHOPT_COMPRESSION); +} - this.err = 0; // error code, if happens (0 = Z_OK) - this.msg = ''; // error message - this.ended = false; // used to avoid multiple onEnd() calls - this.chunks = []; // chunks of compressed data +async function decodeMeshoptBufferView(scenegraph, bufferView) { + const meshoptExtension = scenegraph.getObjectExtension(bufferView, EXT_MESHOPT_COMPRESSION); - this.strm = new ZStream(); - this.strm.avail_out = 0; + if (meshoptExtension) { + const { + byteOffset = 0, + byteLength = 0, + byteStride, + count, + mode, + filter = 'NONE', + buffer: bufferIndex + } = meshoptExtension; + const buffer = scenegraph.gltf.buffers[bufferIndex]; + const source = new Uint8Array(buffer.arrayBuffer, buffer.byteOffset + byteOffset, byteLength); + const result = new Uint8Array(scenegraph.gltf.buffers[bufferView.buffer].arrayBuffer, bufferView.byteOffset, bufferView.byteLength); + await meshoptDecodeGltfBuffer(result, count, byteStride, source, mode, filter); + return result; + } - var status = zlib_inflate.inflateInit2( - this.strm, - opt.windowBits - ); + return null; +} - if (status !== c.Z_OK) { - throw new Error(msg[status]); - } +var EXT_meshopt_compression = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name$6, + decode: decode$4 +}); - this.header = new GZheader(); +const EXT_TEXTURE_WEBP = 'EXT_texture_webp'; +const name$5 = EXT_TEXTURE_WEBP; +function preprocess$3(gltfData, options) { + const scenegraph = new GLTFScenegraph(gltfData); - zlib_inflate.inflateGetHeader(this.strm, this.header); + if (!_isImageFormatSupported('image/webp')) { + if (scenegraph.getRequiredExtensions().includes(EXT_TEXTURE_WEBP)) { + throw new Error("gltf: Required extension ".concat(EXT_TEXTURE_WEBP, " not supported by browser")); + } - // Setup dictionary - if (opt.dictionary) { - // Convert data if needed - if (typeof opt.dictionary === 'string') { - opt.dictionary = strings.string2buf(opt.dictionary); - } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { - opt.dictionary = new Uint8Array(opt.dictionary); - } - if (opt.raw) { //In raw mode we need to set the dictionary early - status = zlib_inflate.inflateSetDictionary(this.strm, opt.dictionary); - if (status !== c.Z_OK) { - throw new Error(msg[status]); - } - } - } - } + return; + } - /** - * Inflate#push(data[, mode]) -> Boolean - * - data (Uint8Array|Array|ArrayBuffer|String): input data - * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. - * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. - * - * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with - * new output chunks. Returns `true` on success. The last data block must have - * mode Z_FINISH (or `true`). That will flush internal pending buffers and call - * [[Inflate#onEnd]]. For interim explicit flushes (without ending the stream) you - * can use mode Z_SYNC_FLUSH, keeping the decompression context. - * - * On fail call [[Inflate#onEnd]] with error code and return false. - * - * We strongly recommend to use `Uint8Array` on input for best speed (output - * format is detected automatically). Also, don't skip last param and always - * use the same type in your code (boolean or number). That will improve JS speed. - * - * For regular `Array`-s make sure all elements are [0..255]. - * - * ##### Example - * - * ```javascript - * push(chunk, false); // push one of data chunks - * ... - * push(chunk, true); // push last chunk - * ``` - **/ - Inflate.prototype.push = function (data, mode) { - var strm = this.strm; - var chunkSize = this.options.chunkSize; - var dictionary = this.options.dictionary; - var status, _mode; - var next_out_utf8, tail, utf8str; - - // Flag to properly process Z_BUF_ERROR on testing inflate call - // when we check that all output data was flushed. - var allowBufError = false; - - if (this.ended) { return false; } - _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH); + const { + json + } = scenegraph; - // Convert data if needed - if (typeof data === 'string') { - // Only binary strings can be decompressed on practice - strm.input = strings.binstring2buf(data); - } else if (toString.call(data) === '[object ArrayBuffer]') { - strm.input = new Uint8Array(data); - } else { - strm.input = data; - } + for (const texture of json.textures || []) { + const extension = scenegraph.getObjectExtension(texture, EXT_TEXTURE_WEBP); - strm.next_in = 0; - strm.avail_in = strm.input.length; + if (extension) { + texture.source = extension.source; + } - do { - if (strm.avail_out === 0) { - strm.output = new utils.Buf8(chunkSize); - strm.next_out = 0; - strm.avail_out = chunkSize; - } + scenegraph.removeObjectExtension(texture, EXT_TEXTURE_WEBP); + } - status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */ + scenegraph.removeExtension(EXT_TEXTURE_WEBP); +} - if (status === c.Z_NEED_DICT && dictionary) { - status = zlib_inflate.inflateSetDictionary(this.strm, dictionary); - } +var EXT_texture_webp = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name$5, + preprocess: preprocess$3 +}); - if (status === c.Z_BUF_ERROR && allowBufError === true) { - status = c.Z_OK; - allowBufError = false; - } +const KHR_TEXTURE_BASISU = 'KHR_texture_basisu'; +const name$4 = KHR_TEXTURE_BASISU; +function preprocess$2(gltfData, options) { + const scene = new GLTFScenegraph(gltfData); + const { + json + } = scene; - if (status !== c.Z_STREAM_END && status !== c.Z_OK) { - this.onEnd(status); - this.ended = true; - return false; - } + for (const texture of json.textures || []) { + const extension = scene.getObjectExtension(texture, KHR_TEXTURE_BASISU); - if (strm.next_out) { - if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && (_mode === c.Z_FINISH || _mode === c.Z_SYNC_FLUSH))) { + if (extension) { + texture.source = extension.source; + } - if (this.options.to === 'string') { + scene.removeObjectExtension(texture, KHR_TEXTURE_BASISU); + } - next_out_utf8 = strings.utf8border(strm.output, strm.next_out); + scene.removeExtension(KHR_TEXTURE_BASISU); +} - tail = strm.next_out - next_out_utf8; - utf8str = strings.buf2string(strm.output, next_out_utf8); +var KHR_texture_basisu = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name$4, + preprocess: preprocess$2 +}); - // move tail - strm.next_out = tail; - strm.avail_out = chunkSize - tail; - if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); } +const VERSION$1 = "3.2.6" ; - this.onData(utf8str); +const DEFAULT_DRACO_OPTIONS = { + draco: { + decoderType: typeof WebAssembly === 'object' ? 'wasm' : 'js', + libraryPath: 'libs/', + extraAttributes: {}, + attributeNameEntry: undefined + } +}; +const DracoLoader$1 = { + name: 'Draco', + id: 'draco', + module: 'draco', + shapes: ['mesh'], + version: VERSION$1, + worker: true, + extensions: ['drc'], + mimeTypes: ['application/octet-stream'], + binary: true, + tests: ['DRACO'], + options: DEFAULT_DRACO_OPTIONS +}; - } else { - this.onData(utils.shrinkBuf(strm.output, strm.next_out)); - } - } - } +function getMeshBoundingBox(attributes) { + let minX = Infinity; + let minY = Infinity; + let minZ = Infinity; + let maxX = -Infinity; + let maxY = -Infinity; + let maxZ = -Infinity; + const positions = attributes.POSITION ? attributes.POSITION.value : []; + const len = positions && positions.length; - // When no more input data, we should check that internal inflate buffers - // are flushed. The only way to do it when avail_out = 0 - run one more - // inflate pass. But if output data not exists, inflate return Z_BUF_ERROR. - // Here we set flag to process this error properly. - // - // NOTE. Deflate does not return error in this case and does not needs such - // logic. - if (strm.avail_in === 0 && strm.avail_out === 0) { - allowBufError = true; - } + for (let i = 0; i < len; i += 3) { + const x = positions[i]; + const y = positions[i + 1]; + const z = positions[i + 2]; + minX = x < minX ? x : minX; + minY = y < minY ? y : minY; + minZ = z < minZ ? z : minZ; + maxX = x > maxX ? x : maxX; + maxY = y > maxY ? y : maxY; + maxZ = z > maxZ ? z : maxZ; + } - } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== c.Z_STREAM_END); + return [[minX, minY, minZ], [maxX, maxY, maxZ]]; +} - if (status === c.Z_STREAM_END) { - _mode = c.Z_FINISH; - } +function assert(condition, message) { + if (!condition) { + throw new Error(message || 'loader assertion failed.'); + } +} - // Finalize on the last chunk. - if (_mode === c.Z_FINISH) { - status = zlib_inflate.inflateEnd(this.strm); - this.onEnd(status); - this.ended = true; - return status === c.Z_OK; - } +class Schema { + constructor(fields, metadata) { + _defineProperty(this, "fields", void 0); - // callback interim results if Z_SYNC_FLUSH. - if (_mode === c.Z_SYNC_FLUSH) { - this.onEnd(c.Z_OK); - strm.avail_out = 0; - return true; - } + _defineProperty(this, "metadata", void 0); - return true; - }; + assert(Array.isArray(fields)); + checkNames(fields); + this.fields = fields; + this.metadata = metadata || new Map(); + } + compareTo(other) { + if (this.metadata !== other.metadata) { + return false; + } - /** - * Inflate#onData(chunk) -> Void - * - chunk (Uint8Array|Array|String): output data. Type of array depends - * on js engine support. When string output requested, each chunk - * will be string. - * - * By default, stores data blocks in `chunks[]` property and glue - * those in `onEnd`. Override this handler, if you need another behaviour. - **/ - Inflate.prototype.onData = function (chunk) { - this.chunks.push(chunk); - }; + if (this.fields.length !== other.fields.length) { + return false; + } + for (let i = 0; i < this.fields.length; ++i) { + if (!this.fields[i].compareTo(other.fields[i])) { + return false; + } + } - /** - * Inflate#onEnd(status) -> Void - * - status (Number): inflate status. 0 (Z_OK) on success, - * other if not. - * - * Called either after you tell inflate that the input stream is - * complete (Z_FINISH) or should be flushed (Z_SYNC_FLUSH) - * or if an error happened. By default - join collected chunks, - * free memory and fill `results` / `err` properties. - **/ - Inflate.prototype.onEnd = function (status) { - // On success - join - if (status === c.Z_OK) { - if (this.options.to === 'string') { - // Glue & convert here, until we teach pako to send - // utf8 aligned strings to onData - this.result = this.chunks.join(''); - } else { - this.result = utils.flattenChunks(this.chunks); - } - } - this.chunks = []; - this.err = status; - this.msg = this.strm.msg; - }; + return true; + } + select(...columnNames) { + const nameMap = Object.create(null); - /** - * inflate(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * Decompress `data` with inflate/ungzip and `options`. Autodetect - * format via wrapper header by default. That's why we don't provide - * separate `ungzip` method. - * - * Supported options are: - * - * - windowBits - * - * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) - * for more information. - * - * Sugar (options): - * - * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify - * negative windowBits implicitly. - * - `to` (String) - if equal to 'string', then result will be converted - * from utf8 to utf16 (javascript) string. When string output requested, - * chunk length can differ from `chunkSize`, depending on content. - * - * - * ##### Example: - * - * ```javascript - * var pako = require('pako') - * , input = pako.deflate([1,2,3,4,5,6,7,8,9]) - * , output; - * - * try { - * output = pako.inflate(input); - * } catch (err) - * console.log(err); - * } - * ``` - **/ - function inflate(input, options) { - var inflator = new Inflate(options); + for (const name of columnNames) { + nameMap[name] = true; + } - inflator.push(input, true); + const selectedFields = this.fields.filter(field => nameMap[field.name]); + return new Schema(selectedFields, this.metadata); + } - // That will never happens, if you don't cheat with options :) - if (inflator.err) { throw inflator.msg || msg[inflator.err]; } + selectAt(...columnIndices) { + const selectedFields = columnIndices.map(index => this.fields[index]).filter(Boolean); + return new Schema(selectedFields, this.metadata); + } - return inflator.result; - } + assign(schemaOrFields) { + let fields; + let metadata = this.metadata; + if (schemaOrFields instanceof Schema) { + const otherSchema = schemaOrFields; + fields = otherSchema.fields; + metadata = mergeMaps(mergeMaps(new Map(), this.metadata), otherSchema.metadata); + } else { + fields = schemaOrFields; + } - /** - * inflateRaw(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * The same as [[inflate]], but creates raw data, without wrapper - * (header and adler32 crc). - **/ - function inflateRaw(input, options) { - options = options || {}; - options.raw = true; - return inflate(input, options); - } + const fieldMap = Object.create(null); + for (const field of this.fields) { + fieldMap[field.name] = field; + } - /** - * ungzip(data[, options]) -> Uint8Array|Array|String - * - data (Uint8Array|Array|String): input data to decompress. - * - options (Object): zlib inflate options. - * - * Just shortcut to [[inflate]], because it autodetects format - * by header.content. Done for convenience. - **/ + for (const field of fields) { + fieldMap[field.name] = field; + } + const mergedFields = Object.values(fieldMap); + return new Schema(mergedFields, metadata); + } - exports.Inflate = Inflate; - exports.inflate = inflate; - exports.inflateRaw = inflateRaw; - exports.ungzip = inflate; +} - },{"./utils/common":3,"./utils/strings":4,"./zlib/constants":6,"./zlib/gzheader":9,"./zlib/inflate":11,"./zlib/messages":13,"./zlib/zstream":15}],3:[function(require,module,exports){ +function checkNames(fields) { + const usedNames = {}; + for (const field of fields) { + if (usedNames[field.name]) { + console.warn('Schema: duplicated field name', field.name, field); + } - var TYPED_OK = (typeof Uint8Array !== 'undefined') && - (typeof Uint16Array !== 'undefined') && - (typeof Int32Array !== 'undefined'); + usedNames[field.name] = true; + } +} - function _has(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); - } +function mergeMaps(m1, m2) { + return new Map([...(m1 || new Map()), ...(m2 || new Map())]); +} - exports.assign = function (obj /*from1, from2, from3, ...*/) { - var sources = Array.prototype.slice.call(arguments, 1); - while (sources.length) { - var source = sources.shift(); - if (!source) { continue; } +class Field { + constructor(name, type, nullable = false, metadata = new Map()) { + _defineProperty(this, "name", void 0); - if (typeof source !== 'object') { - throw new TypeError(source + 'must be non-object'); - } + _defineProperty(this, "type", void 0); - for (var p in source) { - if (_has(source, p)) { - obj[p] = source[p]; - } - } - } + _defineProperty(this, "nullable", void 0); - return obj; - }; + _defineProperty(this, "metadata", void 0); + this.name = name; + this.type = type; + this.nullable = nullable; + this.metadata = metadata; + } -// reduce buffer size, avoiding mem copy - exports.shrinkBuf = function (buf, size) { - if (buf.length === size) { return buf; } - if (buf.subarray) { return buf.subarray(0, size); } - buf.length = size; - return buf; - }; + get typeId() { + return this.type && this.type.typeId; + } + clone() { + return new Field(this.name, this.type, this.nullable, this.metadata); + } - var fnTyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - if (src.subarray && dest.subarray) { - dest.set(src.subarray(src_offs, src_offs + len), dest_offs); - return; - } - // Fallback to ordinary array - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - // Join array of chunks to single array. - flattenChunks: function (chunks) { - var i, l, len, pos, chunk, result; + compareTo(other) { + return this.name === other.name && this.type === other.type && this.nullable === other.nullable && this.metadata === other.metadata; + } - // calculate data length - len = 0; - for (i = 0, l = chunks.length; i < l; i++) { - len += chunks[i].length; - } + toString() { + return "".concat(this.type).concat(this.nullable ? ', nullable' : '').concat(this.metadata ? ", metadata: ".concat(this.metadata) : ''); + } - // join chunks - result = new Uint8Array(len); - pos = 0; - for (i = 0, l = chunks.length; i < l; i++) { - chunk = chunks[i]; - result.set(chunk, pos); - pos += chunk.length; - } +} - return result; - } - }; +let Type; - var fnUntyped = { - arraySet: function (dest, src, src_offs, len, dest_offs) { - for (var i = 0; i < len; i++) { - dest[dest_offs + i] = src[src_offs + i]; - } - }, - // Join array of chunks to single array. - flattenChunks: function (chunks) { - return [].concat.apply([], chunks); - } - }; +(function (Type) { + Type[Type["NONE"] = 0] = "NONE"; + Type[Type["Null"] = 1] = "Null"; + Type[Type["Int"] = 2] = "Int"; + Type[Type["Float"] = 3] = "Float"; + Type[Type["Binary"] = 4] = "Binary"; + Type[Type["Utf8"] = 5] = "Utf8"; + Type[Type["Bool"] = 6] = "Bool"; + Type[Type["Decimal"] = 7] = "Decimal"; + Type[Type["Date"] = 8] = "Date"; + Type[Type["Time"] = 9] = "Time"; + Type[Type["Timestamp"] = 10] = "Timestamp"; + Type[Type["Interval"] = 11] = "Interval"; + Type[Type["List"] = 12] = "List"; + Type[Type["Struct"] = 13] = "Struct"; + Type[Type["Union"] = 14] = "Union"; + Type[Type["FixedSizeBinary"] = 15] = "FixedSizeBinary"; + Type[Type["FixedSizeList"] = 16] = "FixedSizeList"; + Type[Type["Map"] = 17] = "Map"; + Type[Type["Dictionary"] = -1] = "Dictionary"; + Type[Type["Int8"] = -2] = "Int8"; + Type[Type["Int16"] = -3] = "Int16"; + Type[Type["Int32"] = -4] = "Int32"; + Type[Type["Int64"] = -5] = "Int64"; + Type[Type["Uint8"] = -6] = "Uint8"; + Type[Type["Uint16"] = -7] = "Uint16"; + Type[Type["Uint32"] = -8] = "Uint32"; + Type[Type["Uint64"] = -9] = "Uint64"; + Type[Type["Float16"] = -10] = "Float16"; + Type[Type["Float32"] = -11] = "Float32"; + Type[Type["Float64"] = -12] = "Float64"; + Type[Type["DateDay"] = -13] = "DateDay"; + Type[Type["DateMillisecond"] = -14] = "DateMillisecond"; + Type[Type["TimestampSecond"] = -15] = "TimestampSecond"; + Type[Type["TimestampMillisecond"] = -16] = "TimestampMillisecond"; + Type[Type["TimestampMicrosecond"] = -17] = "TimestampMicrosecond"; + Type[Type["TimestampNanosecond"] = -18] = "TimestampNanosecond"; + Type[Type["TimeSecond"] = -19] = "TimeSecond"; + Type[Type["TimeMillisecond"] = -20] = "TimeMillisecond"; + Type[Type["TimeMicrosecond"] = -21] = "TimeMicrosecond"; + Type[Type["TimeNanosecond"] = -22] = "TimeNanosecond"; + Type[Type["DenseUnion"] = -23] = "DenseUnion"; + Type[Type["SparseUnion"] = -24] = "SparseUnion"; + Type[Type["IntervalDayTime"] = -25] = "IntervalDayTime"; + Type[Type["IntervalYearMonth"] = -26] = "IntervalYearMonth"; +})(Type || (Type = {})); +let _Symbol$toStringTag, _Symbol$toStringTag2, _Symbol$toStringTag7; +class DataType { + static isNull(x) { + return x && x.typeId === Type.Null; + } -// Enable/Disable typed arrays use, for testing -// - exports.setTyped = function (on) { - if (on) { - exports.Buf8 = Uint8Array; - exports.Buf16 = Uint16Array; - exports.Buf32 = Int32Array; - exports.assign(exports, fnTyped); - } else { - exports.Buf8 = Array; - exports.Buf16 = Array; - exports.Buf32 = Array; - exports.assign(exports, fnUntyped); - } - }; + static isInt(x) { + return x && x.typeId === Type.Int; + } - exports.setTyped(TYPED_OK); + static isFloat(x) { + return x && x.typeId === Type.Float; + } - },{}],4:[function(require,module,exports){ + static isBinary(x) { + return x && x.typeId === Type.Binary; + } + static isUtf8(x) { + return x && x.typeId === Type.Utf8; + } - var utils = require('./common'); + static isBool(x) { + return x && x.typeId === Type.Bool; + } + static isDecimal(x) { + return x && x.typeId === Type.Decimal; + } -// Quick check if we can use fast array to bin string conversion -// -// - apply(Array) can fail on Android 2.2 -// - apply(Uint8Array) can fail on iOS 5.1 Safari -// - var STR_APPLY_OK = true; - var STR_APPLY_UIA_OK = true; + static isDate(x) { + return x && x.typeId === Type.Date; + } - try { String.fromCharCode.apply(null, [ 0 ]); } catch (__) { STR_APPLY_OK = false; } - try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; } + static isTime(x) { + return x && x.typeId === Type.Time; + } + static isTimestamp(x) { + return x && x.typeId === Type.Timestamp; + } -// Table with utf8 lengths (calculated by first byte of sequence) -// Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, -// because max possible codepoint is 0x10ffff - var _utf8len = new utils.Buf8(256); - for (var q = 0; q < 256; q++) { - _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1); - } - _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start + static isInterval(x) { + return x && x.typeId === Type.Interval; + } + static isList(x) { + return x && x.typeId === Type.List; + } -// convert string to array (typed, when possible) - exports.string2buf = function (str) { - var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + static isStruct(x) { + return x && x.typeId === Type.Struct; + } - // count binary size - for (m_pos = 0; m_pos < str_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { - c2 = str.charCodeAt(m_pos + 1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; - } + static isUnion(x) { + return x && x.typeId === Type.Union; + } - // allocate buffer - buf = new utils.Buf8(buf_len); + static isFixedSizeBinary(x) { + return x && x.typeId === Type.FixedSizeBinary; + } - // convert - for (i = 0, m_pos = 0; i < buf_len; m_pos++) { - c = str.charCodeAt(m_pos); - if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { - c2 = str.charCodeAt(m_pos + 1); - if ((c2 & 0xfc00) === 0xdc00) { - c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); - m_pos++; - } - } - if (c < 0x80) { - /* one byte */ - buf[i++] = c; - } else if (c < 0x800) { - /* two bytes */ - buf[i++] = 0xC0 | (c >>> 6); - buf[i++] = 0x80 | (c & 0x3f); - } else if (c < 0x10000) { - /* three bytes */ - buf[i++] = 0xE0 | (c >>> 12); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } else { - /* four bytes */ - buf[i++] = 0xf0 | (c >>> 18); - buf[i++] = 0x80 | (c >>> 12 & 0x3f); - buf[i++] = 0x80 | (c >>> 6 & 0x3f); - buf[i++] = 0x80 | (c & 0x3f); - } - } + static isFixedSizeList(x) { + return x && x.typeId === Type.FixedSizeList; + } - return buf; - }; + static isMap(x) { + return x && x.typeId === Type.Map; + } -// Helper (used in 2 places) - function buf2binstring(buf, len) { - // On Chrome, the arguments in a function call that are allowed is `65534`. - // If the length of the buffer is smaller than that, we can use this optimization, - // otherwise we will take a slower path. - if (len < 65534) { - if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) { - return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len)); - } - } + static isDictionary(x) { + return x && x.typeId === Type.Dictionary; + } - var result = ''; - for (var i = 0; i < len; i++) { - result += String.fromCharCode(buf[i]); - } - return result; - } + get typeId() { + return Type.NONE; + } + compareTo(other) { + return this === other; + } -// Convert byte array to binary string - exports.buf2binstring = function (buf) { - return buf2binstring(buf, buf.length); - }; +} +_Symbol$toStringTag = Symbol.toStringTag; +class Int extends DataType { + constructor(isSigned, bitWidth) { + super(); + _defineProperty(this, "isSigned", void 0); -// Convert binary string (typed, when possible) - exports.binstring2buf = function (str) { - var buf = new utils.Buf8(str.length); - for (var i = 0, len = buf.length; i < len; i++) { - buf[i] = str.charCodeAt(i); - } - return buf; - }; + _defineProperty(this, "bitWidth", void 0); + this.isSigned = isSigned; + this.bitWidth = bitWidth; + } -// convert array to string - exports.buf2string = function (buf, max) { - var i, out, c, c_len; - var len = max || buf.length; + get typeId() { + return Type.Int; + } - // Reserve max possible length (2 words per char) - // NB: by unknown reasons, Array is significantly faster for - // String.fromCharCode.apply than Uint16Array. - var utf16buf = new Array(len * 2); + get [_Symbol$toStringTag]() { + return 'Int'; + } - for (out = 0, i = 0; i < len;) { - c = buf[i++]; - // quick process ascii - if (c < 0x80) { utf16buf[out++] = c; continue; } + toString() { + return "".concat(this.isSigned ? 'I' : 'Ui', "nt").concat(this.bitWidth); + } - c_len = _utf8len[c]; - // skip 5 & 6 byte codes - if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; } +} +class Int8 extends Int { + constructor() { + super(true, 8); + } - // apply mask on first byte - c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; - // join the rest - while (c_len > 1 && i < len) { - c = (c << 6) | (buf[i++] & 0x3f); - c_len--; - } +} +class Int16 extends Int { + constructor() { + super(true, 16); + } - // terminated by end of string? - if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } +} +class Int32 extends Int { + constructor() { + super(true, 32); + } - if (c < 0x10000) { - utf16buf[out++] = c; - } else { - c -= 0x10000; - utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); - utf16buf[out++] = 0xdc00 | (c & 0x3ff); - } - } +} +class Uint8 extends Int { + constructor() { + super(false, 8); + } - return buf2binstring(utf16buf, out); - }; +} +class Uint16 extends Int { + constructor() { + super(false, 16); + } +} +class Uint32 extends Int { + constructor() { + super(false, 32); + } -// Calculate max possible position in utf8 buffer, -// that will not break sequence. If that's not possible -// - (very small limits) return max size as is. -// -// buf[] - utf8 bytes array -// max - length limit (mandatory); - exports.utf8border = function (buf, max) { - var pos; +} +const Precision = { + HALF: 16, + SINGLE: 32, + DOUBLE: 64 +}; +_Symbol$toStringTag2 = Symbol.toStringTag; +class Float extends DataType { + constructor(precision) { + super(); - max = max || buf.length; - if (max > buf.length) { max = buf.length; } + _defineProperty(this, "precision", void 0); - // go back from last position, until start of sequence found - pos = max - 1; - while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + this.precision = precision; + } - // Very small and broken sequence, - // return max, because we should return something anyway. - if (pos < 0) { return max; } - - // If we came to start of buffer - that means buffer is too small, - // return max too. - if (pos === 0) { return max; } - - return (pos + _utf8len[buf[pos]] > max) ? pos : max; - }; - - },{"./common":3}],5:[function(require,module,exports){ - -// Note: adler32 takes 12% for level 0 and 2% for level 6. -// It isn't worth it to make additional optimizations as in original. -// Small size is preferable. + get typeId() { + return Type.Float; + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - - function adler32(adler, buf, len, pos) { - var s1 = (adler & 0xffff) |0, - s2 = ((adler >>> 16) & 0xffff) |0, - n = 0; - - while (len !== 0) { - // Set limit ~ twice less than 5552, to keep - // s2 in 31-bits, because we force signed ints. - // in other case %= will fail. - n = len > 2000 ? 2000 : len; - len -= n; + get [_Symbol$toStringTag2]() { + return 'Float'; + } - do { - s1 = (s1 + buf[pos++]) |0; - s2 = (s2 + s1) |0; - } while (--n); + toString() { + return "Float".concat(this.precision); + } - s1 %= 65521; - s2 %= 65521; - } +} +class Float32 extends Float { + constructor() { + super(Precision.SINGLE); + } - return (s1 | (s2 << 16)) |0; - } +} +class Float64 extends Float { + constructor() { + super(Precision.DOUBLE); + } +} +_Symbol$toStringTag7 = Symbol.toStringTag; +class FixedSizeList extends DataType { + constructor(listSize, child) { + super(); - module.exports = adler32; + _defineProperty(this, "listSize", void 0); - },{}],6:[function(require,module,exports){ + _defineProperty(this, "children", void 0); -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - - module.exports = { - - /* Allowed flush values; see deflate() and inflate() below for details */ - Z_NO_FLUSH: 0, - Z_PARTIAL_FLUSH: 1, - Z_SYNC_FLUSH: 2, - Z_FULL_FLUSH: 3, - Z_FINISH: 4, - Z_BLOCK: 5, - Z_TREES: 6, - - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - Z_OK: 0, - Z_STREAM_END: 1, - Z_NEED_DICT: 2, - Z_ERRNO: -1, - Z_STREAM_ERROR: -2, - Z_DATA_ERROR: -3, - //Z_MEM_ERROR: -4, - Z_BUF_ERROR: -5, - //Z_VERSION_ERROR: -6, - - /* compression levels */ - Z_NO_COMPRESSION: 0, - Z_BEST_SPEED: 1, - Z_BEST_COMPRESSION: 9, - Z_DEFAULT_COMPRESSION: -1, - - - Z_FILTERED: 1, - Z_HUFFMAN_ONLY: 2, - Z_RLE: 3, - Z_FIXED: 4, - Z_DEFAULT_STRATEGY: 0, - - /* Possible values of the data_type field (though see inflate()) */ - Z_BINARY: 0, - Z_TEXT: 1, - //Z_ASCII: 1, // = Z_TEXT (deprecated) - Z_UNKNOWN: 2, - - /* The deflate compression method */ - Z_DEFLATED: 8 - //Z_NULL: null // Use -1 or null inline, depending on var type - }; + this.listSize = listSize; + this.children = [child]; + } - },{}],7:[function(require,module,exports){ + get typeId() { + return Type.FixedSizeList; + } -// Note: we can't get significant speed boost here. -// So write code to minimize size - no pregenerated tables -// and array tools dependencies. + get valueType() { + return this.children[0].type; + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. + get valueField() { + return this.children[0]; + } -// Use ordinary array, since untyped makes no boost here - function makeTable() { - var c, table = []; + get [_Symbol$toStringTag7]() { + return 'FixedSizeList'; + } - for (var n = 0; n < 256; n++) { - c = n; - for (var k = 0; k < 8; k++) { - c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); - } - table[n] = c; - } + toString() { + return "FixedSizeList[".concat(this.listSize, "]<").concat(this.valueType, ">"); + } - return table; - } +} -// Create table on load. Just 255 signed longs. Not a problem. - var crcTable = makeTable(); +function getArrowTypeFromTypedArray(array) { + switch (array.constructor) { + case Int8Array: + return new Int8(); + case Uint8Array: + return new Uint8(); - function crc32(crc, buf, len, pos) { - var t = crcTable, - end = pos + len; + case Int16Array: + return new Int16(); - crc ^= -1; + case Uint16Array: + return new Uint16(); - for (var i = pos; i < end; i++) { - crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; - } + case Int32Array: + return new Int32(); - return (crc ^ (-1)); // >>> 0; - } + case Uint32Array: + return new Uint32(); + case Float32Array: + return new Float32(); - module.exports = crc32; + case Float64Array: + return new Float64(); - },{}],8:[function(require,module,exports){ + default: + throw new Error('array type not supported'); + } +} -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. +function deduceMeshField(attributeName, attribute, optionalMetadata) { + const type = getArrowTypeFromTypedArray(attribute.value); + const metadata = optionalMetadata ? optionalMetadata : makeMeshAttributeMetadata(attribute); + const field = new Field(attributeName, new FixedSizeList(attribute.size, new Field('value', type)), false, metadata); + return field; +} - var utils = require('../utils/common'); - var trees = require('./trees'); - var adler32 = require('./adler32'); - var crc32 = require('./crc32'); - var msg = require('./messages'); +function makeMeshAttributeMetadata(attribute) { + const result = new Map(); - /* Public constants ==========================================================*/ - /* ===========================================================================*/ + if ('byteOffset' in attribute) { + result.set('byteOffset', attribute.byteOffset.toString(10)); + } + if ('byteStride' in attribute) { + result.set('byteStride', attribute.byteStride.toString(10)); + } - /* Allowed flush values; see deflate() and inflate() below for details */ - var Z_NO_FLUSH = 0; - var Z_PARTIAL_FLUSH = 1; -//var Z_SYNC_FLUSH = 2; - var Z_FULL_FLUSH = 3; - var Z_FINISH = 4; - var Z_BLOCK = 5; -//var Z_TREES = 6; + if ('normalized' in attribute) { + result.set('normalized', attribute.normalized.toString()); + } + return result; +} - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - var Z_OK = 0; - var Z_STREAM_END = 1; -//var Z_NEED_DICT = 2; -//var Z_ERRNO = -1; - var Z_STREAM_ERROR = -2; - var Z_DATA_ERROR = -3; -//var Z_MEM_ERROR = -4; - var Z_BUF_ERROR = -5; -//var Z_VERSION_ERROR = -6; +function getDracoSchema(attributes, loaderData, indices) { + const metadataMap = makeMetadata(loaderData.metadata); + const fields = []; + const namedLoaderDataAttributes = transformAttributesLoaderData(loaderData.attributes); + for (const attributeName in attributes) { + const attribute = attributes[attributeName]; + const field = getArrowFieldFromAttribute(attributeName, attribute, namedLoaderDataAttributes[attributeName]); + fields.push(field); + } - /* compression levels */ -//var Z_NO_COMPRESSION = 0; -//var Z_BEST_SPEED = 1; -//var Z_BEST_COMPRESSION = 9; - var Z_DEFAULT_COMPRESSION = -1; + if (indices) { + const indicesField = getArrowFieldFromAttribute('indices', indices); + fields.push(indicesField); + } + return new Schema(fields, metadataMap); +} - var Z_FILTERED = 1; - var Z_HUFFMAN_ONLY = 2; - var Z_RLE = 3; - var Z_FIXED = 4; - var Z_DEFAULT_STRATEGY = 0; +function transformAttributesLoaderData(loaderData) { + const result = {}; - /* Possible values of the data_type field (though see inflate()) */ -//var Z_BINARY = 0; -//var Z_TEXT = 1; -//var Z_ASCII = 1; // = Z_TEXT - var Z_UNKNOWN = 2; + for (const key in loaderData) { + const dracoAttribute = loaderData[key]; + result[dracoAttribute.name || 'undefined'] = dracoAttribute; + } + return result; +} - /* The deflate compression method */ - var Z_DEFLATED = 8; +function getArrowFieldFromAttribute(attributeName, attribute, loaderData) { + const metadataMap = loaderData ? makeMetadata(loaderData.metadata) : undefined; + const field = deduceMeshField(attributeName, attribute, metadataMap); + return field; +} - /*============================================================================*/ +function makeMetadata(metadata) { + const metadataMap = new Map(); + for (const key in metadata) { + metadataMap.set("".concat(key, ".string"), JSON.stringify(metadata[key])); + } - var MAX_MEM_LEVEL = 9; - /* Maximum value for memLevel in deflateInit2 */ - var MAX_WBITS = 15; - /* 32K LZ77 window */ - var DEF_MEM_LEVEL = 8; + return metadataMap; +} +const DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP = { + POSITION: 'POSITION', + NORMAL: 'NORMAL', + COLOR: 'COLOR_0', + TEX_COORD: 'TEXCOORD_0' +}; +const DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP = { + 1: Int8Array, + 2: Uint8Array, + 3: Int16Array, + 4: Uint16Array, + 5: Int32Array, + 6: Uint32Array, + 9: Float32Array +}; +const INDEX_ITEM_SIZE = 4; +class DracoParser { + constructor(draco) { + _defineProperty(this, "draco", void 0); - var LENGTH_CODES = 29; - /* number of length codes, not counting the special END_BLOCK code */ - var LITERALS = 256; - /* number of literal bytes 0..255 */ - var L_CODES = LITERALS + 1 + LENGTH_CODES; - /* number of Literal or Length codes, including the END_BLOCK code */ - var D_CODES = 30; - /* number of distance codes */ - var BL_CODES = 19; - /* number of codes used to transfer the bit lengths */ - var HEAP_SIZE = 2 * L_CODES + 1; - /* maximum heap size */ - var MAX_BITS = 15; - /* All codes must not exceed MAX_BITS bits */ + _defineProperty(this, "decoder", void 0); - var MIN_MATCH = 3; - var MAX_MATCH = 258; - var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + _defineProperty(this, "metadataQuerier", void 0); - var PRESET_DICT = 0x20; + this.draco = draco; + this.decoder = new this.draco.Decoder(); + this.metadataQuerier = new this.draco.MetadataQuerier(); + } - var INIT_STATE = 42; - var EXTRA_STATE = 69; - var NAME_STATE = 73; - var COMMENT_STATE = 91; - var HCRC_STATE = 103; - var BUSY_STATE = 113; - var FINISH_STATE = 666; + destroy() { + this.draco.destroy(this.decoder); + this.draco.destroy(this.metadataQuerier); + } - var BS_NEED_MORE = 1; /* block not completed, need more input or more output */ - var BS_BLOCK_DONE = 2; /* block flush performed */ - var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ - var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + parseSync(arrayBuffer, options = {}) { + const buffer = new this.draco.DecoderBuffer(); + buffer.Init(new Int8Array(arrayBuffer), arrayBuffer.byteLength); - var OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + this._disableAttributeTransforms(options); - function err(strm, errorCode) { - strm.msg = msg[errorCode]; - return errorCode; - } + const geometry_type = this.decoder.GetEncodedGeometryType(buffer); + const dracoGeometry = geometry_type === this.draco.TRIANGULAR_MESH ? new this.draco.Mesh() : new this.draco.PointCloud(); - function rank(f) { - return ((f) << 1) - ((f) > 4 ? 9 : 0); - } + try { + let dracoStatus; - function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + switch (geometry_type) { + case this.draco.TRIANGULAR_MESH: + dracoStatus = this.decoder.DecodeBufferToMesh(buffer, dracoGeometry); + break; + case this.draco.POINT_CLOUD: + dracoStatus = this.decoder.DecodeBufferToPointCloud(buffer, dracoGeometry); + break; - /* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->output buffer and copying into it. - * (See also read_buf()). - */ - function flush_pending(strm) { - var s = strm.state; + default: + throw new Error('DRACO: Unknown geometry type.'); + } - //_tr_flush_bits(s); - var len = s.pending; - if (len > strm.avail_out) { - len = strm.avail_out; - } - if (len === 0) { return; } + if (!dracoStatus.ok() || !dracoGeometry.ptr) { + const message = "DRACO decompression failed: ".concat(dracoStatus.error_msg()); + throw new Error(message); + } - utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out); - strm.next_out += len; - s.pending_out += len; - strm.total_out += len; - strm.avail_out -= len; - s.pending -= len; - if (s.pending === 0) { - s.pending_out = 0; - } - } + const loaderData = this._getDracoLoaderData(dracoGeometry, geometry_type, options); + const geometry = this._getMeshData(dracoGeometry, loaderData, options); - function flush_block_only(s, last) { - trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); - s.block_start = s.strstart; - flush_pending(s.strm); - } + const boundingBox = getMeshBoundingBox(geometry.attributes); + const schema = getDracoSchema(geometry.attributes, loaderData, geometry.indices); + const data = { + loader: 'draco', + loaderData, + header: { + vertexCount: dracoGeometry.num_points(), + boundingBox + }, + ...geometry, + schema + }; + return data; + } finally { + this.draco.destroy(buffer); + if (dracoGeometry) { + this.draco.destroy(dracoGeometry); + } + } + } - function put_byte(s, b) { - s.pending_buf[s.pending++] = b; - } + _getDracoLoaderData(dracoGeometry, geometry_type, options) { + const metadata = this._getTopLevelMetadata(dracoGeometry); + const attributes = this._getDracoAttributes(dracoGeometry, options); - /* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ - function putShortMSB(s, b) { -// put_byte(s, (Byte)(b >> 8)); -// put_byte(s, (Byte)(b & 0xff)); - s.pending_buf[s.pending++] = (b >>> 8) & 0xff; - s.pending_buf[s.pending++] = b & 0xff; - } + return { + geometry_type, + num_attributes: dracoGeometry.num_attributes(), + num_points: dracoGeometry.num_points(), + num_faces: dracoGeometry instanceof this.draco.Mesh ? dracoGeometry.num_faces() : 0, + metadata, + attributes + }; + } + _getDracoAttributes(dracoGeometry, options) { + const dracoAttributes = {}; - /* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->input buffer and copying from it. - * (See also flush_pending()). - */ - function read_buf(strm, buf, start, size) { - var len = strm.avail_in; + for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) { + const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId); - if (len > size) { len = size; } - if (len === 0) { return 0; } + const metadata = this._getAttributeMetadata(dracoGeometry, attributeId); - strm.avail_in -= len; + dracoAttributes[dracoAttribute.unique_id()] = { + unique_id: dracoAttribute.unique_id(), + attribute_type: dracoAttribute.attribute_type(), + data_type: dracoAttribute.data_type(), + num_components: dracoAttribute.num_components(), + byte_offset: dracoAttribute.byte_offset(), + byte_stride: dracoAttribute.byte_stride(), + normalized: dracoAttribute.normalized(), + attribute_index: attributeId, + metadata + }; - // zmemcpy(buf, strm->next_in, len); - utils.arraySet(buf, strm.input, strm.next_in, len, start); - if (strm.state.wrap === 1) { - strm.adler = adler32(strm.adler, buf, len, start); - } + const quantization = this._getQuantizationTransform(dracoAttribute, options); - else if (strm.state.wrap === 2) { - strm.adler = crc32(strm.adler, buf, len, start); - } + if (quantization) { + dracoAttributes[dracoAttribute.unique_id()].quantization_transform = quantization; + } - strm.next_in += len; - strm.total_in += len; + const octahedron = this._getOctahedronTransform(dracoAttribute, options); - return len; - } + if (octahedron) { + dracoAttributes[dracoAttribute.unique_id()].octahedron_transform = octahedron; + } + } + return dracoAttributes; + } - /* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ - function longest_match(s, cur_match) { - var chain_length = s.max_chain_length; /* max hash chain length */ - var scan = s.strstart; /* current string */ - var match; /* matched string */ - var len; /* length of current match */ - var best_len = s.prev_length; /* best match length so far */ - var nice_match = s.nice_match; /* stop if match long enough */ - var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? - s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; - - var _win = s.window; // shortcut - - var wmask = s.w_mask; - var prev = s.prev; - - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ + _getMeshData(dracoGeometry, loaderData, options) { + const attributes = this._getMeshAttributes(loaderData, dracoGeometry, options); - var strend = s.strstart + MAX_MATCH; - var scan_end1 = _win[scan + best_len - 1]; - var scan_end = _win[scan + best_len]; + const positionAttribute = attributes.POSITION; - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + if (!positionAttribute) { + throw new Error('DRACO: No position attribute found.'); + } - /* Do not waste too much time if we already have a good match: */ - if (s.prev_length >= s.good_match) { - chain_length >>= 2; + if (dracoGeometry instanceof this.draco.Mesh) { + switch (options.topology) { + case 'triangle-strip': + return { + topology: 'triangle-strip', + mode: 4, + attributes, + indices: { + value: this._getTriangleStripIndices(dracoGeometry), + size: 1 } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if (nice_match > s.lookahead) { nice_match = s.lookahead; } - - // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - // Assert(cur_match < s->strstart, "no future"); - match = cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ - - if (_win[match + best_len] !== scan_end || - _win[match + best_len - 1] !== scan_end1 || - _win[match] !== _win[scan] || - _win[++match] !== _win[scan + 1]) { - continue; - } - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2; - match++; - // Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - /*jshint noempty:false*/ - } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && - scan < strend); - - // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (strend - scan); - scan = strend - MAX_MATCH; - - if (len > best_len) { - s.match_start = cur_match; - best_len = len; - if (len >= nice_match) { - break; - } - scan_end1 = _win[scan + best_len - 1]; - scan_end = _win[scan + best_len]; - } - } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + }; - if (best_len <= s.lookahead) { - return best_len; + case 'triangle-list': + default: + return { + topology: 'triangle-list', + mode: 5, + attributes, + indices: { + value: this._getTriangleListIndices(dracoGeometry), + size: 1 } - return s.lookahead; - } - + }; + } + } - /* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ - function fill_window(s) { - var _w_size = s.w_size; - var p, n, m, more, str; + return { + topology: 'point-list', + mode: 0, + attributes + }; + } - //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + _getMeshAttributes(loaderData, dracoGeometry, options) { + const attributes = {}; - do { - more = s.window_size - s.lookahead - s.strstart; + for (const loaderAttribute of Object.values(loaderData.attributes)) { + const attributeName = this._deduceAttributeName(loaderAttribute, options); - // JS ints have 32 bit, block below not needed - /* Deal with !@#$% 64K limit: */ - //if (sizeof(int) <= 2) { - // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - // more = wsize; - // - // } else if (more == (unsigned)(-1)) { - // /* Very unlikely, but possible on 16 bit machine if - // * strstart == 0 && lookahead == 1 (input done a byte at time) - // */ - // more--; - // } - //} - - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { - - utils.arraySet(s.window, s.window, _w_size, _w_size, 0); - s.match_start -= _w_size; - s.strstart -= _w_size; - /* we now have strstart >= MAX_DIST */ - s.block_start -= _w_size; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ + loaderAttribute.name = attributeName; - n = s.hash_size; - p = n; - do { - m = s.head[--p]; - s.head[p] = (m >= _w_size ? m - _w_size : 0); - } while (--n); + const { + value, + size + } = this._getAttributeValues(dracoGeometry, loaderAttribute); - n = _w_size; - p = n; - do { - m = s.prev[--p]; - s.prev[p] = (m >= _w_size ? m - _w_size : 0); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); + attributes[attributeName] = { + value, + size, + byteOffset: loaderAttribute.byte_offset, + byteStride: loaderAttribute.byte_stride, + normalized: loaderAttribute.normalized + }; + } - more += _w_size; - } - if (s.strm.avail_in === 0) { - break; - } + return attributes; + } - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - //Assert(more >= 2, "more < 2"); - n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); - s.lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s.lookahead + s.insert >= MIN_MATCH) { - str = s.strstart - s.insert; - s.ins_h = s.window[str]; - - /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask; -//#if MIN_MATCH != 3 -// Call update_hash() MIN_MATCH-3 more times -//#endif - while (s.insert) { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; - - s.prev[str & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = str; - str++; - s.insert--; - if (s.lookahead + s.insert < MIN_MATCH) { - break; - } - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ + _getTriangleListIndices(dracoGeometry) { + const numFaces = dracoGeometry.num_faces(); + const numIndices = numFaces * 3; + const byteLength = numIndices * INDEX_ITEM_SIZE; - } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); + const ptr = this.draco._malloc(byteLength); - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ -// if (s.high_water < s.window_size) { -// var curr = s.strstart + s.lookahead; -// var init = 0; -// -// if (s.high_water < curr) { -// /* Previous high water mark below current data -- zero WIN_INIT -// * bytes or up to end of window, whichever is less. -// */ -// init = s.window_size - curr; -// if (init > WIN_INIT) -// init = WIN_INIT; -// zmemzero(s->window + curr, (unsigned)init); -// s->high_water = curr + init; -// } -// else if (s->high_water < (ulg)curr + WIN_INIT) { -// /* High water mark at or above current data, but below current data -// * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up -// * to end of window, whichever is less. -// */ -// init = (ulg)curr + WIN_INIT - s->high_water; -// if (init > s->window_size - s->high_water) -// init = s->window_size - s->high_water; -// zmemzero(s->window + s->high_water, (unsigned)init); -// s->high_water += init; -// } -// } -// -// Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, -// "not enough room for search"); - } - - /* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ - function deflate_stored(s, flush) { - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - var max_block_size = 0xffff; + try { + this.decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); + return new Uint32Array(this.draco.HEAPF32.buffer, ptr, numIndices).slice(); + } finally { + this.draco._free(ptr); + } + } - if (max_block_size > s.pending_buf_size - 5) { - max_block_size = s.pending_buf_size - 5; - } + _getTriangleStripIndices(dracoGeometry) { + const dracoArray = new this.draco.DracoInt32Array(); - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s.lookahead <= 1) { - - //Assert(s->strstart < s->w_size+MAX_DIST(s) || - // s->block_start >= (long)s->w_size, "slide too late"); -// if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || -// s.block_start >= s.w_size)) { -// throw new Error("slide too late"); -// } - - fill_window(s); - if (s.lookahead === 0 && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } + try { + this.decoder.GetTriangleStripsFromMesh(dracoGeometry, dracoArray); + return getUint32Array(dracoArray); + } finally { + this.draco.destroy(dracoArray); + } + } - if (s.lookahead === 0) { - break; - } - /* flush the current block */ - } - //Assert(s->block_start >= 0L, "block gone"); -// if (s.block_start < 0) throw new Error("block gone"); + _getAttributeValues(dracoGeometry, attribute) { + const TypedArrayCtor = DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP[attribute.data_type]; + const numComponents = attribute.num_components; + const numPoints = dracoGeometry.num_points(); + const numValues = numPoints * numComponents; + const byteLength = numValues * TypedArrayCtor.BYTES_PER_ELEMENT; + const dataType = getDracoDataType(this.draco, TypedArrayCtor); + let value; - s.strstart += s.lookahead; - s.lookahead = 0; + const ptr = this.draco._malloc(byteLength); - /* Emit a stored block if pending_buf will be full: */ - var max_start = s.block_start + max_block_size; + try { + const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attribute.attribute_index); + this.decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, dracoAttribute, dataType, byteLength, ptr); + value = new TypedArrayCtor(this.draco.HEAPF32.buffer, ptr, numValues).slice(); + } finally { + this.draco._free(ptr); + } - if (s.strstart === 0 || s.strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s.lookahead = s.strstart - max_start; - s.strstart = max_start; - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ + return { + value, + size: numComponents + }; + } + _deduceAttributeName(attribute, options) { + const uniqueId = attribute.unique_id; - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } + for (const [attributeName, attributeUniqueId] of Object.entries(options.extraAttributes || {})) { + if (attributeUniqueId === uniqueId) { + return attributeName; + } + } - s.insert = 0; + const thisAttributeType = attribute.attribute_type; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } + for (const dracoAttributeConstant in DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP) { + const attributeType = this.draco[dracoAttributeConstant]; - if (s.strstart > s.block_start) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } + if (attributeType === thisAttributeType) { + return DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP[dracoAttributeConstant]; + } + } - return BS_NEED_MORE; - } + const entryName = options.attributeNameEntry || 'name'; - /* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ - function deflate_fast(s, flush) { - var hash_head; /* head of the hash chain */ - var bflush; /* set if current block must be flushed */ + if (attribute.metadata[entryName]) { + return attribute.metadata[entryName].string; + } - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { - break; /* flush the current block */ - } - } + return "CUSTOM_ATTRIBUTE_".concat(uniqueId); + } - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } + _getTopLevelMetadata(dracoGeometry) { + const dracoMetadata = this.decoder.GetMetadata(dracoGeometry); + return this._getDracoMetadata(dracoMetadata); + } - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ - } - if (s.match_length >= MIN_MATCH) { - // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + _getAttributeMetadata(dracoGeometry, attributeId) { + const dracoMetadata = this.decoder.GetAttributeMetadata(dracoGeometry, attributeId); + return this._getDracoMetadata(dracoMetadata); + } - /*** _tr_tally_dist(s, s.strstart - s.match_start, - s.match_length - MIN_MATCH, bflush); ***/ - bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + _getDracoMetadata(dracoMetadata) { + if (!dracoMetadata || !dracoMetadata.ptr) { + return {}; + } - s.lookahead -= s.match_length; + const result = {}; + const numEntries = this.metadataQuerier.NumEntries(dracoMetadata); - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { - s.match_length--; /* string at strstart already in table */ - do { - s.strstart++; - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s.match_length !== 0); - s.strstart++; - } else - { - s.strstart += s.match_length; - s.match_length = 0; - s.ins_h = s.window[s.strstart]; - /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask; - -//#if MIN_MATCH != 3 -// Call UPDATE_HASH() MIN_MATCH-3 more times -//#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s.window[s.strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + for (let entryIndex = 0; entryIndex < numEntries; entryIndex++) { + const entryName = this.metadataQuerier.GetEntryName(dracoMetadata, entryIndex); + result[entryName] = this._getDracoMetadataField(dracoMetadata, entryName); + } - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1); - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; - } + return result; + } - /* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ - function deflate_slow(s, flush) { - var hash_head; /* head of hash chain */ - var bflush; /* set if current block must be flushed */ + _getDracoMetadataField(dracoMetadata, entryName) { + const dracoArray = new this.draco.DracoInt32Array(); - var max_insert; + try { + this.metadataQuerier.GetIntEntryArray(dracoMetadata, entryName, dracoArray); + const intArray = getInt32Array(dracoArray); + return { + int: this.metadataQuerier.GetIntEntry(dracoMetadata, entryName), + string: this.metadataQuerier.GetStringEntry(dracoMetadata, entryName), + double: this.metadataQuerier.GetDoubleEntry(dracoMetadata, entryName), + intArray + }; + } finally { + this.draco.destroy(dracoArray); + } + } - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s.lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } + _disableAttributeTransforms(options) { + const { + quantizedAttributes = [], + octahedronAttributes = [] + } = options; + const skipAttributes = [...quantizedAttributes, ...octahedronAttributes]; - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = 0/*NIL*/; - if (s.lookahead >= MIN_MATCH) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } + for (const dracoAttributeName of skipAttributes) { + this.decoder.SkipAttributeTransform(this.draco[dracoAttributeName]); + } + } - /* Find the longest match, discarding those <= prev_length. - */ - s.prev_length = s.match_length; - s.prev_match = s.match_start; - s.match_length = MIN_MATCH - 1; + _getQuantizationTransform(dracoAttribute, options) { + const { + quantizedAttributes = [] + } = options; + const attribute_type = dracoAttribute.attribute_type(); + const skip = quantizedAttributes.map(type => this.decoder[type]).includes(attribute_type); - if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && - s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s.match_length = longest_match(s, hash_head); - /* longest_match() sets match_start */ + if (skip) { + const transform = new this.draco.AttributeQuantizationTransform(); - if (s.match_length <= 5 && - (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + try { + if (transform.InitFromAttribute(dracoAttribute)) { + return { + quantization_bits: transform.quantization_bits(), + range: transform.range(), + min_values: new Float32Array([1, 2, 3]).map(i => transform.min_value(i)) + }; + } + } finally { + this.draco.destroy(transform); + } + } - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s.match_length = MIN_MATCH - 1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { - max_insert = s.strstart + s.lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ + return null; + } - //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + _getOctahedronTransform(dracoAttribute, options) { + const { + octahedronAttributes = [] + } = options; + const attribute_type = dracoAttribute.attribute_type(); + const octahedron = octahedronAttributes.map(type => this.decoder[type]).includes(attribute_type); - /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, - s.prev_length - MIN_MATCH, bflush);***/ - bflush = trees._tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s.lookahead -= s.prev_length - 1; - s.prev_length -= 2; - do { - if (++s.strstart <= max_insert) { - /*** INSERT_STRING(s, s.strstart, hash_head); ***/ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask; - hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; - s.head[s.ins_h] = s.strstart; - /***/ - } - } while (--s.prev_length !== 0); - s.match_available = 0; - s.match_length = MIN_MATCH - 1; - s.strstart++; + if (octahedron) { + const transform = new this.draco.AttributeQuantizationTransform(); - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } + try { + if (transform.InitFromAttribute(dracoAttribute)) { + return { + quantization_bits: transform.quantization_bits() + }; + } + } finally { + this.draco.destroy(transform); + } + } - } else if (s.match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); + return null; + } - if (bflush) { - /*** FLUSH_BLOCK_ONLY(s, 0) ***/ - flush_block_only(s, false); - /***/ - } - s.strstart++; - s.lookahead--; - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s.match_available = 1; - s.strstart++; - s.lookahead--; - } - } - //Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s.match_available) { - //Tracevv((stderr,"%c", s->window[s->strstart-1])); - /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart - 1]); +} - s.match_available = 0; - } - s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } +function getDracoDataType(draco, attributeType) { + switch (attributeType) { + case Float32Array: + return draco.DT_FLOAT32; - return BS_BLOCK_DONE; - } + case Int8Array: + return draco.DT_INT8; + case Int16Array: + return draco.DT_INT16; - /* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ - function deflate_rle(s, flush) { - var bflush; /* set if current block must be flushed */ - var prev; /* byte at distance one to match */ - var scan, strend; /* scan goes up to strend for length of run */ + case Int32Array: + return draco.DT_INT32; - var _win = s.window; + case Uint8Array: + return draco.DT_UINT8; - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s.lookahead <= MAX_MATCH) { - fill_window(s); - if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - if (s.lookahead === 0) { break; } /* flush the current block */ - } + case Uint16Array: + return draco.DT_UINT16; - /* See how many times the previous byte repeats */ - s.match_length = 0; - if (s.lookahead >= MIN_MATCH && s.strstart > 0) { - scan = s.strstart - 1; - prev = _win[scan]; - if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { - strend = s.strstart + MAX_MATCH; - do { - /*jshint noempty:false*/ - } while (prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - prev === _win[++scan] && prev === _win[++scan] && - scan < strend); - s.match_length = MAX_MATCH - (strend - scan); - if (s.match_length > s.lookahead) { - s.match_length = s.lookahead; - } - } - //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } + case Uint32Array: + return draco.DT_UINT32; - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s.match_length >= MIN_MATCH) { - //check_match(s, s.strstart, s.strstart - 1, s.match_length); + default: + return draco.DT_INVALID; + } +} - /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ - bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH); +function getInt32Array(dracoArray) { + const numValues = dracoArray.size(); + const intArray = new Int32Array(numValues); - s.lookahead -= s.match_length; - s.strstart += s.match_length; - s.match_length = 0; - } else { - /* No match, output a literal byte */ - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); + for (let i = 0; i < numValues; i++) { + intArray[i] = dracoArray.GetValue(i); + } - s.lookahead--; - s.strstart++; - } - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; - } + return intArray; +} - /* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ - function deflate_huff(s, flush) { - var bflush; /* set if current block must be flushed */ +function getUint32Array(dracoArray) { + const numValues = dracoArray.size(); + const intArray = new Int32Array(numValues); - for (;;) { - /* Make sure that we have a literal to write. */ - if (s.lookahead === 0) { - fill_window(s); - if (s.lookahead === 0) { - if (flush === Z_NO_FLUSH) { - return BS_NEED_MORE; - } - break; /* flush the current block */ - } - } + for (let i = 0; i < numValues; i++) { + intArray[i] = dracoArray.GetValue(i); + } - /* Output a literal byte */ - s.match_length = 0; - //Tracevv((stderr,"%c", s->window[s->strstart])); - /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ - bflush = trees._tr_tally(s, 0, s.window[s.strstart]); - s.lookahead--; - s.strstart++; - if (bflush) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - } - s.insert = 0; - if (flush === Z_FINISH) { - /*** FLUSH_BLOCK(s, 1); ***/ - flush_block_only(s, true); - if (s.strm.avail_out === 0) { - return BS_FINISH_STARTED; - } - /***/ - return BS_FINISH_DONE; - } - if (s.last_lit) { - /*** FLUSH_BLOCK(s, 0); ***/ - flush_block_only(s, false); - if (s.strm.avail_out === 0) { - return BS_NEED_MORE; - } - /***/ - } - return BS_BLOCK_DONE; - } + return intArray; +} - /* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ - function Config(good_length, max_lazy, nice_length, max_chain, func) { - this.good_length = good_length; - this.max_lazy = max_lazy; - this.nice_length = nice_length; - this.max_chain = max_chain; - this.func = func; - } - - var configuration_table; - - configuration_table = [ - /* good lazy nice chain */ - new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ - new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ - new Config(4, 5, 16, 8, deflate_fast), /* 2 */ - new Config(4, 6, 32, 32, deflate_fast), /* 3 */ - - new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ - new Config(8, 16, 32, 32, deflate_slow), /* 5 */ - new Config(8, 16, 128, 128, deflate_slow), /* 6 */ - new Config(8, 32, 128, 256, deflate_slow), /* 7 */ - new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ - new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ - ]; +const DRACO_VERSION = '1.4.1'; +const DRACO_JS_DECODER_URL = "https://www.gstatic.com/draco/versioned/decoders/".concat(DRACO_VERSION, "/draco_decoder.js"); +const DRACO_WASM_WRAPPER_URL = "https://www.gstatic.com/draco/versioned/decoders/".concat(DRACO_VERSION, "/draco_wasm_wrapper.js"); +const DRACO_WASM_DECODER_URL = "https://www.gstatic.com/draco/versioned/decoders/".concat(DRACO_VERSION, "/draco_decoder.wasm"); +let loadDecoderPromise; +async function loadDracoDecoderModule(options) { + const modules = options.modules || {}; + if (modules.draco3d) { + loadDecoderPromise = loadDecoderPromise || modules.draco3d.createDecoderModule({}).then(draco => { + return { + draco + }; + }); + } else { + loadDecoderPromise = loadDecoderPromise || loadDracoDecoder(options); + } - /* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ - function lm_init(s) { - s.window_size = 2 * s.w_size; + return await loadDecoderPromise; +} - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); +async function loadDracoDecoder(options) { + let DracoDecoderModule; + let wasmBinary; - /* Set the default configuration parameters: - */ - s.max_lazy_match = configuration_table[s.level].max_lazy; - s.good_match = configuration_table[s.level].good_length; - s.nice_match = configuration_table[s.level].nice_length; - s.max_chain_length = configuration_table[s.level].max_chain; + switch (options.draco && options.draco.decoderType) { + case 'js': + DracoDecoderModule = await loadLibrary(DRACO_JS_DECODER_URL, 'draco', options); + break; - s.strstart = 0; - s.block_start = 0; - s.lookahead = 0; - s.insert = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - s.ins_h = 0; - } - - - function DeflateState() { - this.strm = null; /* pointer back to this zlib stream */ - this.status = 0; /* as the name implies */ - this.pending_buf = null; /* output still pending */ - this.pending_buf_size = 0; /* size of pending_buf */ - this.pending_out = 0; /* next pending byte to output to the stream */ - this.pending = 0; /* nb of bytes in the pending buffer */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.gzhead = null; /* gzip header information to write */ - this.gzindex = 0; /* where in extra, name, or comment */ - this.method = Z_DEFLATED; /* can only be DEFLATED */ - this.last_flush = -1; /* value of flush param for previous deflate call */ - - this.w_size = 0; /* LZ77 window size (32K by default) */ - this.w_bits = 0; /* log2(w_size) (8..16) */ - this.w_mask = 0; /* w_size - 1 */ - - this.window = null; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. - */ + case 'wasm': + default: + [DracoDecoderModule, wasmBinary] = await Promise.all([await loadLibrary(DRACO_WASM_WRAPPER_URL, 'draco', options), await loadLibrary(DRACO_WASM_DECODER_URL, 'draco', options)]); + } - this.window_size = 0; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ + DracoDecoderModule = DracoDecoderModule || globalThis.DracoDecoderModule; + return await initializeDracoDecoder(DracoDecoderModule, wasmBinary); +} - this.prev = null; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ +function initializeDracoDecoder(DracoDecoderModule, wasmBinary) { + const options = {}; - this.head = null; /* Heads of the hash chains or NIL. */ + if (wasmBinary) { + options.wasmBinary = wasmBinary; + } - this.ins_h = 0; /* hash index of string to be inserted */ - this.hash_size = 0; /* number of elements in hash table */ - this.hash_bits = 0; /* log2(hash_size) */ - this.hash_mask = 0; /* hash_size-1 */ + return new Promise(resolve => { + DracoDecoderModule({ ...options, + onModuleLoaded: draco => resolve({ + draco + }) + }); + }); +} +const DracoLoader = { ...DracoLoader$1, + parse: parse$2 +}; - this.hash_shift = 0; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ +async function parse$2(arrayBuffer, options) { + const { + draco + } = await loadDracoDecoderModule(options); + const dracoParser = new DracoParser(draco); - this.block_start = 0; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ + try { + return dracoParser.parseSync(arrayBuffer, options === null || options === void 0 ? void 0 : options.draco); + } finally { + dracoParser.destroy(); + } +} - this.match_length = 0; /* length of best match */ - this.prev_match = 0; /* previous match */ - this.match_available = 0; /* set if previous match exists */ - this.strstart = 0; /* start of string to insert */ - this.match_start = 0; /* start of matching string */ - this.lookahead = 0; /* number of valid bytes ahead in window */ +function getGLTFAccessors(attributes) { + const accessors = {}; - this.prev_length = 0; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ + for (const name in attributes) { + const attribute = attributes[name]; - this.max_chain_length = 0; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ + if (name !== 'indices') { + const glTFAccessor = getGLTFAccessor(attribute); + accessors[name] = glTFAccessor; + } + } - this.max_lazy_match = 0; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ - // That's alias to max_lazy_match, don't use directly - //this.max_insert_length = 0; - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ + return accessors; +} +function getGLTFAccessor(attribute) { + const { + buffer, + size, + count + } = getAccessorData(attribute); + const glTFAccessor = { + value: buffer, + size, + byteOffset: 0, + count, + type: getAccessorTypeFromSize(size), + componentType: getComponentTypeFromArray(buffer) + }; + return glTFAccessor; +} - this.level = 0; /* compression level (1..9) */ - this.strategy = 0; /* favor or force Huffman coding*/ +function getAccessorData(attribute) { + let buffer = attribute; + let size = 1; + let count = 0; - this.good_match = 0; - /* Use a faster search when the previous match is longer than this */ + if (attribute && attribute.value) { + buffer = attribute.value; + size = attribute.size || 1; + } - this.nice_match = 0; /* Stop searching when current match exceeds this */ + if (buffer) { + if (!ArrayBuffer.isView(buffer)) { + buffer = toTypedArray(buffer, Float32Array); + } - /* used by trees.c: */ + count = buffer.length / size; + } - /* Didn't use ct_data typedef below to suppress compiler warning */ + return { + buffer, + size, + count + }; +} - // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ +function toTypedArray(array, ArrayType, convertTypedArrays = false) { + if (!array) { + return null; + } - // Use flat array of DOUBLE size, with interleaved fata, - // because JS does not support effective - this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2); - this.dyn_dtree = new utils.Buf16((2 * D_CODES + 1) * 2); - this.bl_tree = new utils.Buf16((2 * BL_CODES + 1) * 2); - zero(this.dyn_ltree); - zero(this.dyn_dtree); - zero(this.bl_tree); + if (Array.isArray(array)) { + return new ArrayType(array); + } - this.l_desc = null; /* desc. for literal tree */ - this.d_desc = null; /* desc. for distance tree */ - this.bl_desc = null; /* desc. for bit length tree */ + if (convertTypedArrays && !(array instanceof ArrayType)) { + return new ArrayType(array); + } - //ush bl_count[MAX_BITS+1]; - this.bl_count = new utils.Buf16(MAX_BITS + 1); - /* number of codes at each bit length for an optimal tree */ + return array; +} - //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - this.heap = new utils.Buf16(2 * L_CODES + 1); /* heap used to build the Huffman trees */ - zero(this.heap); +const KHR_DRACO_MESH_COMPRESSION = 'KHR_draco_mesh_compression'; +const name$3 = KHR_DRACO_MESH_COMPRESSION; +function preprocess$1(gltfData, options, context) { + const scenegraph = new GLTFScenegraph(gltfData); - this.heap_len = 0; /* number of elements in the heap */ - this.heap_max = 0; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ + for (const primitive of makeMeshPrimitiveIterator(scenegraph)) { + if (scenegraph.getObjectExtension(primitive, KHR_DRACO_MESH_COMPRESSION)) ; + } +} +async function decode$3(gltfData, options, context) { + var _options$gltf; - this.depth = new utils.Buf16(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; - zero(this.depth); - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ + if (!(options !== null && options !== void 0 && (_options$gltf = options.gltf) !== null && _options$gltf !== void 0 && _options$gltf.decompressMeshes)) { + return; + } - this.l_buf = 0; /* buffer index for literals or lengths */ - - this.lit_bufsize = 0; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ + const scenegraph = new GLTFScenegraph(gltfData); + const promises = []; - this.last_lit = 0; /* running index in l_buf */ + for (const primitive of makeMeshPrimitiveIterator(scenegraph)) { + if (scenegraph.getObjectExtension(primitive, KHR_DRACO_MESH_COMPRESSION)) { + promises.push(decompressPrimitive(scenegraph, primitive, options, context)); + } + } - this.d_buf = 0; - /* Buffer index for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ + await Promise.all(promises); + scenegraph.removeExtension(KHR_DRACO_MESH_COMPRESSION); +} +function encode$3(gltfData, options = {}) { + const scenegraph = new GLTFScenegraph(gltfData); - this.opt_len = 0; /* bit length of current block with optimal trees */ - this.static_len = 0; /* bit length of current block with static trees */ - this.matches = 0; /* number of string matches in current block */ - this.insert = 0; /* bytes at end of window left to insert */ + for (const mesh of scenegraph.json.meshes || []) { + compressMesh(mesh); + scenegraph.addRequiredExtension(KHR_DRACO_MESH_COMPRESSION); + } +} +async function decompressPrimitive(scenegraph, primitive, options, context) { + const dracoExtension = scenegraph.getObjectExtension(primitive, KHR_DRACO_MESH_COMPRESSION); - this.bi_buf = 0; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - this.bi_valid = 0; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ + if (!dracoExtension) { + return; + } - // Used for window memory init. We safely ignore it for JS. That makes - // sense only for pointers and memory check tools. - //this.high_water = 0; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ - } + const buffer = scenegraph.getTypedArrayForBufferView(dracoExtension.bufferView); + const bufferCopy = sliceArrayBuffer(buffer.buffer, buffer.byteOffset); + const { + parse + } = context; + const dracoOptions = { ...options + }; + delete dracoOptions['3d-tiles']; + const decodedData = await parse(bufferCopy, DracoLoader, dracoOptions, context); + const decodedAttributes = getGLTFAccessors(decodedData.attributes); + for (const [attributeName, decodedAttribute] of Object.entries(decodedAttributes)) { + if (attributeName in primitive.attributes) { + const accessorIndex = primitive.attributes[attributeName]; + const accessor = scenegraph.getAccessor(accessorIndex); - function deflateResetKeep(strm) { - var s; + if (accessor !== null && accessor !== void 0 && accessor.min && accessor !== null && accessor !== void 0 && accessor.max) { + decodedAttribute.min = accessor.min; + decodedAttribute.max = accessor.max; + } + } + } - if (!strm || !strm.state) { - return err(strm, Z_STREAM_ERROR); - } + primitive.attributes = decodedAttributes; - strm.total_in = strm.total_out = 0; - strm.data_type = Z_UNKNOWN; + if (decodedData.indices) { + primitive.indices = getGLTFAccessor(decodedData.indices); + } - s = strm.state; - s.pending = 0; - s.pending_out = 0; + checkPrimitive(primitive); +} - if (s.wrap < 0) { - s.wrap = -s.wrap; - /* was made negative by deflate(..., Z_FINISH); */ - } - s.status = (s.wrap ? INIT_STATE : BUSY_STATE); - strm.adler = (s.wrap === 2) ? - 0 // crc32(0, Z_NULL, 0) - : - 1; // adler32(0, Z_NULL, 0) - s.last_flush = Z_NO_FLUSH; - trees._tr_init(s); - return Z_OK; - } +function compressMesh(attributes, indices, mode = 4, options, context) { + var _context$parseSync; + if (!options.DracoWriter) { + throw new Error('options.gltf.DracoWriter not provided'); + } - function deflateReset(strm) { - var ret = deflateResetKeep(strm); - if (ret === Z_OK) { - lm_init(strm.state); - } - return ret; - } + const compressedData = options.DracoWriter.encodeSync({ + attributes + }); + const decodedData = context === null || context === void 0 ? void 0 : (_context$parseSync = context.parseSync) === null || _context$parseSync === void 0 ? void 0 : _context$parseSync.call(context, { + attributes + }); + const fauxAccessors = options._addFauxAttributes(decodedData.attributes); - function deflateSetHeader(strm, head) { - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; } - strm.state.gzhead = head; - return Z_OK; + const bufferViewIndex = options.addBufferView(compressedData); + const glTFMesh = { + primitives: [{ + attributes: fauxAccessors, + mode, + extensions: { + [KHR_DRACO_MESH_COMPRESSION]: { + bufferView: bufferViewIndex, + attributes: fauxAccessors } + } + }] + }; + return glTFMesh; +} +function checkPrimitive(primitive) { + if (!primitive.attributes && Object.keys(primitive.attributes).length > 0) { + throw new Error('glTF: Empty primitive detected: Draco decompression failure?'); + } +} - function deflateInit2(strm, level, method, windowBits, memLevel, strategy) { - if (!strm) { // === Z_NULL - return Z_STREAM_ERROR; - } - var wrap = 1; +function* makeMeshPrimitiveIterator(scenegraph) { + for (const mesh of scenegraph.json.meshes || []) { + for (const primitive of mesh.primitives) { + yield primitive; + } + } +} - if (level === Z_DEFAULT_COMPRESSION) { - level = 6; - } +var KHR_draco_mesh_compression = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name$3, + preprocess: preprocess$1, + decode: decode$3, + encode: encode$3 +}); - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } +const KHR_LIGHTS_PUNCTUAL = 'KHR_lights_punctual'; +const name$2 = KHR_LIGHTS_PUNCTUAL; +async function decode$2(gltfData) { + const gltfScenegraph = new GLTFScenegraph(gltfData); + const { + json + } = gltfScenegraph; + const extension = gltfScenegraph.getExtension(KHR_LIGHTS_PUNCTUAL); - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } + if (extension) { + gltfScenegraph.json.lights = extension.lights; + gltfScenegraph.removeExtension(KHR_LIGHTS_PUNCTUAL); + } + for (const node of json.nodes || []) { + const nodeExtension = gltfScenegraph.getObjectExtension(node, KHR_LIGHTS_PUNCTUAL); - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { - return err(strm, Z_STREAM_ERROR); - } + if (nodeExtension) { + node.light = nodeExtension.light; + } + gltfScenegraph.removeObjectExtension(node, KHR_LIGHTS_PUNCTUAL); + } +} +async function encode$2(gltfData) { + const gltfScenegraph = new GLTFScenegraph(gltfData); + const { + json + } = gltfScenegraph; - if (windowBits === 8) { - windowBits = 9; - } - /* until 256-byte window bug fixed */ + if (json.lights) { + const extension = gltfScenegraph.addExtension(KHR_LIGHTS_PUNCTUAL); + assert$1(!extension.lights); + extension.lights = json.lights; + delete json.lights; + } - var s = new DeflateState(); + if (gltfScenegraph.json.lights) { + for (const light of gltfScenegraph.json.lights) { + const node = light.node; + gltfScenegraph.addObjectExtension(node, KHR_LIGHTS_PUNCTUAL, light); + } - strm.state = s; - s.strm = strm; + delete gltfScenegraph.json.lights; + } +} - s.wrap = wrap; - s.gzhead = null; - s.w_bits = windowBits; - s.w_size = 1 << s.w_bits; - s.w_mask = s.w_size - 1; +var KHR_lights_punctual = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name$2, + decode: decode$2, + encode: encode$2 +}); - s.hash_bits = memLevel + 7; - s.hash_size = 1 << s.hash_bits; - s.hash_mask = s.hash_size - 1; - s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); +const KHR_MATERIALS_UNLIT = 'KHR_materials_unlit'; +const name$1 = KHR_MATERIALS_UNLIT; +async function decode$1(gltfData) { + const gltfScenegraph = new GLTFScenegraph(gltfData); + const { + json + } = gltfScenegraph; + gltfScenegraph.removeExtension(KHR_MATERIALS_UNLIT); - s.window = new utils.Buf8(s.w_size * 2); - s.head = new utils.Buf16(s.hash_size); - s.prev = new utils.Buf16(s.w_size); + for (const material of json.materials || []) { + const extension = material.extensions && material.extensions.KHR_materials_unlit; - // Don't need mem init magic for JS. - //s.high_water = 0; /* nothing written to s->window yet */ + if (extension) { + material.unlit = true; + } - s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + gltfScenegraph.removeObjectExtension(material, KHR_MATERIALS_UNLIT); + } +} +function encode$1(gltfData) { + const gltfScenegraph = new GLTFScenegraph(gltfData); + const { + json + } = gltfScenegraph; - s.pending_buf_size = s.lit_bufsize * 4; + if (gltfScenegraph.materials) { + for (const material of json.materials || []) { + if (material.unlit) { + delete material.unlit; + gltfScenegraph.addObjectExtension(material, KHR_MATERIALS_UNLIT, {}); + gltfScenegraph.addExtension(KHR_MATERIALS_UNLIT); + } + } + } +} - //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - //s->pending_buf = (uchf *) overlay; - s.pending_buf = new utils.Buf8(s.pending_buf_size); +var KHR_materials_unlit = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name$1, + decode: decode$1, + encode: encode$1 +}); - // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) - //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s.d_buf = 1 * s.lit_bufsize; +const KHR_TECHNIQUES_WEBGL = 'KHR_techniques_webgl'; +const name = KHR_TECHNIQUES_WEBGL; +async function decode(gltfData) { + const gltfScenegraph = new GLTFScenegraph(gltfData); + const { + json + } = gltfScenegraph; + const extension = gltfScenegraph.getExtension(KHR_TECHNIQUES_WEBGL); - //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - s.l_buf = (1 + 2) * s.lit_bufsize; + if (extension) { + const techniques = resolveTechniques(extension, gltfScenegraph); - s.level = level; - s.strategy = strategy; - s.method = method; + for (const material of json.materials || []) { + const materialExtension = gltfScenegraph.getObjectExtension(material, KHR_TECHNIQUES_WEBGL); - return deflateReset(strm); - } + if (materialExtension) { + material.technique = Object.assign({}, materialExtension, techniques[materialExtension.technique]); + material.technique.values = resolveValues(material.technique, gltfScenegraph); + } - function deflateInit(strm, level) { - return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY); - } + gltfScenegraph.removeObjectExtension(material, KHR_TECHNIQUES_WEBGL); + } + gltfScenegraph.removeExtension(KHR_TECHNIQUES_WEBGL); + } +} +async function encode(gltfData, options) {} - function deflate(strm, flush) { - var old_flush, s; - var beg, val; // for gzip header write only +function resolveTechniques(techniquesExtension, gltfScenegraph) { + const { + programs = [], + shaders = [], + techniques = [] + } = techniquesExtension; + const textDecoder = new TextDecoder(); + shaders.forEach(shader => { + if (Number.isFinite(shader.bufferView)) { + shader.code = textDecoder.decode(gltfScenegraph.getTypedArrayForBufferView(shader.bufferView)); + } else { + throw new Error('KHR_techniques_webgl: no shader code'); + } + }); + programs.forEach(program => { + program.fragmentShader = shaders[program.fragmentShader]; + program.vertexShader = shaders[program.vertexShader]; + }); + techniques.forEach(technique => { + technique.program = programs[technique.program]; + }); + return techniques; +} - if (!strm || !strm.state || - flush > Z_BLOCK || flush < 0) { - return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR; - } +function resolveValues(technique, gltfScenegraph) { + const values = Object.assign({}, technique.values); + Object.keys(technique.uniforms || {}).forEach(uniform => { + if (technique.uniforms[uniform].value && !(uniform in values)) { + values[uniform] = technique.uniforms[uniform].value; + } + }); + Object.keys(values).forEach(uniform => { + if (typeof values[uniform] === 'object' && values[uniform].index !== undefined) { + values[uniform].texture = gltfScenegraph.getTexture(values[uniform].index); + } + }); + return values; +} - s = strm.state; +var KHR_techniques_webgl = /*#__PURE__*/Object.freeze({ + __proto__: null, + name: name, + decode: decode, + encode: encode +}); - if (!strm.output || - (!strm.input && strm.avail_in !== 0) || - (s.status === FINISH_STATE && flush !== Z_FINISH)) { - return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR); - } +const EXTENSIONS = [EXT_meshopt_compression, EXT_texture_webp, KHR_texture_basisu, KHR_draco_mesh_compression, KHR_lights_punctual, KHR_materials_unlit, KHR_techniques_webgl]; +function preprocessExtensions(gltf, options = {}, context) { + const extensions = EXTENSIONS.filter(extension => useExtension(extension.name, options)); - s.strm = strm; /* just in case */ - old_flush = s.last_flush; - s.last_flush = flush; + for (const extension of extensions) { + var _extension$preprocess; - /* Write the header */ - if (s.status === INIT_STATE) { + (_extension$preprocess = extension.preprocess) === null || _extension$preprocess === void 0 ? void 0 : _extension$preprocess.call(extension, gltf, options, context); + } +} +async function decodeExtensions(gltf, options = {}, context) { + const extensions = EXTENSIONS.filter(extension => useExtension(extension.name, options)); - if (s.wrap === 2) { // GZIP header - strm.adler = 0; //crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (!s.gzhead) { // s->gzhead == Z_NULL - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s.status = BUSY_STATE; - } - else { - put_byte(s, (s.gzhead.text ? 1 : 0) + - (s.gzhead.hcrc ? 2 : 0) + - (!s.gzhead.extra ? 0 : 4) + - (!s.gzhead.name ? 0 : 8) + - (!s.gzhead.comment ? 0 : 16) - ); - put_byte(s, s.gzhead.time & 0xff); - put_byte(s, (s.gzhead.time >> 8) & 0xff); - put_byte(s, (s.gzhead.time >> 16) & 0xff); - put_byte(s, (s.gzhead.time >> 24) & 0xff); - put_byte(s, s.level === 9 ? 2 : - (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? - 4 : 0)); - put_byte(s, s.gzhead.os & 0xff); - if (s.gzhead.extra && s.gzhead.extra.length) { - put_byte(s, s.gzhead.extra.length & 0xff); - put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); - } - if (s.gzhead.hcrc) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0); - } - s.gzindex = 0; - s.status = EXTRA_STATE; - } - } - else // DEFLATE header - { - var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8; - var level_flags = -1; - - if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { - level_flags = 0; - } else if (s.level < 6) { - level_flags = 1; - } else if (s.level === 6) { - level_flags = 2; - } else { - level_flags = 3; - } - header |= (level_flags << 6); - if (s.strstart !== 0) { header |= PRESET_DICT; } - header += 31 - (header % 31); + for (const extension of extensions) { + var _extension$decode; - s.status = BUSY_STATE; - putShortMSB(s, header); + await ((_extension$decode = extension.decode) === null || _extension$decode === void 0 ? void 0 : _extension$decode.call(extension, gltf, options, context)); + } +} - /* Save the adler32 of the preset dictionary: */ - if (s.strstart !== 0) { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } - strm.adler = 1; // adler32(0L, Z_NULL, 0); - } - } +function useExtension(extensionName, options) { + var _options$gltf; -//#ifdef GZIP - if (s.status === EXTRA_STATE) { - if (s.gzhead.extra/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ + const excludes = (options === null || options === void 0 ? void 0 : (_options$gltf = options.gltf) === null || _options$gltf === void 0 ? void 0 : _options$gltf.excludeExtensions) || {}; + const exclude = extensionName in excludes && !excludes[extensionName]; + return !exclude; +} - while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - break; - } - } - put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); - s.gzindex++; - } - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (s.gzindex === s.gzhead.extra.length) { - s.gzindex = 0; - s.status = NAME_STATE; - } - } - else { - s.status = NAME_STATE; - } - } - if (s.status === NAME_STATE) { - if (s.gzhead.name/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - //int val; +const KHR_BINARY_GLTF = 'KHR_binary_glTF'; +function preprocess(gltfData) { + const gltfScenegraph = new GLTFScenegraph(gltfData); + const { + json + } = gltfScenegraph; - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.name.length) { - val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); + for (const image of json.images || []) { + const extension = gltfScenegraph.getObjectExtension(image, KHR_BINARY_GLTF); - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.gzindex = 0; - s.status = COMMENT_STATE; - } - } - else { - s.status = COMMENT_STATE; - } - } - if (s.status === COMMENT_STATE) { - if (s.gzhead.comment/* != Z_NULL*/) { - beg = s.pending; /* start of bytes to update crc */ - //int val; + if (extension) { + Object.assign(image, extension); + } - do { - if (s.pending === s.pending_buf_size) { - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - flush_pending(strm); - beg = s.pending; - if (s.pending === s.pending_buf_size) { - val = 1; - break; - } - } - // JS specific: little magic to add zero terminator to end of string - if (s.gzindex < s.gzhead.comment.length) { - val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; - } else { - val = 0; - } - put_byte(s, val); - } while (val !== 0); + gltfScenegraph.removeObjectExtension(image, KHR_BINARY_GLTF); + } - if (s.gzhead.hcrc && s.pending > beg) { - strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg); - } - if (val === 0) { - s.status = HCRC_STATE; - } - } - else { - s.status = HCRC_STATE; - } - } - if (s.status === HCRC_STATE) { - if (s.gzhead.hcrc) { - if (s.pending + 2 > s.pending_buf_size) { - flush_pending(strm); - } - if (s.pending + 2 <= s.pending_buf_size) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - strm.adler = 0; //crc32(0L, Z_NULL, 0); - s.status = BUSY_STATE; - } - } - else { - s.status = BUSY_STATE; - } - } -//#endif + if (json.buffers && json.buffers[0]) { + delete json.buffers[0].uri; + } - /* Flush as much pending output as possible */ - if (s.pending !== 0) { - flush_pending(strm); - if (strm.avail_out === 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s.last_flush = -1; - return Z_OK; - } + gltfScenegraph.removeExtension(KHR_BINARY_GLTF); +} - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && - flush !== Z_FINISH) { - return err(strm, Z_BUF_ERROR); - } +const GLTF_ARRAYS = { + accessors: 'accessor', + animations: 'animation', + buffers: 'buffer', + bufferViews: 'bufferView', + images: 'image', + materials: 'material', + meshes: 'mesh', + nodes: 'node', + samplers: 'sampler', + scenes: 'scene', + skins: 'skin', + textures: 'texture' +}; +const GLTF_KEYS = { + accessor: 'accessors', + animations: 'animation', + buffer: 'buffers', + bufferView: 'bufferViews', + image: 'images', + material: 'materials', + mesh: 'meshes', + node: 'nodes', + sampler: 'samplers', + scene: 'scenes', + skin: 'skins', + texture: 'textures' +}; - /* User must not provide more input after the first FINISH: */ - if (s.status === FINISH_STATE && strm.avail_in !== 0) { - return err(strm, Z_BUF_ERROR); - } +class GLTFV1Normalizer { + constructor() { + _defineProperty(this, "idToIndexMap", { + animations: {}, + accessors: {}, + buffers: {}, + bufferViews: {}, + images: {}, + materials: {}, + meshes: {}, + nodes: {}, + samplers: {}, + scenes: {}, + skins: {}, + textures: {} + }); - /* Start a new block or continue the current one. - */ - if (strm.avail_in !== 0 || s.lookahead !== 0 || - (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) { - var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : - (s.strategy === Z_RLE ? deflate_rle(s, flush) : - configuration_table[s.level].func(s, flush)); - - if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { - s.status = FINISH_STATE; - } - if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { - if (strm.avail_out === 0) { - s.last_flush = -1; - /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate === BS_BLOCK_DONE) { - if (flush === Z_PARTIAL_FLUSH) { - trees._tr_align(s); - } - else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _defineProperty(this, "json", void 0); + } - trees._tr_stored_block(s, 0, 0, false); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush === Z_FULL_FLUSH) { - /*** CLEAR_HASH(s); ***/ /* forget history */ - zero(s.head); // Fill with NIL (= 0); - - if (s.lookahead === 0) { - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - } - } - flush_pending(strm); - if (strm.avail_out === 0) { - s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - //Assert(strm->avail_out > 0, "bug2"); - //if (strm.avail_out <= 0) { throw new Error("bug2");} + normalize(gltf, options) { + this.json = gltf.json; + const json = gltf.json; - if (flush !== Z_FINISH) { return Z_OK; } - if (s.wrap <= 0) { return Z_STREAM_END; } + switch (json.asset && json.asset.version) { + case '2.0': + return; - /* Write the trailer */ - if (s.wrap === 2) { - put_byte(s, strm.adler & 0xff); - put_byte(s, (strm.adler >> 8) & 0xff); - put_byte(s, (strm.adler >> 16) & 0xff); - put_byte(s, (strm.adler >> 24) & 0xff); - put_byte(s, strm.total_in & 0xff); - put_byte(s, (strm.total_in >> 8) & 0xff); - put_byte(s, (strm.total_in >> 16) & 0xff); - put_byte(s, (strm.total_in >> 24) & 0xff); - } - else - { - putShortMSB(s, strm.adler >>> 16); - putShortMSB(s, strm.adler & 0xffff); - } + case undefined: + case '1.0': + break; - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s.wrap > 0) { s.wrap = -s.wrap; } - /* write the trailer only once! */ - return s.pending !== 0 ? Z_OK : Z_STREAM_END; - } + default: + console.warn("glTF: Unknown version ".concat(json.asset.version)); + return; + } - function deflateEnd(strm) { - var status; + if (!options.normalize) { + throw new Error('glTF v1 is not supported.'); + } - if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { - return Z_STREAM_ERROR; - } + console.warn('Converting glTF v1 to glTF v2 format. This is experimental and may fail.'); - status = strm.state.status; - if (status !== INIT_STATE && - status !== EXTRA_STATE && - status !== NAME_STATE && - status !== COMMENT_STATE && - status !== HCRC_STATE && - status !== BUSY_STATE && - status !== FINISH_STATE - ) { - return err(strm, Z_STREAM_ERROR); - } + this._addAsset(json); - strm.state = null; + this._convertTopLevelObjectsToArrays(json); - return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK; - } + preprocess(gltf); + this._convertObjectIdsToArrayIndices(json); - /* ========================================================================= - * Initializes the compression dictionary from the given byte - * sequence without producing any compressed output. - */ - function deflateSetDictionary(strm, dictionary) { - var dictLength = dictionary.length; - - var s; - var str, n; - var wrap; - var avail; - var next; - var input; - var tmpDict; - - if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { - return Z_STREAM_ERROR; - } - - s = strm.state; - wrap = s.wrap; - - if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { - return Z_STREAM_ERROR; - } - - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ - if (wrap === 1) { - /* adler32(strm->adler, dictionary, dictLength); */ - strm.adler = adler32(strm.adler, dictionary, dictLength, 0); - } - - s.wrap = 0; /* avoid computing Adler-32 in read_buf */ - - /* if dictionary would fill window, just replace the history */ - if (dictLength >= s.w_size) { - if (wrap === 0) { /* already empty otherwise */ - /*** CLEAR_HASH(s); ***/ - zero(s.head); // Fill with NIL (= 0); - s.strstart = 0; - s.block_start = 0; - s.insert = 0; - } - /* use the tail */ - // dictionary = dictionary.slice(dictLength - s.w_size); - tmpDict = new utils.Buf8(s.w_size); - utils.arraySet(tmpDict, dictionary, dictLength - s.w_size, s.w_size, 0); - dictionary = tmpDict; - dictLength = s.w_size; - } - /* insert dictionary into window and hash */ - avail = strm.avail_in; - next = strm.next_in; - input = strm.input; - strm.avail_in = dictLength; - strm.next_in = 0; - strm.input = dictionary; - fill_window(s); - while (s.lookahead >= MIN_MATCH) { - str = s.strstart; - n = s.lookahead - (MIN_MATCH - 1); - do { - /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ - s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH - 1]) & s.hash_mask; + this._updateObjects(json); - s.prev[str & s.w_mask] = s.head[s.ins_h]; + this._updateMaterial(json); + } - s.head[s.ins_h] = str; - str++; - } while (--n); - s.strstart = str; - s.lookahead = MIN_MATCH - 1; - fill_window(s); - } - s.strstart += s.lookahead; - s.block_start = s.strstart; - s.insert = s.lookahead; - s.lookahead = 0; - s.match_length = s.prev_length = MIN_MATCH - 1; - s.match_available = 0; - strm.next_in = next; - strm.input = input; - strm.avail_in = avail; - s.wrap = wrap; - return Z_OK; - } - - - exports.deflateInit = deflateInit; - exports.deflateInit2 = deflateInit2; - exports.deflateReset = deflateReset; - exports.deflateResetKeep = deflateResetKeep; - exports.deflateSetHeader = deflateSetHeader; - exports.deflate = deflate; - exports.deflateEnd = deflateEnd; - exports.deflateSetDictionary = deflateSetDictionary; - exports.deflateInfo = 'pako deflate (from Nodeca project)'; - - /* Not implemented -exports.deflateBound = deflateBound; -exports.deflateCopy = deflateCopy; -exports.deflateParams = deflateParams; -exports.deflatePending = deflatePending; -exports.deflatePrime = deflatePrime; -exports.deflateTune = deflateTune; -*/ + _addAsset(json) { + json.asset = json.asset || {}; + json.asset.version = '2.0'; + json.asset.generator = json.asset.generator || 'Normalized to glTF 2.0 by loaders.gl'; + } - },{"../utils/common":3,"./adler32":5,"./crc32":7,"./messages":13,"./trees":14}],9:[function(require,module,exports){ + _convertTopLevelObjectsToArrays(json) { + for (const arrayName in GLTF_ARRAYS) { + this._convertTopLevelObjectToArray(json, arrayName); + } + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - - function GZheader() { - /* true if compressed data believed to be text */ - this.text = 0; - /* modification time */ - this.time = 0; - /* extra flags (not used when writing a gzip file) */ - this.xflags = 0; - /* operating system */ - this.os = 0; - /* pointer to extra field or Z_NULL if none */ - this.extra = null; - /* extra field length (valid if extra != Z_NULL) */ - this.extra_len = 0; // Actually, we don't need it in JS, - // but leave for few code modifications + _convertTopLevelObjectToArray(json, mapName) { + const objectMap = json[mapName]; - // - // Setup limits is not necessary because in js we should not preallocate memory - // for inflate use constant limit in 65536 bytes - // + if (!objectMap || Array.isArray(objectMap)) { + return; + } - /* space at extra (only when reading header) */ - // this.extra_max = 0; - /* pointer to zero-terminated file name or Z_NULL */ - this.name = ''; - /* space at name (only when reading header) */ - // this.name_max = 0; - /* pointer to zero-terminated comment or Z_NULL */ - this.comment = ''; - /* space at comment (only when reading header) */ - // this.comm_max = 0; - /* true if there was or will be a header crc */ - this.hcrc = 0; - /* true when done reading gzip header (not used when writing a gzip file) */ - this.done = false; - } + json[mapName] = []; - module.exports = GZheader; + for (const id in objectMap) { + const object = objectMap[id]; + object.id = object.id || id; + const index = json[mapName].length; + json[mapName].push(object); + this.idToIndexMap[mapName][id] = index; + } + } - },{}],10:[function(require,module,exports){ + _convertObjectIdsToArrayIndices(json) { + for (const arrayName in GLTF_ARRAYS) { + this._convertIdsToIndices(json, arrayName); + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -// See state defs from inflate.js - var BAD = 30; /* got a data error -- remain here until reset */ - var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + if ('scene' in json) { + json.scene = this._convertIdToIndex(json.scene, 'scene'); + } - /* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state.mode === LEN - strm.avail_in >= 6 - strm.avail_out >= 258 - start >= strm.avail_out - state.bits < 8 - - On return, state.mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm.avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm.avail_out >= 258 for each loop to avoid checking for - output space. - */ - module.exports = function inflate_fast(strm, start) { - var state; - var _in; /* local strm.input */ - var last; /* have enough input while in < last */ - var _out; /* local strm.output */ - var beg; /* inflate()'s initial strm.output */ - var end; /* while out < end, enough space available */ -//#ifdef INFLATE_STRICT - var dmax; /* maximum distance from zlib header */ -//#endif - var wsize; /* window size or zero if not using window */ - var whave; /* valid bytes in the window */ - var wnext; /* window write index */ - // Use `s_window` instead `window`, avoid conflict with instrumentation tools - var s_window; /* allocated sliding window, if wsize != 0 */ - var hold; /* local strm.hold */ - var bits; /* local strm.bits */ - var lcode; /* local strm.lencode */ - var dcode; /* local strm.distcode */ - var lmask; /* mask for first level of length codes */ - var dmask; /* mask for first level of distance codes */ - var here; /* retrieved table entry */ - var op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - var len; /* match length, unused bytes */ - var dist; /* match distance */ - var from; /* where to copy match from */ - var from_source; - - - var input, output; // JS specific, because we have no pointers - - /* copy state to local variables */ - state = strm.state; - //here = state.here; - _in = strm.next_in; - input = strm.input; - last = _in + (strm.avail_in - 5); - _out = strm.next_out; - output = strm.output; - beg = _out - (start - strm.avail_out); - end = _out + (strm.avail_out - 257); -//#ifdef INFLATE_STRICT - dmax = state.dmax; -//#endif - wsize = state.wsize; - whave = state.whave; - wnext = state.wnext; - s_window = state.window; - hold = state.hold; - bits = state.bits; - lcode = state.lencode; - dcode = state.distcode; - lmask = (1 << state.lenbits) - 1; - dmask = (1 << state.distbits) - 1; - - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - - top: - do { - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } + for (const texture of json.textures) { + this._convertTextureIds(texture); + } - here = lcode[hold & lmask]; - - dolen: - for (;;) { // Goto emulation - op = here >>> 24/*here.bits*/; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 0xff/*here.op*/; - if (op === 0) { /* literal */ - //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - // "inflate: literal '%c'\n" : - // "inflate: literal 0x%02x\n", here.val)); - output[_out++] = here & 0xffff/*here.val*/; - } - else if (op & 16) { /* length base */ - len = here & 0xffff/*here.val*/; - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - len += hold & ((1 << op) - 1); - hold >>>= op; - bits -= op; - } - //Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += input[_in++] << bits; - bits += 8; - hold += input[_in++] << bits; - bits += 8; - } - here = dcode[hold & dmask]; + for (const mesh of json.meshes) { + this._convertMeshIds(mesh); + } - dodist: - for (;;) { // goto emulation - op = here >>> 24/*here.bits*/; - hold >>>= op; - bits -= op; - op = (here >>> 16) & 0xff/*here.op*/; + for (const node of json.nodes) { + this._convertNodeIds(node); + } - if (op & 16) { /* distance base */ - dist = here & 0xffff/*here.val*/; - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - if (bits < op) { - hold += input[_in++] << bits; - bits += 8; - } - } - dist += hold & ((1 << op) - 1); -//#ifdef INFLATE_STRICT - if (dist > dmax) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break top; - } -//#endif - hold >>>= op; - bits -= op; - //Tracevv((stderr, "inflate: distance %u\n", dist)); - op = _out - beg; /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - if (state.sane) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break top; - } + for (const node of json.scenes) { + this._convertSceneIds(node); + } + } -// (!) This block is disabled in zlib defaults, -// don't enable it for binary compatibility -//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR -// if (len <= op - whave) { -// do { -// output[_out++] = 0; -// } while (--len); -// continue top; -// } -// len -= op - whave; -// do { -// output[_out++] = 0; -// } while (--op > whave); -// if (op === 0) { -// from = _out - dist; -// do { -// output[_out++] = output[from++]; -// } while (--len); -// continue top; -// } -//#endif - } - from = 0; // window index - from_source = s_window; - if (wnext === 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - else if (wnext < op) { /* wrap around window */ - from += wsize + wnext - op; - op -= wnext; - if (op < len) { /* some from end of window */ - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = 0; - if (wnext < len) { /* some from start of window */ - op = wnext; - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - } - else { /* contiguous in window */ - from += wnext - op; - if (op < len) { /* some from window */ - len -= op; - do { - output[_out++] = s_window[from++]; - } while (--op); - from = _out - dist; /* rest from output */ - from_source = output; - } - } - while (len > 2) { - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - output[_out++] = from_source[from++]; - len -= 3; - } - if (len) { - output[_out++] = from_source[from++]; - if (len > 1) { - output[_out++] = from_source[from++]; - } - } - } - else { - from = _out - dist; /* copy direct from output */ - do { /* minimum length is three */ - output[_out++] = output[from++]; - output[_out++] = output[from++]; - output[_out++] = output[from++]; - len -= 3; - } while (len > 2); - if (len) { - output[_out++] = output[from++]; - if (len > 1) { - output[_out++] = output[from++]; - } - } - } - } - else if ((op & 64) === 0) { /* 2nd level distance code */ - here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; - continue dodist; - } - else { - strm.msg = 'invalid distance code'; - state.mode = BAD; - break top; - } + _convertTextureIds(texture) { + if (texture.source) { + texture.source = this._convertIdToIndex(texture.source, 'image'); + } + } - break; // need to emulate goto via "continue" - } - } - else if ((op & 64) === 0) { /* 2nd level length code */ - here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; - continue dolen; - } - else if (op & 32) { /* end-of-block */ - //Tracevv((stderr, "inflate: end of block\n")); - state.mode = TYPE; - break top; - } - else { - strm.msg = 'invalid literal/length code'; - state.mode = BAD; - break top; - } + _convertMeshIds(mesh) { + for (const primitive of mesh.primitives) { + const { + attributes, + indices, + material + } = primitive; - break; // need to emulate goto via "continue" - } - } while (_in < last && _out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - _in -= len; - bits -= len << 3; - hold &= (1 << bits) - 1; - - /* update state and return */ - strm.next_in = _in; - strm.next_out = _out; - strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); - strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); - state.hold = hold; - state.bits = bits; - return; - }; + for (const attributeName in attributes) { + attributes[attributeName] = this._convertIdToIndex(attributes[attributeName], 'accessor'); + } - },{}],11:[function(require,module,exports){ + if (indices) { + primitive.indices = this._convertIdToIndex(indices, 'accessor'); + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. + if (material) { + primitive.material = this._convertIdToIndex(material, 'material'); + } + } + } - var utils = require('../utils/common'); - var adler32 = require('./adler32'); - var crc32 = require('./crc32'); - var inflate_fast = require('./inffast'); - var inflate_table = require('./inftrees'); + _convertNodeIds(node) { + if (node.children) { + node.children = node.children.map(child => this._convertIdToIndex(child, 'node')); + } - var CODES = 0; - var LENS = 1; - var DISTS = 2; + if (node.meshes) { + node.meshes = node.meshes.map(mesh => this._convertIdToIndex(mesh, 'mesh')); + } + } - /* Public constants ==========================================================*/ - /* ===========================================================================*/ + _convertSceneIds(scene) { + if (scene.nodes) { + scene.nodes = scene.nodes.map(node => this._convertIdToIndex(node, 'node')); + } + } + _convertIdsToIndices(json, topLevelArrayName) { + if (!json[topLevelArrayName]) { + console.warn("gltf v1: json doesn't contain attribute ".concat(topLevelArrayName)); + json[topLevelArrayName] = []; + } - /* Allowed flush values; see deflate() and inflate() below for details */ -//var Z_NO_FLUSH = 0; -//var Z_PARTIAL_FLUSH = 1; -//var Z_SYNC_FLUSH = 2; -//var Z_FULL_FLUSH = 3; - var Z_FINISH = 4; - var Z_BLOCK = 5; - var Z_TREES = 6; + for (const object of json[topLevelArrayName]) { + for (const key in object) { + const id = object[key]; + const index = this._convertIdToIndex(id, key); - /* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - var Z_OK = 0; - var Z_STREAM_END = 1; - var Z_NEED_DICT = 2; -//var Z_ERRNO = -1; - var Z_STREAM_ERROR = -2; - var Z_DATA_ERROR = -3; - var Z_MEM_ERROR = -4; - var Z_BUF_ERROR = -5; -//var Z_VERSION_ERROR = -6; + object[key] = index; + } + } + } - /* The deflate compression method */ - var Z_DEFLATED = 8; - - - /* STATES ====================================================================*/ - /* ===========================================================================*/ - - - var HEAD = 1; /* i: waiting for magic header */ - var FLAGS = 2; /* i: waiting for method and flags (gzip) */ - var TIME = 3; /* i: waiting for modification time (gzip) */ - var OS = 4; /* i: waiting for extra flags and operating system (gzip) */ - var EXLEN = 5; /* i: waiting for extra length (gzip) */ - var EXTRA = 6; /* i: waiting for extra bytes (gzip) */ - var NAME = 7; /* i: waiting for end of file name (gzip) */ - var COMMENT = 8; /* i: waiting for end of comment (gzip) */ - var HCRC = 9; /* i: waiting for header crc (gzip) */ - var DICTID = 10; /* i: waiting for dictionary check value */ - var DICT = 11; /* waiting for inflateSetDictionary() call */ - var TYPE = 12; /* i: waiting for type bits, including last-flag bit */ - var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ - var STORED = 14; /* i: waiting for stored size (length and complement) */ - var COPY_ = 15; /* i/o: same as COPY below, but only first time in */ - var COPY = 16; /* i/o: waiting for input or output to copy stored block */ - var TABLE = 17; /* i: waiting for dynamic block table lengths */ - var LENLENS = 18; /* i: waiting for code length code lengths */ - var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ - var LEN_ = 20; /* i: same as LEN below, but only first time in */ - var LEN = 21; /* i: waiting for length/lit/eob code */ - var LENEXT = 22; /* i: waiting for length extra bits */ - var DIST = 23; /* i: waiting for distance code */ - var DISTEXT = 24; /* i: waiting for distance extra bits */ - var MATCH = 25; /* o: waiting for output space to copy string */ - var LIT = 26; /* o: waiting for output space to write literal */ - var CHECK = 27; /* i: waiting for 32-bit check value */ - var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ - var DONE = 29; /* finished check, done -- remain here until reset */ - var BAD = 30; /* got a data error -- remain here until reset */ - var MEM = 31; /* got an inflate() memory error -- remain here until reset */ - var SYNC = 32; /* looking for synchronization bytes to restart inflate() */ - - /* ===========================================================================*/ - - - - var ENOUGH_LENS = 852; - var ENOUGH_DISTS = 592; -//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); - - var MAX_WBITS = 15; - /* 32K LZ77 window */ - var DEF_WBITS = MAX_WBITS; - - - function zswap32(q) { - return (((q >>> 24) & 0xff) + - ((q >>> 8) & 0xff00) + - ((q & 0xff00) << 8) + - ((q & 0xff) << 24)); - } - - - function InflateState() { - this.mode = 0; /* current inflate mode */ - this.last = false; /* true if processing last block */ - this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ - this.havedict = false; /* true if dictionary provided */ - this.flags = 0; /* gzip header method and flags (0 if zlib) */ - this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ - this.check = 0; /* protected copy of check value */ - this.total = 0; /* protected copy of output count */ - // TODO: may be {} - this.head = null; /* where to save gzip header information */ - - /* sliding window */ - this.wbits = 0; /* log base 2 of requested window size */ - this.wsize = 0; /* window size or zero if not using window */ - this.whave = 0; /* valid bytes in the window */ - this.wnext = 0; /* window write index */ - this.window = null; /* allocated sliding window, if needed */ - - /* bit accumulator */ - this.hold = 0; /* input bit accumulator */ - this.bits = 0; /* number of bits in "in" */ - - /* for string and stored block copying */ - this.length = 0; /* literal or length of data to copy */ - this.offset = 0; /* distance back to copy string from */ - - /* for table and code decoding */ - this.extra = 0; /* extra bits needed */ - - /* fixed and dynamic code tables */ - this.lencode = null; /* starting table for length/literal codes */ - this.distcode = null; /* starting table for distance codes */ - this.lenbits = 0; /* index bits for lencode */ - this.distbits = 0; /* index bits for distcode */ - - /* dynamic table building */ - this.ncode = 0; /* number of code length code lengths */ - this.nlen = 0; /* number of length code lengths */ - this.ndist = 0; /* number of distance code lengths */ - this.have = 0; /* number of code lengths in lens[] */ - this.next = null; /* next available space in codes[] */ - - this.lens = new utils.Buf16(320); /* temporary storage for code lengths */ - this.work = new utils.Buf16(288); /* work area for code table building */ - - /* - because we don't have pointers in js, we use lencode and distcode directly - as buffers so we don't need codes - */ - //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */ - this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ - this.distdyn = null; /* dynamic table for distance codes (JS specific) */ - this.sane = 0; /* if false, allow invalid distance too far */ - this.back = 0; /* bits back of last unprocessed length/lit */ - this.was = 0; /* initial length of match */ - } - - function inflateResetKeep(strm) { - var state; - - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - strm.total_in = strm.total_out = state.total = 0; - strm.msg = ''; /*Z_NULL*/ - if (state.wrap) { /* to support ill-conceived Java test suite */ - strm.adler = state.wrap & 1; - } - state.mode = HEAD; - state.last = 0; - state.havedict = 0; - state.dmax = 32768; - state.head = null/*Z_NULL*/; - state.hold = 0; - state.bits = 0; - //state.lencode = state.distcode = state.next = state.codes; - state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS); - state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS); - - state.sane = 1; - state.back = -1; - //Tracev((stderr, "inflate: reset\n")); - return Z_OK; - } - - function inflateReset(strm) { - var state; - - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - state.wsize = 0; - state.whave = 0; - state.wnext = 0; - return inflateResetKeep(strm); + _convertIdToIndex(id, key) { + const arrayName = GLTF_KEYS[key]; - } + if (arrayName in this.idToIndexMap) { + const index = this.idToIndexMap[arrayName][id]; - function inflateReset2(strm, windowBits) { - var wrap; - var state; + if (!Number.isFinite(index)) { + throw new Error("gltf v1: failed to resolve ".concat(key, " with id ").concat(id)); + } - /* get the state */ - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; + return index; + } - /* extract wrap request from windowBits parameter */ - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } - else { - wrap = (windowBits >> 4) + 1; - if (windowBits < 48) { - windowBits &= 15; - } - } + return id; + } - /* set number of window bits, free window if different */ - if (windowBits && (windowBits < 8 || windowBits > 15)) { - return Z_STREAM_ERROR; - } - if (state.window !== null && state.wbits !== windowBits) { - state.window = null; - } + _updateObjects(json) { + for (const buffer of this.json.buffers) { + delete buffer.type; + } + } - /* update state and reset the rest of it */ - state.wrap = wrap; - state.wbits = windowBits; - return inflateReset(strm); - } + _updateMaterial(json) { + for (const material of json.materials) { + var _material$values, _material$values2; - function inflateInit2(strm, windowBits) { - var ret; - var state; + material.pbrMetallicRoughness = { + baseColorFactor: [1, 1, 1, 1], + metallicFactor: 1, + roughnessFactor: 1 + }; + const textureId = ((_material$values = material.values) === null || _material$values === void 0 ? void 0 : _material$values.tex) || ((_material$values2 = material.values) === null || _material$values2 === void 0 ? void 0 : _material$values2.texture2d_0); + const textureIndex = json.textures.findIndex(texture => texture.id === textureId); - if (!strm) { return Z_STREAM_ERROR; } - //strm.msg = Z_NULL; /* in case we return an error */ + if (textureIndex !== -1) { + material.pbrMetallicRoughness.baseColorTexture = { + index: textureIndex + }; + } + } + } - state = new InflateState(); +} - //if (state === Z_NULL) return Z_MEM_ERROR; - //Tracev((stderr, "inflate: allocated\n")); - strm.state = state; - state.window = null/*Z_NULL*/; - ret = inflateReset2(strm, windowBits); - if (ret !== Z_OK) { - strm.state = null/*Z_NULL*/; - } - return ret; - } +function normalizeGLTFV1(gltf, options = {}) { + return new GLTFV1Normalizer().normalize(gltf, options); +} - function inflateInit(strm) { - return inflateInit2(strm, DEF_WBITS); - } +const COMPONENTS = { + SCALAR: 1, + VEC2: 2, + VEC3: 3, + VEC4: 4, + MAT2: 4, + MAT3: 9, + MAT4: 16 +}; +const BYTES = { + 5120: 1, + 5121: 1, + 5122: 2, + 5123: 2, + 5125: 4, + 5126: 4 +}; +const GL_SAMPLER = { + TEXTURE_MAG_FILTER: 0x2800, + TEXTURE_MIN_FILTER: 0x2801, + TEXTURE_WRAP_S: 0x2802, + TEXTURE_WRAP_T: 0x2803, + REPEAT: 0x2901, + LINEAR: 0x2601, + NEAREST_MIPMAP_LINEAR: 0x2702 +}; +const SAMPLER_PARAMETER_GLTF_TO_GL = { + magFilter: GL_SAMPLER.TEXTURE_MAG_FILTER, + minFilter: GL_SAMPLER.TEXTURE_MIN_FILTER, + wrapS: GL_SAMPLER.TEXTURE_WRAP_S, + wrapT: GL_SAMPLER.TEXTURE_WRAP_T +}; +const DEFAULT_SAMPLER = { + [GL_SAMPLER.TEXTURE_MAG_FILTER]: GL_SAMPLER.LINEAR, + [GL_SAMPLER.TEXTURE_MIN_FILTER]: GL_SAMPLER.NEAREST_MIPMAP_LINEAR, + [GL_SAMPLER.TEXTURE_WRAP_S]: GL_SAMPLER.REPEAT, + [GL_SAMPLER.TEXTURE_WRAP_T]: GL_SAMPLER.REPEAT +}; +function getBytesFromComponentType(componentType) { + return BYTES[componentType]; +} - /* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ - var virgin = true; +function getSizeFromAccessorType(type) { + return COMPONENTS[type]; +} - var lenfix, distfix; // We have no pointers in JS, so keep tables separate +class GLTFPostProcessor { + constructor() { + _defineProperty(this, "baseUri", ''); - function fixedtables(state) { - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - var sym; + _defineProperty(this, "json", {}); - lenfix = new utils.Buf32(512); - distfix = new utils.Buf32(32); + _defineProperty(this, "buffers", []); - /* literal/length table */ - sym = 0; - while (sym < 144) { state.lens[sym++] = 8; } - while (sym < 256) { state.lens[sym++] = 9; } - while (sym < 280) { state.lens[sym++] = 7; } - while (sym < 288) { state.lens[sym++] = 8; } + _defineProperty(this, "images", []); + } - inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 }); + postProcess(gltf, options = {}) { + const { + json, + buffers = [], + images = [], + baseUri = '' + } = gltf; + assert$1(json); + this.baseUri = baseUri; + this.json = json; + this.buffers = buffers; + this.images = images; - /* distance table */ - sym = 0; - while (sym < 32) { state.lens[sym++] = 5; } + this._resolveTree(this.json, options); - inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 }); + return this.json; + } - /* do this just once */ - virgin = false; - } + _resolveTree(json, options = {}) { + if (json.bufferViews) { + json.bufferViews = json.bufferViews.map((bufView, i) => this._resolveBufferView(bufView, i)); + } - state.lencode = lenfix; - state.lenbits = 9; - state.distcode = distfix; - state.distbits = 5; - } + if (json.images) { + json.images = json.images.map((image, i) => this._resolveImage(image, i)); + } + if (json.samplers) { + json.samplers = json.samplers.map((sampler, i) => this._resolveSampler(sampler, i)); + } - /* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ - function updatewindow(strm, src, end, copy) { - var dist; - var state = strm.state; + if (json.textures) { + json.textures = json.textures.map((texture, i) => this._resolveTexture(texture, i)); + } - /* if it hasn't been done already, allocate space for the window */ - if (state.window === null) { - state.wsize = 1 << state.wbits; - state.wnext = 0; - state.whave = 0; + if (json.accessors) { + json.accessors = json.accessors.map((accessor, i) => this._resolveAccessor(accessor, i)); + } - state.window = new utils.Buf8(state.wsize); - } + if (json.materials) { + json.materials = json.materials.map((material, i) => this._resolveMaterial(material, i)); + } - /* copy state->wsize or less output bytes into the circular window */ - if (copy >= state.wsize) { - utils.arraySet(state.window, src, end - state.wsize, state.wsize, 0); - state.wnext = 0; - state.whave = state.wsize; - } - else { - dist = state.wsize - state.wnext; - if (dist > copy) { - dist = copy; - } - //zmemcpy(state->window + state->wnext, end - copy, dist); - utils.arraySet(state.window, src, end - copy, dist, state.wnext); - copy -= dist; - if (copy) { - //zmemcpy(state->window, end - copy, copy); - utils.arraySet(state.window, src, end - copy, copy, 0); - state.wnext = copy; - state.whave = state.wsize; - } - else { - state.wnext += dist; - if (state.wnext === state.wsize) { state.wnext = 0; } - if (state.whave < state.wsize) { state.whave += dist; } - } - } - return 0; - } + if (json.meshes) { + json.meshes = json.meshes.map((mesh, i) => this._resolveMesh(mesh, i)); + } - function inflate(strm, flush) { - var state; - var input, output; // input/output buffers - var next; /* next input INDEX */ - var put; /* next output INDEX */ - var have, left; /* available input and output */ - var hold; /* bit buffer */ - var bits; /* bits in bit buffer */ - var _in, _out; /* save starting available input and output */ - var copy; /* number of stored or match bytes to copy */ - var from; /* where to copy match bytes from */ - var from_source; - var here = 0; /* current decoding table entry */ - var here_bits, here_op, here_val; // paked "here" denormalized (JS specific) - //var last; /* parent table entry */ - var last_bits, last_op, last_val; // paked "last" denormalized (JS specific) - var len; /* length to copy for repeats, bits to drop */ - var ret; /* return code */ - var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */ - var opts; - - var n; // temporary var for NEED_BITS - - var order = /* permutation of code lengths */ - [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]; - - - if (!strm || !strm.state || !strm.output || - (!strm.input && strm.avail_in !== 0)) { - return Z_STREAM_ERROR; - } - - state = strm.state; - if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ - - - //--- LOAD() --- - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - //--- - - _in = have; - _out = left; - ret = Z_OK; - - inf_leave: // goto emulation - for (;;) { - switch (state.mode) { - case HEAD: - if (state.wrap === 0) { - state.mode = TYPEDO; - break; - } - //=== NEEDBITS(16); - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ - state.check = 0/*crc32(0L, Z_NULL, 0)*/; - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// + if (json.nodes) { + json.nodes = json.nodes.map((node, i) => this._resolveNode(node, i)); + } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = FLAGS; - break; - } - state.flags = 0; /* expect zlib header */ - if (state.head) { - state.head.done = false; - } - if (!(state.wrap & 1) || /* check if zlib header allowed */ - (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { - strm.msg = 'incorrect header check'; - state.mode = BAD; - break; - } - if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { - strm.msg = 'unknown compression method'; - state.mode = BAD; - break; - } - //--- DROPBITS(4) ---// - hold >>>= 4; - bits -= 4; - //---// - len = (hold & 0x0f)/*BITS(4)*/ + 8; - if (state.wbits === 0) { - state.wbits = len; - } - else if (len > state.wbits) { - strm.msg = 'invalid window size'; - state.mode = BAD; - break; - } - state.dmax = 1 << len; - //Tracev((stderr, "inflate: zlib header ok\n")); - strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; - state.mode = hold & 0x200 ? DICTID : TYPE; - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - break; - case FLAGS: - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.flags = hold; - if ((state.flags & 0xff) !== Z_DEFLATED) { - strm.msg = 'unknown compression method'; - state.mode = BAD; - break; - } - if (state.flags & 0xe000) { - strm.msg = 'unknown header flags set'; - state.mode = BAD; - break; - } - if (state.head) { - state.head.text = ((hold >> 8) & 1); - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = TIME; - /* falls through */ - case TIME: - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (state.head) { - state.head.time = hold; - } - if (state.flags & 0x0200) { - //=== CRC4(state.check, hold) - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - hbuf[2] = (hold >>> 16) & 0xff; - hbuf[3] = (hold >>> 24) & 0xff; - state.check = crc32(state.check, hbuf, 4, 0); - //=== - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = OS; - /* falls through */ - case OS: - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (state.head) { - state.head.xflags = (hold & 0xff); - state.head.os = (hold >> 8); - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = EXLEN; - /* falls through */ - case EXLEN: - if (state.flags & 0x0400) { - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.length = hold; - if (state.head) { - state.head.extra_len = hold; - } - if (state.flags & 0x0200) { - //=== CRC2(state.check, hold); - hbuf[0] = hold & 0xff; - hbuf[1] = (hold >>> 8) & 0xff; - state.check = crc32(state.check, hbuf, 2, 0); - //===// - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - } - else if (state.head) { - state.head.extra = null/*Z_NULL*/; - } - state.mode = EXTRA; - /* falls through */ - case EXTRA: - if (state.flags & 0x0400) { - copy = state.length; - if (copy > have) { copy = have; } - if (copy) { - if (state.head) { - len = state.head.extra_len - state.length; - if (!state.head.extra) { - // Use untyped array for more convenient processing later - state.head.extra = new Array(state.head.extra_len); - } - utils.arraySet( - state.head.extra, - input, - next, - // extra field is limited to 65536 bytes - // - no need for additional size check - copy, - /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ - len - ); - //zmemcpy(state.head.extra + len, next, - // len + copy > state.head.extra_max ? - // state.head.extra_max - len : copy); - } - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - state.length -= copy; - } - if (state.length) { break inf_leave; } - } - state.length = 0; - state.mode = NAME; - /* falls through */ - case NAME: - if (state.flags & 0x0800) { - if (have === 0) { break inf_leave; } - copy = 0; - do { - // TODO: 2 or 1 bytes? - len = input[next + copy++]; - /* use constant limit because in js we should not preallocate memory */ - if (state.head && len && - (state.length < 65536 /*state.head.name_max*/)) { - state.head.name += String.fromCharCode(len); - } - } while (len && copy < have); + if (json.skins) { + json.skins = json.skins.map((skin, i) => this._resolveSkin(skin, i)); + } - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { break inf_leave; } - } - else if (state.head) { - state.head.name = null; - } - state.length = 0; - state.mode = COMMENT; - /* falls through */ - case COMMENT: - if (state.flags & 0x1000) { - if (have === 0) { break inf_leave; } - copy = 0; - do { - len = input[next + copy++]; - /* use constant limit because in js we should not preallocate memory */ - if (state.head && len && - (state.length < 65536 /*state.head.comm_max*/)) { - state.head.comment += String.fromCharCode(len); - } - } while (len && copy < have); - if (state.flags & 0x0200) { - state.check = crc32(state.check, input, copy, next); - } - have -= copy; - next += copy; - if (len) { break inf_leave; } - } - else if (state.head) { - state.head.comment = null; - } - state.mode = HCRC; - /* falls through */ - case HCRC: - if (state.flags & 0x0200) { - //=== NEEDBITS(16); */ - while (bits < 16) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (hold !== (state.check & 0xffff)) { - strm.msg = 'header crc mismatch'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - } - if (state.head) { - state.head.hcrc = ((state.flags >> 9) & 1); - state.head.done = true; - } - strm.adler = state.check = 0; - state.mode = TYPE; - break; - case DICTID: - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - strm.adler = state.check = zswap32(hold); - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = DICT; - /* falls through */ - case DICT: - if (state.havedict === 0) { - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - return Z_NEED_DICT; - } - strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; - state.mode = TYPE; - /* falls through */ - case TYPE: - if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } - /* falls through */ - case TYPEDO: - if (state.last) { - //--- BYTEBITS() ---// - hold >>>= bits & 7; - bits -= bits & 7; - //---// - state.mode = CHECK; - break; - } - //=== NEEDBITS(3); */ - while (bits < 3) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.last = (hold & 0x01)/*BITS(1)*/; - //--- DROPBITS(1) ---// - hold >>>= 1; - bits -= 1; - //---// + if (json.scenes) { + json.scenes = json.scenes.map((scene, i) => this._resolveScene(scene, i)); + } - switch ((hold & 0x03)/*BITS(2)*/) { - case 0: /* stored block */ - //Tracev((stderr, "inflate: stored block%s\n", - // state.last ? " (last)" : "")); - state.mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - //Tracev((stderr, "inflate: fixed codes block%s\n", - // state.last ? " (last)" : "")); - state.mode = LEN_; /* decode codes */ - if (flush === Z_TREES) { - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - break inf_leave; - } - break; - case 2: /* dynamic block */ - //Tracev((stderr, "inflate: dynamic codes block%s\n", - // state.last ? " (last)" : "")); - state.mode = TABLE; - break; - case 3: - strm.msg = 'invalid block type'; - state.mode = BAD; - } - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - break; - case STORED: - //--- BYTEBITS() ---// /* go to byte boundary */ - hold >>>= bits & 7; - bits -= bits & 7; - //---// - //=== NEEDBITS(32); */ - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { - strm.msg = 'invalid stored block lengths'; - state.mode = BAD; - break; - } - state.length = hold & 0xffff; - //Tracev((stderr, "inflate: stored length %u\n", - // state.length)); - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - state.mode = COPY_; - if (flush === Z_TREES) { break inf_leave; } - /* falls through */ - case COPY_: - state.mode = COPY; - /* falls through */ - case COPY: - copy = state.length; - if (copy) { - if (copy > have) { copy = have; } - if (copy > left) { copy = left; } - if (copy === 0) { break inf_leave; } - //--- zmemcpy(put, next, copy); --- - utils.arraySet(output, input, next, copy, put); - //---// - have -= copy; - next += copy; - left -= copy; - put += copy; - state.length -= copy; - break; - } - //Tracev((stderr, "inflate: stored end\n")); - state.mode = TYPE; - break; - case TABLE: - //=== NEEDBITS(14); */ - while (bits < 14) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; - //--- DROPBITS(5) ---// - hold >>>= 5; - bits -= 5; - //---// - state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; - //--- DROPBITS(5) ---// - hold >>>= 5; - bits -= 5; - //---// - state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; - //--- DROPBITS(4) ---// - hold >>>= 4; - bits -= 4; - //---// -//#ifndef PKZIP_BUG_WORKAROUND - if (state.nlen > 286 || state.ndist > 30) { - strm.msg = 'too many length or distance symbols'; - state.mode = BAD; - break; - } -//#endif - //Tracev((stderr, "inflate: table sizes ok\n")); - state.have = 0; - state.mode = LENLENS; - /* falls through */ - case LENLENS: - while (state.have < state.ncode) { - //=== NEEDBITS(3); - while (bits < 3) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); - //--- DROPBITS(3) ---// - hold >>>= 3; - bits -= 3; - //---// - } - while (state.have < 19) { - state.lens[order[state.have++]] = 0; - } - // We have separate tables & no pointers. 2 commented lines below not needed. - //state.next = state.codes; - //state.lencode = state.next; - // Switch to use dynamic table - state.lencode = state.lendyn; - state.lenbits = 7; - - opts = { bits: state.lenbits }; - ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); - state.lenbits = opts.bits; - - if (ret) { - strm.msg = 'invalid code lengths set'; - state.mode = BAD; - break; - } - //Tracev((stderr, "inflate: code lengths ok\n")); - state.have = 0; - state.mode = CODELENS; - /* falls through */ - case CODELENS: - while (state.have < state.nlen + state.ndist) { - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if (here_val < 16) { - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.lens[state.have++] = here_val; - } - else { - if (here_val === 16) { - //=== NEEDBITS(here.bits + 2); - n = here_bits + 2; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - if (state.have === 0) { - strm.msg = 'invalid bit length repeat'; - state.mode = BAD; - break; - } - len = state.lens[state.have - 1]; - copy = 3 + (hold & 0x03);//BITS(2); - //--- DROPBITS(2) ---// - hold >>>= 2; - bits -= 2; - //---// - } - else if (here_val === 17) { - //=== NEEDBITS(here.bits + 3); - n = here_bits + 3; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - len = 0; - copy = 3 + (hold & 0x07);//BITS(3); - //--- DROPBITS(3) ---// - hold >>>= 3; - bits -= 3; - //---// - } - else { - //=== NEEDBITS(here.bits + 7); - n = here_bits + 7; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - len = 0; - copy = 11 + (hold & 0x7f);//BITS(7); - //--- DROPBITS(7) ---// - hold >>>= 7; - bits -= 7; - //---// - } - if (state.have + copy > state.nlen + state.ndist) { - strm.msg = 'invalid bit length repeat'; - state.mode = BAD; - break; - } - while (copy--) { - state.lens[state.have++] = len; - } - } - } + if (json.scene !== undefined) { + json.scene = json.scenes[this.json.scene]; + } + } - /* handle error breaks in while */ - if (state.mode === BAD) { break; } + getScene(index) { + return this._get('scenes', index); + } - /* check for end-of-block code (better have one) */ - if (state.lens[256] === 0) { - strm.msg = 'invalid code -- missing end-of-block'; - state.mode = BAD; - break; - } + getNode(index) { + return this._get('nodes', index); + } - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state.lenbits = 9; + getSkin(index) { + return this._get('skins', index); + } - opts = { bits: state.lenbits }; - ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); - // We have separate tables & no pointers. 2 commented lines below not needed. - // state.next_index = opts.table_index; - state.lenbits = opts.bits; - // state.lencode = state.next; + getMesh(index) { + return this._get('meshes', index); + } - if (ret) { - strm.msg = 'invalid literal/lengths set'; - state.mode = BAD; - break; - } + getMaterial(index) { + return this._get('materials', index); + } - state.distbits = 6; - //state.distcode.copy(state.codes); - // Switch to use dynamic table - state.distcode = state.distdyn; - opts = { bits: state.distbits }; - ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); - // We have separate tables & no pointers. 2 commented lines below not needed. - // state.next_index = opts.table_index; - state.distbits = opts.bits; - // state.distcode = state.next; - - if (ret) { - strm.msg = 'invalid distances set'; - state.mode = BAD; - break; - } - //Tracev((stderr, 'inflate: codes ok\n')); - state.mode = LEN_; - if (flush === Z_TREES) { break inf_leave; } - /* falls through */ - case LEN_: - state.mode = LEN; - /* falls through */ - case LEN: - if (have >= 6 && left >= 258) { - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - inflate_fast(strm, _out); - //--- LOAD() --- - put = strm.next_out; - output = strm.output; - left = strm.avail_out; - next = strm.next_in; - input = strm.input; - have = strm.avail_in; - hold = state.hold; - bits = state.bits; - //--- - - if (state.mode === TYPE) { - state.back = -1; - } - break; - } - state.back = 0; - for (;;) { - here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; + getAccessor(index) { + return this._get('accessors', index); + } - if (here_bits <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if (here_op && (here_op & 0xf0) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.lencode[last_val + - ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((last_bits + here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - //--- DROPBITS(last.bits) ---// - hold >>>= last_bits; - bits -= last_bits; - //---// - state.back += last_bits; - } - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.back += here_bits; - state.length = here_val; - if (here_op === 0) { - //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - // "inflate: literal '%c'\n" : - // "inflate: literal 0x%02x\n", here.val)); - state.mode = LIT; - break; - } - if (here_op & 32) { - //Tracevv((stderr, "inflate: end of block\n")); - state.back = -1; - state.mode = TYPE; - break; - } - if (here_op & 64) { - strm.msg = 'invalid literal/length code'; - state.mode = BAD; - break; - } - state.extra = here_op & 15; - state.mode = LENEXT; - /* falls through */ - case LENEXT: - if (state.extra) { - //=== NEEDBITS(state.extra); - n = state.extra; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; - //--- DROPBITS(state.extra) ---// - hold >>>= state.extra; - bits -= state.extra; - //---// - state.back += state.extra; - } - //Tracevv((stderr, "inflate: length %u\n", state.length)); - state.was = state.length; - state.mode = DIST; - /* falls through */ - case DIST: - for (;;) { - here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/ - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - if ((here_op & 0xf0) === 0) { - last_bits = here_bits; - last_op = here_op; - last_val = here_val; - for (;;) { - here = state.distcode[last_val + - ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; - here_bits = here >>> 24; - here_op = (here >>> 16) & 0xff; - here_val = here & 0xffff; - - if ((last_bits + here_bits) <= bits) { break; } - //--- PULLBYTE() ---// - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - //---// - } - //--- DROPBITS(last.bits) ---// - hold >>>= last_bits; - bits -= last_bits; - //---// - state.back += last_bits; - } - //--- DROPBITS(here.bits) ---// - hold >>>= here_bits; - bits -= here_bits; - //---// - state.back += here_bits; - if (here_op & 64) { - strm.msg = 'invalid distance code'; - state.mode = BAD; - break; - } - state.offset = here_val; - state.extra = (here_op) & 15; - state.mode = DISTEXT; - /* falls through */ - case DISTEXT: - if (state.extra) { - //=== NEEDBITS(state.extra); - n = state.extra; - while (bits < n) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; - //--- DROPBITS(state.extra) ---// - hold >>>= state.extra; - bits -= state.extra; - //---// - state.back += state.extra; - } -//#ifdef INFLATE_STRICT - if (state.offset > state.dmax) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break; - } -//#endif - //Tracevv((stderr, "inflate: distance %u\n", state.offset)); - state.mode = MATCH; - /* falls through */ - case MATCH: - if (left === 0) { break inf_leave; } - copy = _out - left; - if (state.offset > copy) { /* copy from window */ - copy = state.offset - copy; - if (copy > state.whave) { - if (state.sane) { - strm.msg = 'invalid distance too far back'; - state.mode = BAD; - break; - } -// (!) This block is disabled in zlib defaults, -// don't enable it for binary compatibility -//#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR -// Trace((stderr, "inflate.c too far\n")); -// copy -= state.whave; -// if (copy > state.length) { copy = state.length; } -// if (copy > left) { copy = left; } -// left -= copy; -// state.length -= copy; -// do { -// output[put++] = 0; -// } while (--copy); -// if (state.length === 0) { state.mode = LEN; } -// break; -//#endif - } - if (copy > state.wnext) { - copy -= state.wnext; - from = state.wsize - copy; - } - else { - from = state.wnext - copy; - } - if (copy > state.length) { copy = state.length; } - from_source = state.window; - } - else { /* copy from output */ - from_source = output; - from = put - state.offset; - copy = state.length; - } - if (copy > left) { copy = left; } - left -= copy; - state.length -= copy; - do { - output[put++] = from_source[from++]; - } while (--copy); - if (state.length === 0) { state.mode = LEN; } - break; - case LIT: - if (left === 0) { break inf_leave; } - output[put++] = state.length; - left--; - state.mode = LEN; - break; - case CHECK: - if (state.wrap) { - //=== NEEDBITS(32); - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - // Use '|' instead of '+' to make sure that result is signed - hold |= input[next++] << bits; - bits += 8; - } - //===// - _out -= left; - strm.total_out += _out; - state.total += _out; - if (_out) { - strm.adler = state.check = - /*UPDATE(state.check, put - _out, _out);*/ - (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out)); - - } - _out = left; - // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too - if ((state.flags ? hold : zswap32(hold)) !== state.check) { - strm.msg = 'incorrect data check'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - //Tracev((stderr, "inflate: check matches trailer\n")); - } - state.mode = LENGTH; - /* falls through */ - case LENGTH: - if (state.wrap && state.flags) { - //=== NEEDBITS(32); - while (bits < 32) { - if (have === 0) { break inf_leave; } - have--; - hold += input[next++] << bits; - bits += 8; - } - //===// - if (hold !== (state.total & 0xffffffff)) { - strm.msg = 'incorrect length check'; - state.mode = BAD; - break; - } - //=== INITBITS(); - hold = 0; - bits = 0; - //===// - //Tracev((stderr, "inflate: length matches trailer\n")); - } - state.mode = DONE; - /* falls through */ - case DONE: - ret = Z_STREAM_END; - break inf_leave; - case BAD: - ret = Z_DATA_ERROR; - break inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - /* falls through */ - default: - return Z_STREAM_ERROR; - } - } - - // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - - //--- RESTORE() --- - strm.next_out = put; - strm.avail_out = left; - strm.next_in = next; - strm.avail_in = have; - state.hold = hold; - state.bits = bits; - //--- - - if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && - (state.mode < CHECK || flush !== Z_FINISH))) { - if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ; - } - _in -= strm.avail_in; - _out -= strm.avail_out; - strm.total_in += _in; - strm.total_out += _out; - state.total += _out; - if (state.wrap && _out) { - strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ - (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out)); - } - strm.data_type = state.bits + (state.last ? 64 : 0) + - (state.mode === TYPE ? 128 : 0) + - (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); - if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) { - ret = Z_BUF_ERROR; - } - return ret; - } - - function inflateEnd(strm) { + getCamera(index) { + return null; + } - if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { - return Z_STREAM_ERROR; - } + getTexture(index) { + return this._get('textures', index); + } - var state = strm.state; - if (state.window) { - state.window = null; - } - strm.state = null; - return Z_OK; - } + getSampler(index) { + return this._get('samplers', index); + } - function inflateGetHeader(strm, head) { - var state; + getImage(index) { + return this._get('images', index); + } - /* check state */ - if (!strm || !strm.state) { return Z_STREAM_ERROR; } - state = strm.state; - if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; } + getBufferView(index) { + return this._get('bufferViews', index); + } - /* save header structure */ - state.head = head; - head.done = false; - return Z_OK; - } + getBuffer(index) { + return this._get('buffers', index); + } - function inflateSetDictionary(strm, dictionary) { - var dictLength = dictionary.length; + _get(array, index) { + if (typeof index === 'object') { + return index; + } - var state; - var dictid; - var ret; + const object = this.json[array] && this.json[array][index]; - /* check state */ - if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR; } - state = strm.state; + if (!object) { + console.warn("glTF file error: Could not find ".concat(array, "[").concat(index, "]")); + } - if (state.wrap !== 0 && state.mode !== DICT) { - return Z_STREAM_ERROR; - } + return object; + } - /* check for correct dictionary identifier */ - if (state.mode === DICT) { - dictid = 1; /* adler32(0, null, 0)*/ - /* dictid = adler32(dictid, dictionary, dictLength); */ - dictid = adler32(dictid, dictionary, dictLength, 0); - if (dictid !== state.check) { - return Z_DATA_ERROR; - } - } - /* copy dictionary to window using updatewindow(), which will amend the - existing dictionary if appropriate */ - ret = updatewindow(strm, dictionary, dictLength, dictLength); - if (ret) { - state.mode = MEM; - return Z_MEM_ERROR; - } - state.havedict = 1; - // Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; - } + _resolveScene(scene, index) { + scene.id = scene.id || "scene-".concat(index); + scene.nodes = (scene.nodes || []).map(node => this.getNode(node)); + return scene; + } - exports.inflateReset = inflateReset; - exports.inflateReset2 = inflateReset2; - exports.inflateResetKeep = inflateResetKeep; - exports.inflateInit = inflateInit; - exports.inflateInit2 = inflateInit2; - exports.inflate = inflate; - exports.inflateEnd = inflateEnd; - exports.inflateGetHeader = inflateGetHeader; - exports.inflateSetDictionary = inflateSetDictionary; - exports.inflateInfo = 'pako inflate (from Nodeca project)'; + _resolveNode(node, index) { + node.id = node.id || "node-".concat(index); - /* Not implemented -exports.inflateCopy = inflateCopy; -exports.inflateGetDictionary = inflateGetDictionary; -exports.inflateMark = inflateMark; -exports.inflatePrime = inflatePrime; -exports.inflateSync = inflateSync; -exports.inflateSyncPoint = inflateSyncPoint; -exports.inflateUndermine = inflateUndermine; -*/ + if (node.children) { + node.children = node.children.map(child => this.getNode(child)); + } - },{"../utils/common":3,"./adler32":5,"./crc32":7,"./inffast":10,"./inftrees":12}],12:[function(require,module,exports){ + if (node.mesh !== undefined) { + node.mesh = this.getMesh(node.mesh); + } else if (node.meshes !== undefined && node.meshes.length) { + node.mesh = node.meshes.reduce((accum, meshIndex) => { + const mesh = this.getMesh(meshIndex); + accum.id = mesh.id; + accum.primitives = accum.primitives.concat(mesh.primitives); + return accum; + }, { + primitives: [] + }); + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - - var utils = require('../utils/common'); - - var MAXBITS = 15; - var ENOUGH_LENS = 852; - var ENOUGH_DISTS = 592; -//var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); - - var CODES = 0; - var LENS = 1; - var DISTS = 2; - - var lbase = [ /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 - ]; + if (node.camera !== undefined) { + node.camera = this.getCamera(node.camera); + } - var lext = [ /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 - ]; + if (node.skin !== undefined) { + node.skin = this.getSkin(node.skin); + } - var dbase = [ /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0 - ]; + return node; + } - var dext = [ /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64 - ]; + _resolveSkin(skin, index) { + skin.id = skin.id || "skin-".concat(index); + skin.inverseBindMatrices = this.getAccessor(skin.inverseBindMatrices); + return skin; + } - module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts) - { - var bits = opts.bits; - //here = opts.here; /* table entry for duplication */ - - var len = 0; /* a code's length in bits */ - var sym = 0; /* index of code symbols */ - var min = 0, max = 0; /* minimum and maximum code lengths */ - var root = 0; /* number of index bits for root table */ - var curr = 0; /* number of index bits for current table */ - var drop = 0; /* code bits to drop for sub-table */ - var left = 0; /* number of prefix codes available */ - var used = 0; /* code entries in table used */ - var huff = 0; /* Huffman code */ - var incr; /* for incrementing code, index */ - var fill; /* index for replicating entries */ - var low; /* low bits for current root entry */ - var mask; /* mask for low root bits */ - var next; /* next available space in table */ - var base = null; /* base value table to use */ - var base_index = 0; -// var shoextra; /* extra bits table to use */ - var end; /* use base and extra for symbol > end */ - var count = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */ - var offs = new utils.Buf16(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */ - var extra = null; - var extra_index = 0; - - var here_bits, here_op, here_val; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ + _resolveMesh(mesh, index) { + mesh.id = mesh.id || "mesh-".concat(index); - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) { - count[len] = 0; - } - for (sym = 0; sym < codes; sym++) { - count[lens[lens_index + sym]]++; - } + if (mesh.primitives) { + mesh.primitives = mesh.primitives.map(primitive => { + primitive = { ...primitive + }; + const attributes = primitive.attributes; + primitive.attributes = {}; - /* bound code lengths, force root to be within code lengths */ - root = bits; - for (max = MAXBITS; max >= 1; max--) { - if (count[max] !== 0) { break; } - } - if (root > max) { - root = max; - } - if (max === 0) { /* no symbols to code at all */ - //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ - //table.bits[opts.table_index] = 1; //here.bits = (var char)1; - //table.val[opts.table_index++] = 0; //here.val = (var short)0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; + for (const attribute in attributes) { + primitive.attributes[attribute] = this.getAccessor(attributes[attribute]); + } + if (primitive.indices !== undefined) { + primitive.indices = this.getAccessor(primitive.indices); + } - //table.op[opts.table_index] = 64; - //table.bits[opts.table_index] = 1; - //table.val[opts.table_index++] = 0; - table[table_index++] = (1 << 24) | (64 << 16) | 0; + if (primitive.material !== undefined) { + primitive.material = this.getMaterial(primitive.material); + } - opts.bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min < max; min++) { - if (count[min] !== 0) { break; } - } - if (root < min) { - root = min; - } + return primitive; + }); + } - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) { - return -1; - } /* over-subscribed */ - } - if (left > 0 && (type === CODES || max !== 1)) { - return -1; /* incomplete set */ - } + return mesh; + } - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) { - offs[len + 1] = offs[len] + count[len]; - } + _resolveMaterial(material, index) { + material.id = material.id || "material-".concat(index); - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) { - if (lens[lens_index + sym] !== 0) { - work[offs[lens[lens_index + sym]]++] = sym; - } - } + if (material.normalTexture) { + material.normalTexture = { ...material.normalTexture + }; + material.normalTexture.texture = this.getTexture(material.normalTexture.index); + } - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. + if (material.occlusionTexture) { + material.occlustionTexture = { ...material.occlustionTexture + }; + material.occlusionTexture.texture = this.getTexture(material.occlusionTexture.index); + } - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. + if (material.emissiveTexture) { + material.emmisiveTexture = { ...material.emmisiveTexture + }; + material.emissiveTexture.texture = this.getTexture(material.emissiveTexture.index); + } - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. + if (!material.emissiveFactor) { + material.emissiveFactor = material.emmisiveTexture ? [1, 1, 1] : [0, 0, 0]; + } - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked for LENS and DIST tables against - the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in - the initial root table size constants. See the comments in inftrees.h - for more information. + if (material.pbrMetallicRoughness) { + material.pbrMetallicRoughness = { ...material.pbrMetallicRoughness + }; + const mr = material.pbrMetallicRoughness; - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ + if (mr.baseColorTexture) { + mr.baseColorTexture = { ...mr.baseColorTexture + }; + mr.baseColorTexture.texture = this.getTexture(mr.baseColorTexture.index); + } - /* set up for code type */ - // poor man optimization - use if-else instead of switch, - // to avoid deopts in old v8 - if (type === CODES) { - base = extra = work; /* dummy value--not used */ - end = 19; - - } else if (type === LENS) { - base = lbase; - base_index -= 257; - extra = lext; - extra_index -= 257; - end = 256; - - } else { /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize opts for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = table_index; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = -1; /* trigger new sub-table when len > root */ - used = 1 << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if ((type === LENS && used > ENOUGH_LENS) || - (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } + if (mr.metallicRoughnessTexture) { + mr.metallicRoughnessTexture = { ...mr.metallicRoughnessTexture + }; + mr.metallicRoughnessTexture.texture = this.getTexture(mr.metallicRoughnessTexture.index); + } + } - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - here_bits = len - drop; - if (work[sym] < end) { - here_op = 0; - here_val = work[sym]; - } - else if (work[sym] > end) { - here_op = extra[extra_index + work[sym]]; - here_val = base[base_index + work[sym]]; - } - else { - here_op = 32 + 64; /* end of block */ - here_val = 0; - } + return material; + } - /* replicate for those indices with low len bits equal to huff */ - incr = 1 << (len - drop); - fill = 1 << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; - } while (fill !== 0); - - /* backwards increment the len-bit code huff */ - incr = 1 << (len - 1); - while (huff & incr) { - incr >>= 1; - } - if (incr !== 0) { - huff &= incr - 1; - huff += incr; - } else { - huff = 0; - } + _resolveAccessor(accessor, index) { + accessor.id = accessor.id || "accessor-".concat(index); - /* go to next symbol, update count, len */ - sym++; - if (--count[len] === 0) { - if (len === max) { break; } - len = lens[lens_index + work[sym]]; - } + if (accessor.bufferView !== undefined) { + accessor.bufferView = this.getBufferView(accessor.bufferView); + } - /* create new sub-table if needed */ - if (len > root && (huff & mask) !== low) { - /* if first time, transition to sub-tables */ - if (drop === 0) { - drop = root; - } + accessor.bytesPerComponent = getBytesFromComponentType(accessor.componentType); + accessor.components = getSizeFromAccessorType(accessor.type); + accessor.bytesPerElement = accessor.bytesPerComponent * accessor.components; - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = 1 << curr; - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) { break; } - curr++; - left <<= 1; - } + if (accessor.bufferView) { + const buffer = accessor.bufferView.buffer; + const { + ArrayType, + byteLength + } = getAccessorArrayTypeAndLength(accessor, accessor.bufferView); + const byteOffset = (accessor.bufferView.byteOffset || 0) + (accessor.byteOffset || 0) + buffer.byteOffset; + let cutBuffer = buffer.arrayBuffer.slice(byteOffset, byteOffset + byteLength); - /* check for enough space */ - used += 1 << curr; - if ((type === LENS && used > ENOUGH_LENS) || - (type === DISTS && used > ENOUGH_DISTS)) { - return 1; - } + if (accessor.bufferView.byteStride) { + cutBuffer = this._getValueFromInterleavedBuffer(buffer, byteOffset, accessor.bufferView.byteStride, accessor.bytesPerElement, accessor.count); + } - /* point entry in root table to sub-table */ - low = huff & mask; - /*table.op[low] = curr; - table.bits[low] = root; - table.val[low] = next - opts.table_index;*/ - table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; - } - } + accessor.value = new ArrayType(cutBuffer); + } - /* fill in remaining table entry if code is incomplete (guaranteed to have - at most one remaining entry, since if the code is incomplete, the - maximum code length that was allowed to get this far is one bit) */ - if (huff !== 0) { - //table.op[next + huff] = 64; /* invalid code marker */ - //table.bits[next + huff] = len - drop; - //table.val[next + huff] = 0; - table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; - } + return accessor; + } - /* set return parameters */ - //opts.table_index += used; - opts.bits = root; - return 0; - }; + _getValueFromInterleavedBuffer(buffer, byteOffset, byteStride, bytesPerElement, count) { + const result = new Uint8Array(count * bytesPerElement); - },{"../utils/common":3}],13:[function(require,module,exports){ + for (let i = 0; i < count; i++) { + const elementOffset = byteOffset + i * byteStride; + result.set(new Uint8Array(buffer.arrayBuffer.slice(elementOffset, elementOffset + bytesPerElement)), i * bytesPerElement); + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - - module.exports = { - 2: 'need dictionary', /* Z_NEED_DICT 2 */ - 1: 'stream end', /* Z_STREAM_END 1 */ - 0: '', /* Z_OK 0 */ - '-1': 'file error', /* Z_ERRNO (-1) */ - '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ - '-3': 'data error', /* Z_DATA_ERROR (-3) */ - '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ - '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ - '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ - }; + return result.buffer; + } - },{}],14:[function(require,module,exports){ + _resolveTexture(texture, index) { + texture.id = texture.id || "texture-".concat(index); + texture.sampler = 'sampler' in texture ? this.getSampler(texture.sampler) : DEFAULT_SAMPLER; + texture.source = this.getImage(texture.source); + return texture; + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. + _resolveSampler(sampler, index) { + sampler.id = sampler.id || "sampler-".concat(index); + sampler.parameters = {}; - /* eslint-disable space-unary-ops */ + for (const key in sampler) { + const glEnum = this._enumSamplerParameter(key); - var utils = require('../utils/common'); + if (glEnum !== undefined) { + sampler.parameters[glEnum] = sampler[key]; + } + } - /* Public constants ==========================================================*/ - /* ===========================================================================*/ + return sampler; + } + _enumSamplerParameter(key) { + return SAMPLER_PARAMETER_GLTF_TO_GL[key]; + } -//var Z_FILTERED = 1; -//var Z_HUFFMAN_ONLY = 2; -//var Z_RLE = 3; - var Z_FIXED = 4; -//var Z_DEFAULT_STRATEGY = 0; + _resolveImage(image, index) { + image.id = image.id || "image-".concat(index); - /* Possible values of the data_type field (though see inflate()) */ - var Z_BINARY = 0; - var Z_TEXT = 1; -//var Z_ASCII = 1; // = Z_TEXT - var Z_UNKNOWN = 2; + if (image.bufferView !== undefined) { + image.bufferView = this.getBufferView(image.bufferView); + } - /*============================================================================*/ + const preloadedImage = this.images[index]; + if (preloadedImage) { + image.image = preloadedImage; + } - function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } } + return image; + } -// From zutil.h + _resolveBufferView(bufferView, index) { + const bufferIndex = bufferView.buffer; + const result = { + id: "bufferView-".concat(index), + ...bufferView, + buffer: this.buffers[bufferIndex] + }; + const arrayBuffer = this.buffers[bufferIndex].arrayBuffer; + let byteOffset = this.buffers[bufferIndex].byteOffset || 0; - var STORED_BLOCK = 0; - var STATIC_TREES = 1; - var DYN_TREES = 2; - /* The three kinds of block type */ + if ('byteOffset' in bufferView) { + byteOffset += bufferView.byteOffset; + } - var MIN_MATCH = 3; - var MAX_MATCH = 258; - /* The minimum and maximum match lengths */ + result.data = new Uint8Array(arrayBuffer, byteOffset, bufferView.byteLength); + return result; + } -// From deflate.h - /* =========================================================================== - * Internal compression state. - */ + _resolveCamera(camera, index) { + camera.id = camera.id || "camera-".concat(index); - var LENGTH_CODES = 29; - /* number of length codes, not counting the special END_BLOCK code */ + if (camera.perspective) ; - var LITERALS = 256; - /* number of literal bytes 0..255 */ + if (camera.orthographic) ; - var L_CODES = LITERALS + 1 + LENGTH_CODES; - /* number of Literal or Length codes, including the END_BLOCK code */ + return camera; + } - var D_CODES = 30; - /* number of distance codes */ +} - var BL_CODES = 19; - /* number of codes used to transfer the bit lengths */ +function postProcessGLTF(gltf, options) { + return new GLTFPostProcessor().postProcess(gltf, options); +} - var HEAP_SIZE = 2 * L_CODES + 1; - /* maximum heap size */ +const MAGIC_glTF = 0x676c5446; +const GLB_FILE_HEADER_SIZE = 12; +const GLB_CHUNK_HEADER_SIZE = 8; +const GLB_CHUNK_TYPE_JSON = 0x4e4f534a; +const GLB_CHUNK_TYPE_BIN = 0x004e4942; +const GLB_CHUNK_TYPE_JSON_XVIZ_DEPRECATED = 0; +const GLB_CHUNK_TYPE_BIX_XVIZ_DEPRECATED = 1; +const GLB_V1_CONTENT_FORMAT_JSON = 0x0; +const LE = true; - var MAX_BITS = 15; - /* All codes must not exceed MAX_BITS bits */ +function getMagicString(dataView, byteOffset = 0) { + return "".concat(String.fromCharCode(dataView.getUint8(byteOffset + 0))).concat(String.fromCharCode(dataView.getUint8(byteOffset + 1))).concat(String.fromCharCode(dataView.getUint8(byteOffset + 2))).concat(String.fromCharCode(dataView.getUint8(byteOffset + 3))); +} - var Buf_size = 16; - /* size of bit buffer in bi_buf */ +function isGLB(arrayBuffer, byteOffset = 0, options = {}) { + const dataView = new DataView(arrayBuffer); + const { + magic = MAGIC_glTF + } = options; + const magic1 = dataView.getUint32(byteOffset, false); + return magic1 === magic || magic1 === MAGIC_glTF; +} +function parseGLBSync(glb, arrayBuffer, byteOffset = 0, options = {}) { + const dataView = new DataView(arrayBuffer); + const type = getMagicString(dataView, byteOffset + 0); + const version = dataView.getUint32(byteOffset + 4, LE); + const byteLength = dataView.getUint32(byteOffset + 8, LE); + Object.assign(glb, { + header: { + byteOffset, + byteLength, + hasBinChunk: false + }, + type, + version, + json: {}, + binChunks: [] + }); + byteOffset += GLB_FILE_HEADER_SIZE; + switch (glb.version) { + case 1: + return parseGLBV1(glb, dataView, byteOffset); - /* =========================================================================== - * Constants - */ + case 2: + return parseGLBV2(glb, dataView, byteOffset, options = {}); - var MAX_BL_BITS = 7; - /* Bit length codes must not exceed MAX_BL_BITS bits */ + default: + throw new Error("Invalid GLB version ".concat(glb.version, ". Only supports v1 and v2.")); + } +} - var END_BLOCK = 256; - /* end of block literal code */ +function parseGLBV1(glb, dataView, byteOffset) { + assert$5(glb.header.byteLength > GLB_FILE_HEADER_SIZE + GLB_CHUNK_HEADER_SIZE); + const contentLength = dataView.getUint32(byteOffset + 0, LE); + const contentFormat = dataView.getUint32(byteOffset + 4, LE); + byteOffset += GLB_CHUNK_HEADER_SIZE; + assert$5(contentFormat === GLB_V1_CONTENT_FORMAT_JSON); + parseJSONChunk(glb, dataView, byteOffset, contentLength); + byteOffset += contentLength; + byteOffset += parseBINChunk(glb, dataView, byteOffset, glb.header.byteLength); + return byteOffset; +} - var REP_3_6 = 16; - /* repeat previous bit length 3-6 times (2 bits of repeat count) */ +function parseGLBV2(glb, dataView, byteOffset, options) { + assert$5(glb.header.byteLength > GLB_FILE_HEADER_SIZE + GLB_CHUNK_HEADER_SIZE); + parseGLBChunksSync(glb, dataView, byteOffset, options); + return byteOffset + glb.header.byteLength; +} - var REPZ_3_10 = 17; - /* repeat a zero length 3-10 times (3 bits of repeat count) */ +function parseGLBChunksSync(glb, dataView, byteOffset, options) { + while (byteOffset + 8 <= glb.header.byteLength) { + const chunkLength = dataView.getUint32(byteOffset + 0, LE); + const chunkFormat = dataView.getUint32(byteOffset + 4, LE); + byteOffset += GLB_CHUNK_HEADER_SIZE; - var REPZ_11_138 = 18; - /* repeat a zero length 11-138 times (7 bits of repeat count) */ + switch (chunkFormat) { + case GLB_CHUNK_TYPE_JSON: + parseJSONChunk(glb, dataView, byteOffset, chunkLength); + break; - /* eslint-disable comma-spacing,array-bracket-spacing */ - var extra_lbits = /* extra bits for each length code */ - [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]; + case GLB_CHUNK_TYPE_BIN: + parseBINChunk(glb, dataView, byteOffset, chunkLength); + break; - var extra_dbits = /* extra bits for each distance code */ - [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]; + case GLB_CHUNK_TYPE_JSON_XVIZ_DEPRECATED: + if (!options.strict) { + parseJSONChunk(glb, dataView, byteOffset, chunkLength); + } - var extra_blbits = /* extra bits for each bit length code */ - [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]; + break; - var bl_order = - [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]; - /* eslint-enable comma-spacing,array-bracket-spacing */ + case GLB_CHUNK_TYPE_BIX_XVIZ_DEPRECATED: + if (!options.strict) { + parseBINChunk(glb, dataView, byteOffset, chunkLength); + } - /* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ + break; + } - /* =========================================================================== - * Local data. These are initialized only once. - */ + byteOffset += padToNBytes(chunkLength, 4); + } -// We pre-fill arrays with 0 to avoid uninitialized gaps + return byteOffset; +} - var DIST_CODE_LEN = 512; /* see definition of array dist_code below */ +function parseJSONChunk(glb, dataView, byteOffset, chunkLength) { + const jsonChunk = new Uint8Array(dataView.buffer, byteOffset, chunkLength); + const textDecoder = new TextDecoder('utf8'); + const jsonText = textDecoder.decode(jsonChunk); + glb.json = JSON.parse(jsonText); + return padToNBytes(chunkLength, 4); +} -// !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 - var static_ltree = new Array((L_CODES + 2) * 2); - zero(static_ltree); - /* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ +function parseBINChunk(glb, dataView, byteOffset, chunkLength) { + glb.header.hasBinChunk = true; + glb.binChunks.push({ + byteOffset, + byteLength: chunkLength, + arrayBuffer: dataView.buffer + }); + return padToNBytes(chunkLength, 4); +} - var static_dtree = new Array(D_CODES * 2); - zero(static_dtree); - /* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ +async function parseGLTF$1(gltf, arrayBufferOrString, byteOffset = 0, options, context) { + var _options$gltf, _options$gltf2, _options$gltf3, _options$gltf4; - var _dist_code = new Array(DIST_CODE_LEN); - zero(_dist_code); - /* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ + parseGLTFContainerSync(gltf, arrayBufferOrString, byteOffset, options); + normalizeGLTFV1(gltf, { + normalize: options === null || options === void 0 ? void 0 : (_options$gltf = options.gltf) === null || _options$gltf === void 0 ? void 0 : _options$gltf.normalize + }); + preprocessExtensions(gltf, options, context); + const promises = []; - var _length_code = new Array(MAX_MATCH - MIN_MATCH + 1); - zero(_length_code); - /* length code for each normalized match length (0 == MIN_MATCH) */ + if (options !== null && options !== void 0 && (_options$gltf2 = options.gltf) !== null && _options$gltf2 !== void 0 && _options$gltf2.loadBuffers && gltf.json.buffers) { + await loadBuffers(gltf, options, context); + } - var base_length = new Array(LENGTH_CODES); - zero(base_length); - /* First normalized length for each code (0 = MIN_MATCH) */ + if (options !== null && options !== void 0 && (_options$gltf3 = options.gltf) !== null && _options$gltf3 !== void 0 && _options$gltf3.loadImages) { + const promise = loadImages(gltf, options, context); + promises.push(promise); + } - var base_dist = new Array(D_CODES); - zero(base_dist); - /* First normalized distance for each code (0 = distance of 1) */ + const promise = decodeExtensions(gltf, options, context); + promises.push(promise); + await Promise.all(promises); + return options !== null && options !== void 0 && (_options$gltf4 = options.gltf) !== null && _options$gltf4 !== void 0 && _options$gltf4.postProcess ? postProcessGLTF(gltf, options) : gltf; +} +function parseGLTFContainerSync(gltf, data, byteOffset, options) { + if (options.uri) { + gltf.baseUri = options.uri; + } - function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { + if (data instanceof ArrayBuffer && !isGLB(data, byteOffset, options)) { + const textDecoder = new TextDecoder(); + data = textDecoder.decode(data); + } - this.static_tree = static_tree; /* static tree or NULL */ - this.extra_bits = extra_bits; /* extra bits for each code or NULL */ - this.extra_base = extra_base; /* base index for extra_bits */ - this.elems = elems; /* max number of elements in the tree */ - this.max_length = max_length; /* max bit length for the codes */ + if (typeof data === 'string') { + gltf.json = parseJSON(data); + } else if (data instanceof ArrayBuffer) { + const glb = {}; + byteOffset = parseGLBSync(glb, data, byteOffset, options.glb); + assert$1(glb.type === 'glTF', "Invalid GLB magic string ".concat(glb.type)); + gltf._glb = glb; + gltf.json = glb.json; + } else { + assert$1(false, 'GLTF: must be ArrayBuffer or string'); + } - // show if `static_tree` has data or dummy - needed for monomorphic objects - this.has_stree = static_tree && static_tree.length; - } + const buffers = gltf.json.buffers || []; + gltf.buffers = new Array(buffers.length).fill(null); + if (gltf._glb && gltf._glb.header.hasBinChunk) { + const { + binChunks + } = gltf._glb; + gltf.buffers[0] = { + arrayBuffer: binChunks[0].arrayBuffer, + byteOffset: binChunks[0].byteOffset, + byteLength: binChunks[0].byteLength + }; + } - var static_l_desc; - var static_d_desc; - var static_bl_desc; + const images = gltf.json.images || []; + gltf.images = new Array(images.length).fill({}); +} +async function loadBuffers(gltf, options, context) { + const buffers = gltf.json.buffers || []; - function TreeDesc(dyn_tree, stat_desc) { - this.dyn_tree = dyn_tree; /* the dynamic tree */ - this.max_code = 0; /* largest code with non zero frequency */ - this.stat_desc = stat_desc; /* the corresponding static tree */ - } + for (let i = 0; i < buffers.length; ++i) { + const buffer = buffers[i]; + if (buffer.uri) { + var _context$fetch, _response$arrayBuffer; + const { + fetch + } = context; + assert$1(fetch); + const uri = resolveUrl(buffer.uri, options); + const response = await (context === null || context === void 0 ? void 0 : (_context$fetch = context.fetch) === null || _context$fetch === void 0 ? void 0 : _context$fetch.call(context, uri)); + const arrayBuffer = await (response === null || response === void 0 ? void 0 : (_response$arrayBuffer = response.arrayBuffer) === null || _response$arrayBuffer === void 0 ? void 0 : _response$arrayBuffer.call(response)); + gltf.buffers[i] = { + arrayBuffer, + byteOffset: 0, + byteLength: arrayBuffer.byteLength + }; + delete buffer.uri; + } else if (gltf.buffers[i] === null) { + gltf.buffers[i] = { + arrayBuffer: new ArrayBuffer(buffer.byteLength), + byteOffset: 0, + byteLength: buffer.byteLength + }; + } + } +} - function d_code(dist) { - return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; - } +async function loadImages(gltf, options, context) { + const imageIndices = getReferencesImageIndices(gltf); + const images = gltf.json.images || []; + const promises = []; + for (const imageIndex of imageIndices) { + promises.push(loadImage(gltf, images[imageIndex], imageIndex, options, context)); + } - /* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ - function put_short(s, w) { -// put_byte(s, (uch)((w) & 0xff)); -// put_byte(s, (uch)((ush)(w) >> 8)); - s.pending_buf[s.pending++] = (w) & 0xff; - s.pending_buf[s.pending++] = (w >>> 8) & 0xff; - } + return await Promise.all(promises); +} +function getReferencesImageIndices(gltf) { + const imageIndices = new Set(); + const textures = gltf.json.textures || []; - /* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ - function send_bits(s, value, length) { - if (s.bi_valid > (Buf_size - length)) { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - put_short(s, s.bi_buf); - s.bi_buf = value >> (Buf_size - s.bi_valid); - s.bi_valid += length - Buf_size; - } else { - s.bi_buf |= (value << s.bi_valid) & 0xffff; - s.bi_valid += length; - } - } + for (const texture of textures) { + if (texture.source !== undefined) { + imageIndices.add(texture.source); + } + } + return Array.from(imageIndices).sort(); +} - function send_code(s, c, tree) { - send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/); - } +async function loadImage(gltf, image, index, options, context) { + const { + fetch, + parse + } = context; + let arrayBuffer; + if (image.uri) { + const uri = resolveUrl(image.uri, options); + const response = await fetch(uri); + arrayBuffer = await response.arrayBuffer(); + } - /* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ - function bi_reverse(code, len) { - var res = 0; - do { - res |= code & 1; - code >>>= 1; - res <<= 1; - } while (--len > 0); - return res >>> 1; - } + if (Number.isFinite(image.bufferView)) { + const array = getTypedArrayForBufferView(gltf.json, gltf.buffers, image.bufferView); + arrayBuffer = sliceArrayBuffer(array.buffer, array.byteOffset, array.byteLength); + } + assert$1(arrayBuffer, 'glTF image has no data'); + let parsedImage = await parse(arrayBuffer, [ImageLoader, BasisLoader], { + mimeType: image.mimeType, + basis: options.basis || { + format: selectSupportedBasisFormat() + } + }, context); - /* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ - function bi_flush(s) { - if (s.bi_valid === 16) { - put_short(s, s.bi_buf); - s.bi_buf = 0; - s.bi_valid = 0; + if (parsedImage && parsedImage[0]) { + parsedImage = { + compressed: true, + mipmaps: false, + width: parsedImage[0].width, + height: parsedImage[0].height, + data: parsedImage[0] + }; + } - } else if (s.bi_valid >= 8) { - s.pending_buf[s.pending++] = s.bi_buf & 0xff; - s.bi_buf >>= 8; - s.bi_valid -= 8; - } - } + gltf.images = gltf.images || []; + gltf.images[index] = parsedImage; +} +const GLTFLoader = { + name: 'glTF', + id: 'gltf', + module: 'gltf', + version: VERSION$5, + extensions: ['gltf', 'glb'], + mimeTypes: ['model/gltf+json', 'model/gltf-binary'], + text: true, + binary: true, + tests: ['glTF'], + parse: parse$1, + options: { + gltf: { + normalize: true, + loadBuffers: true, + loadImages: true, + decompressMeshes: true, + postProcess: true + }, + log: console + }, + deprecatedOptions: { + fetchImages: 'gltf.loadImages', + createImages: 'gltf.loadImages', + decompress: 'gltf.decompressMeshes', + postProcess: 'gltf.postProcess', + gltf: { + decompress: 'gltf.decompressMeshes' + } + } +}; +async function parse$1(arrayBuffer, options = {}, context) { + options = { ...GLTFLoader.options, + ...options + }; + options.gltf = { ...GLTFLoader.options.gltf, + ...options.gltf + }; + const { + byteOffset = 0 + } = options; + const gltf = {}; + return await parseGLTF$1(gltf, arrayBuffer, byteOffset, options, context); +} - /* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. +/** + * @private */ - function gen_bitlen(s, desc) -// deflate_state *s; -// tree_desc *desc; /* the tree descriptor */ - { - var tree = desc.dyn_tree; - var max_code = desc.max_code; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var extra = desc.stat_desc.extra_bits; - var base = desc.stat_desc.extra_base; - var max_length = desc.stat_desc.max_length; - var h; /* heap index */ - var n, m; /* iterate over the tree elements */ - var bits; /* bit length */ - var xbits; /* extra bits */ - var f; /* frequency */ - var overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) { - s.bl_count[bits] = 0; - } - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */ - - for (h = s.heap_max + 1; h < HEAP_SIZE; h++) { - n = s.heap[h]; - bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; - if (bits > max_length) { - bits = max_length; - overflow++; - } - tree[n * 2 + 1]/*.Len*/ = bits; - /* We overwrite tree[n].Dad which is no longer needed */ +class GLTFVBOSceneModelLoader { - if (n > max_code) { continue; } /* not a leaf node */ + constructor(cfg) { + } - s.bl_count[bits]++; - xbits = 0; - if (n >= base) { - xbits = extra[n - base]; + load(plugin, sceneModel, src, options, ok, error) { + options = options || {}; + loadGLTF(plugin, sceneModel, src, options, function () { + core.scheduleTask(function () { + sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events + sceneModel.fire("loaded", true, false); + }); + if (ok) { + ok(); } - f = tree[n * 2]/*.Freq*/; - s.opt_len += f * (bits + xbits); - if (has_stree) { - s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits); + }, + function (msg) { + plugin.error(msg); + if (error) { + error(msg); } - } - if (overflow === 0) { return; } - - // Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ + sceneModel.fire("error", msg); + }); + } - /* Find the first bit length which could increase: */ - do { - bits = max_length - 1; - while (s.bl_count[bits] === 0) { bits--; } - s.bl_count[bits]--; /* move one leaf down the tree */ - s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ - s.bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits !== 0; bits--) { - n = s.bl_count[bits]; - while (n !== 0) { - m = s.heap[--h]; - if (m > max_code) { continue; } - if (tree[m * 2 + 1]/*.Len*/ !== bits) { - // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/; - tree[m * 2 + 1]/*.Len*/ = bits; - } - n--; + parse(plugin, sceneModel, gltf, options, ok, error) { + options = options || {}; + parseGLTF(plugin, gltf, "", options, sceneModel, function () { + sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events + sceneModel.fire("loaded", true, false); + if (ok) { + ok(); } - } - } - + }); + } +} - /* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ - function gen_codes(tree, max_code, bl_count) -// ct_data *tree; /* the tree to decorate */ -// int max_code; /* largest code with non zero frequency */ -// ushf *bl_count; /* number of codes at each bit length */ - { - var next_code = new Array(MAX_BITS + 1); /* next code value for each bit length */ - var code = 0; /* running code value */ - var bits; /* bit index */ - var n; /* code index */ +function loadGLTF(plugin, sceneModel, src, options, ok, error) { + const spinner = plugin.viewer.scene.canvas.spinner; + spinner.processes++; + const isGLB = (src.split('.').pop() === "glb"); + if (isGLB) { + plugin.dataSource.getGLB(src, (arrayBuffer) => { // OK + options.basePath = getBasePath(src); + parseGLTF(plugin, arrayBuffer, src, options, sceneModel, ok); + spinner.processes--; + }, + (err) => { + spinner.processes--; + error(err); + }); + } else { + plugin.dataSource.getGLTF(src, (json) => { // OK + options.basePath = getBasePath(src); + parseGLTF(plugin, json, src, options, sceneModel, ok); + spinner.processes--; + }, + (err) => { + spinner.processes--; + error(err); + }); + } +} - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits - 1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - //Assert (code + bl_count[MAX_BITS]-1 == (1< { + const ctx = { + src: src, + loadBuffer: options.loadBuffer, + basePath: options.basePath, + handlenode: options.handlenode, + gltfData: gltfData, + scene: sceneModel.scene, + plugin: plugin, + sceneModel: sceneModel, + //geometryCreated: {}, + numObjects: 0, + nodes: [], + nextId: 0 + }; + loadTextures(ctx); + loadMaterials(ctx); + loadDefaultScene(ctx); + sceneModel.finalize(); + spinner.processes--; + ok(); + }); +} - //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", - // n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); - } +function loadTextures(ctx) { + const gltfData = ctx.gltfData; + const textures = gltfData.textures; + if (textures) { + for (let i = 0, len = textures.length; i < len; i++) { + loadTexture(ctx, textures[i]); } + } +} +function loadTexture(ctx, texture) { + if (!texture.source || !texture.source.image) { + return; + } + const textureId = `texture-${ctx.nextId++}`; - /* =========================================================================== - * Initialize the various 'constant' tables. - */ - function tr_static_init() { - var n; /* iterates over tree elements */ - var bits; /* bit counter */ - var length; /* length value */ - var code; /* code value */ - var dist; /* distance index */ - var bl_count = new Array(MAX_BITS + 1); - /* number of codes at each bit length for an optimal tree */ - - // do check in _tr_init() - //if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ - /*#ifdef NO_INIT_GLOBAL_POINTERS - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; -#endif*/ - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES - 1; code++) { - base_length[code] = length; - for (n = 0; n < (1 << extra_lbits[code]); n++) { - _length_code[length++] = code; - } - } - //Assert (length == 256, "tr_static_init: length != 256"); - /* Note that the length 255 (match length 258) can be represented - * in two different ways: code 284 + 5 bits or code 285, so we - * overwrite length_code[255] to use the best encoding: - */ - _length_code[length - 1] = code; - - /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ - dist = 0; - for (code = 0; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1 << extra_dbits[code]); n++) { - _dist_code[dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: dist != 256"); - dist >>= 7; /* from now on, all distances are divided by 128 */ - for (; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { - _dist_code[256 + dist++] = code; - } - } - //Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) { - bl_count[bits] = 0; - } - - n = 0; - while (n <= 143) { - static_ltree[n * 2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - while (n <= 255) { - static_ltree[n * 2 + 1]/*.Len*/ = 9; - n++; - bl_count[9]++; - } - while (n <= 279) { - static_ltree[n * 2 + 1]/*.Len*/ = 7; - n++; - bl_count[7]++; - } - while (n <= 287) { - static_ltree[n * 2 + 1]/*.Len*/ = 8; - n++; - bl_count[8]++; - } - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes(static_ltree, L_CODES + 1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n * 2 + 1]/*.Len*/ = 5; - static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5); - } - - // Now data ready and we can init static trees - static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS + 1, L_CODES, MAX_BITS); - static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS); - static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS); + let minFilter = NearestMipMapLinearFilter; + switch (texture.sampler.minFilter) { + case 9728: + minFilter = NearestFilter; + break; + case 9729: + minFilter = LinearFilter; + break; + case 9984: + minFilter = NearestMipMapNearestFilter; + break; + case 9985: + minFilter = LinearMipMapNearestFilter; + break; + case 9986: + minFilter = NearestMipMapLinearFilter; + break; + case 9987: + minFilter = LinearMipMapLinearFilter; + break; + } - //static_init_done = true; - } + let magFilter = LinearFilter; + switch (texture.sampler.magFilter) { + case 9728: + magFilter = NearestFilter; + break; + case 9729: + magFilter = LinearFilter; + break; + } + let wrapS = RepeatWrapping; + switch (texture.sampler.wrapS) { + case 33071: + wrapS = ClampToEdgeWrapping; + break; + case 33648: + wrapS = MirroredRepeatWrapping; + break; + case 10497: + wrapS = RepeatWrapping; + break; + } - /* =========================================================================== - * Initialize a new block. - */ - function init_block(s) { - var n; /* iterates over tree elements */ + let wrapT = RepeatWrapping; + switch (texture.sampler.wrapT) { + case 33071: + wrapT = ClampToEdgeWrapping; + break; + case 33648: + wrapT = MirroredRepeatWrapping; + break; + case 10497: + wrapT = RepeatWrapping; + break; + } - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; } - for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; } - for (n = 0; n < BL_CODES; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; } + let wrapR = RepeatWrapping; + switch (texture.sampler.wrapR) { + case 33071: + wrapR = ClampToEdgeWrapping; + break; + case 33648: + wrapR = MirroredRepeatWrapping; + break; + case 10497: + wrapR = RepeatWrapping; + break; + } + ctx.sceneModel.createTexture({ + id: textureId, + image: texture.source.image, + flipY: !!texture.flipY, + minFilter, + magFilter, + wrapS, + wrapT, + wrapR, + encoding: sRGBEncoding + }); + texture._textureId = textureId; +} - s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1; - s.opt_len = s.static_len = 0; - s.last_lit = s.matches = 0; +function loadMaterials(ctx) { + const gltfData = ctx.gltfData; + const materials = gltfData.materials; + if (materials) { + for (let i = 0, len = materials.length; i < len; i++) { + const material = materials[i]; + material._textureSetId = loadTextureSet(ctx, material); + material._attributes = loadMaterialAttributes(ctx, material); } + } +} - - /* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ - function bi_windup(s) - { - if (s.bi_valid > 8) { - put_short(s, s.bi_buf); - } else if (s.bi_valid > 0) { - //put_byte(s, (Byte)s->bi_buf); - s.pending_buf[s.pending++] = s.bi_buf; +function loadTextureSet(ctx, material) { + const textureSetCfg = {}; + if (material.normalTexture) { + textureSetCfg.normalTextureId = material.normalTexture.texture._textureId; + } + if (material.occlusionTexture) { + textureSetCfg.occlusionTextureId = material.occlusionTexture.texture._textureId; + } + if (material.emissiveTexture) { + textureSetCfg.emissiveTextureId = material.emissiveTexture.texture._textureId; + } + // const alphaMode = material.alphaMode; + // switch (alphaMode) { + // case "NORMAL_OPAQUE": + // materialCfg.alphaMode = "opaque"; + // break; + // case "MASK": + // materialCfg.alphaMode = "mask"; + // break; + // case "BLEND": + // materialCfg.alphaMode = "blend"; + // break; + // default: + // } + // const alphaCutoff = material.alphaCutoff; + // if (alphaCutoff !== undefined) { + // materialCfg.alphaCutoff = alphaCutoff; + // } + const metallicPBR = material.pbrMetallicRoughness; + if (material.pbrMetallicRoughness) { + const pbrMetallicRoughness = material.pbrMetallicRoughness; + const baseColorTexture = pbrMetallicRoughness.baseColorTexture || pbrMetallicRoughness.colorTexture; + if (baseColorTexture) { + if (baseColorTexture.texture) { + textureSetCfg.colorTextureId = baseColorTexture.texture._textureId; + } else { + textureSetCfg.colorTextureId = ctx.gltfData.textures[baseColorTexture.index]._textureId; } - s.bi_buf = 0; - s.bi_valid = 0; } - - /* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ - function copy_block(s, buf, len, header) -//DeflateState *s; -//charf *buf; /* the input data */ -//unsigned len; /* its length */ -//int header; /* true if block header must be written */ - { - bi_windup(s); /* align on byte boundary */ - - if (header) { - put_short(s, len); - put_short(s, ~len); - } -// while (len--) { -// put_byte(s, *buf++); -// } - utils.arraySet(s.pending_buf, s.window, buf, len, s.pending); - s.pending += len; + if (metallicPBR.metallicRoughnessTexture) { + textureSetCfg.metallicRoughnessTextureId = metallicPBR.metallicRoughnessTexture.texture._textureId; } - - /* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ - function smaller(tree, n, m, depth) { - var _n2 = n * 2; - var _m2 = m * 2; - return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || - (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); - } - - /* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ - function pqdownheap(s, tree, k) -// deflate_state *s; -// ct_data *tree; /* the tree to restore */ -// int k; /* node to move down */ - { - var v = s.heap[k]; - var j = k << 1; /* left son of k */ - while (j <= s.heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s.heap_len && - smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s.heap[j], s.depth)) { break; } - - /* Exchange v with the smallest son */ - s.heap[k] = s.heap[j]; - k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; + } + const extensions = material.extensions; + if (extensions) { + const specularPBR = extensions["KHR_materials_pbrSpecularGlossiness"]; + if (specularPBR) { + specularPBR.specularTexture; + const specularColorTexture = specularPBR.specularColorTexture; + if (specularColorTexture !== null && specularColorTexture !== undefined) { + textureSetCfg.colorTextureId = ctx.gltfData.textures[specularColorTexture.index]._textureId; } - s.heap[k] = v; } + } + if (textureSetCfg.normalTextureId !== undefined || + textureSetCfg.occlusionTextureId !== undefined || + textureSetCfg.emissiveTextureId !== undefined || + textureSetCfg.colorTextureId !== undefined || + textureSetCfg.metallicRoughnessTextureId !== undefined) { + textureSetCfg.id = `textureSet-${ctx.nextId++};`; + ctx.sceneModel.createTextureSet(textureSetCfg); + return textureSetCfg.id; + } + return null; +} - -// inlined manually -// var SMALLEST = 1; - - /* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ - function compress_block(s, ltree, dtree) -// deflate_state *s; -// const ct_data *ltree; /* literal tree */ -// const ct_data *dtree; /* distance tree */ - { - var dist; /* distance of matched string */ - var lc; /* match length or unmatched char (if dist == 0) */ - var lx = 0; /* running index in l_buf */ - var code; /* the code to send */ - var extra; /* number of extra bits to send */ - - if (s.last_lit !== 0) { - do { - dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]); - lc = s.pending_buf[s.l_buf + lx]; - lx++; - - if (dist === 0) { - send_code(s, lc, ltree); /* send a literal byte */ - //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code + LITERALS + 1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra !== 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - //Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra !== 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - // "pendingBuf overflow"); - - } while (lx < s.last_lit); +function loadMaterialAttributes(ctx, material) { // Substitute RGBA for material, to use fast flat shading instead + const extensions = material.extensions; + const materialAttributes = { + color: new Float32Array([1, 1, 1, 1]), + opacity: 1, + metallic: 0, + roughness: 1 + }; + if (extensions) { + const specularPBR = extensions["KHR_materials_pbrSpecularGlossiness"]; + if (specularPBR) { + const diffuseFactor = specularPBR.diffuseFactor; + if (diffuseFactor !== null && diffuseFactor !== undefined) { + materialAttributes.color.set(diffuseFactor); } - - send_code(s, END_BLOCK, ltree); } - - - /* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ - function build_tree(s, desc) -// deflate_state *s; -// tree_desc *desc; /* the tree descriptor */ - { - var tree = desc.dyn_tree; - var stree = desc.stat_desc.static_tree; - var has_stree = desc.stat_desc.has_stree; - var elems = desc.stat_desc.elems; - var n, m; /* iterate over heap elements */ - var max_code = -1; /* largest code with non zero frequency */ - var node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s.heap_len = 0; - s.heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n * 2]/*.Freq*/ !== 0) { - s.heap[++s.heap_len] = max_code = n; - s.depth[n] = 0; - - } else { - tree[n * 2 + 1]/*.Len*/ = 0; + const common = extensions["KHR_materials_common"]; + if (common) { + const technique = common.technique; + const values = common.values || {}; + const blinn = technique === "BLINN"; + const phong = technique === "PHONG"; + const lambert = technique === "LAMBERT"; + const diffuse = values.diffuse; + if (diffuse && (blinn || phong || lambert)) { + if (!utils.isString(diffuse)) { + materialAttributes.color.set(diffuse); } } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s.heap_len < 2) { - node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); - tree[node * 2]/*.Freq*/ = 1; - s.depth[node] = 0; - s.opt_len--; - - if (has_stree) { - s.static_len -= stree[node * 2 + 1]/*.Len*/; - } - /* node is 0 or 1 so it does not have extra bits */ + const transparency = values.transparency; + if (transparency !== null && transparency !== undefined) { + materialAttributes.opacity = transparency; + } + const transparent = values.transparent; + if (transparent !== null && transparent !== undefined) { + materialAttributes.opacity = transparent; } - desc.max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - //pqremove(s, tree, n); /* n = node of least frequency */ - /*** pqremove ***/ - n = s.heap[1/*SMALLEST*/]; - s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; - pqdownheap(s, tree, 1/*SMALLEST*/); - /***/ - - m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ - - s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ - s.heap[--s.heap_max] = m; - - /* Create a new node father of n and m */ - tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; - s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; - tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node; - - /* and insert the new node in the heap */ - s.heap[1/*SMALLEST*/] = node++; - pqdownheap(s, tree, 1/*SMALLEST*/); - - } while (s.heap_len >= 2); - - s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes(tree, max_code, s.bl_count); } + } + const metallicPBR = material.pbrMetallicRoughness; + if (metallicPBR) { + const baseColorFactor = metallicPBR.baseColorFactor; + if (baseColorFactor) { + materialAttributes.color[0] = baseColorFactor[0]; + materialAttributes.color[1] = baseColorFactor[1]; + materialAttributes.color[2] = baseColorFactor[2]; + materialAttributes.opacity = baseColorFactor[3]; + } + const metallicFactor = metallicPBR.metallicFactor; + if (metallicFactor !== null && metallicFactor !== undefined) { + materialAttributes.metallic = metallicFactor; + } + const roughnessFactor = metallicPBR.roughnessFactor; + if (roughnessFactor !== null && roughnessFactor !== undefined) { + materialAttributes.roughness = roughnessFactor; + } + } + return materialAttributes; +} +function loadDefaultScene(ctx) { + const gltfData = ctx.gltfData; + const scene = gltfData.scene || gltfData.scenes[0]; + if (!scene) { + error(ctx, "glTF has no default scene"); + return; + } + loadScene(ctx, scene); +} - /* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ - function scan_tree(s, tree, max_code) -// deflate_state *s; -// ct_data *tree; /* the tree to be scanned */ -// int max_code; /* and its largest code of non zero frequency */ - { - var n; /* iterates over all tree elements */ - var prevlen = -1; /* last emitted length */ - var curlen; /* length of current code */ - - var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ - - var count = 0; /* repeat count of the current code */ - var max_count = 7; /* max repeat count */ - var min_count = 4; /* min repeat count */ - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - } - tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; +function loadScene(ctx, scene) { + const nodes = scene.nodes; + if (!nodes) { + return; + } + for (let i = 0, len = nodes.length; i < len; i++) { + const node = nodes[i]; + countMeshUsage(ctx, node); + } + for (let i = 0, len = nodes.length; i < len; i++) { + const node = nodes[i]; + loadNode(ctx, node, null); + } +} - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - s.bl_tree[curlen * 2]/*.Freq*/ += count; - - } else if (curlen !== 0) { - - if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } - s.bl_tree[REP_3_6 * 2]/*.Freq*/++; - - } else if (count <= 10) { - s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++; - - } else { - s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++; - } - - count = 0; - prevlen = curlen; - - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; - - } else { - max_count = 7; - min_count = 4; - } +function countMeshUsage(ctx, node) { + const mesh = node.mesh; + if (mesh) { + mesh.instances = mesh.instances ? mesh.instances + 1 : 1; + } + if (node.children) { + const children = node.children; + for (let i = 0, len = children.length; i < len; i++) { + const childNode = children[i]; + if (!childNode) { + error(ctx, "Node not found: " + i); + continue; } + countMeshUsage(ctx, childNode); } + } +} - - /* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ - function send_tree(s, tree, max_code) -// deflate_state *s; -// ct_data *tree; /* the tree to be scanned */ -// int max_code; /* and its largest code of non zero frequency */ - { - var n; /* iterates over all tree elements */ - var prevlen = -1; /* last emitted length */ - var curlen; /* length of current code */ - - var nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ - - var count = 0; /* repeat count of the current code */ - var max_count = 7; /* max repeat count */ - var min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen === 0) { - max_count = 138; - min_count = 3; +function loadNode(ctx, node, matrix) { + ctx.gltfData; + let localMatrix; + if (node.matrix) { + localMatrix = node.matrix; + if (matrix) { + matrix = math.mulMat4(matrix, localMatrix, math.mat4()); + } else { + matrix = localMatrix; + } + } + if (node.translation) { + localMatrix = math.translationMat4v(node.translation); + if (matrix) { + matrix = math.mulMat4(matrix, localMatrix, math.mat4()); + } else { + matrix = localMatrix; + } + } + if (node.rotation) { + localMatrix = math.quaternionToMat4(node.rotation); + if (matrix) { + matrix = math.mulMat4(matrix, localMatrix, math.mat4()); + } else { + matrix = localMatrix; + } + } + if (node.scale) { + localMatrix = math.scalingMat4v(node.scale); + if (matrix) { + matrix = math.mulMat4(matrix, localMatrix, math.mat4()); + } else { + matrix = localMatrix; + } + } + if (node.mesh) { + const mesh = node.mesh; + let createEntity; + if (ctx.handlenode) { + const actions = {}; + if (!ctx.handlenode(ctx.sceneModel.id, node, actions)) { + return; } + if (actions.createEntity) { + createEntity = actions.createEntity; + } + } + const sceneModel = ctx.sceneModel; + const worldMatrix = matrix ? matrix.slice() : math.identityMat4(); + const numPrimitives = mesh.primitives.length; - for (n = 0; n <= max_code; n++) { - curlen = nextlen; - nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; - - if (++count < max_count && curlen === nextlen) { - continue; - - } else if (count < min_count) { - do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + if (numPrimitives > 0) { - } else if (curlen !== 0) { - if (curlen !== prevlen) { - send_code(s, curlen, s.bl_tree); - count--; - } - //Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s.bl_tree); - send_bits(s, count - 3, 2); + const meshIds = []; - } else if (count <= 10) { - send_code(s, REPZ_3_10, s.bl_tree); - send_bits(s, count - 3, 3); + for (let i = 0; i < numPrimitives; i++) { - } else { - send_code(s, REPZ_11_138, s.bl_tree); - send_bits(s, count - 11, 7); + const primitive = mesh.primitives[i]; + if (primitive.mode < 4) { + continue; } - count = 0; - prevlen = curlen; - if (nextlen === 0) { - max_count = 138; - min_count = 3; - - } else if (curlen === nextlen) { - max_count = 6; - min_count = 3; + const meshCfg = { + id: sceneModel.id + "." + ctx.numObjects++ + }; - } else { - max_count = 7; - min_count = 4; + switch (primitive.mode) { + case 0: // POINTS + meshCfg.primitive = "points"; + break; + case 1: // LINES + meshCfg.primitive = "lines"; + break; + case 2: // LINE_LOOP + meshCfg.primitive = "lines"; + break; + case 3: // LINE_STRIP + meshCfg.primitive = "lines"; + break; + case 4: // TRIANGLES + meshCfg.primitive = "triangles"; + break; + case 5: // TRIANGLE_STRIP + meshCfg.primitive = "triangles"; + break; + case 6: // TRIANGLE_FAN + meshCfg.primitive = "triangles"; + break; + default: + meshCfg.primitive = "triangles"; } - } - } - - - /* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ - function build_bl_tree(s) { - var max_blindex; /* index of last bit length code of non zero freq */ - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, s.dyn_ltree, s.l_desc.max_code); - scan_tree(s, s.dyn_dtree, s.d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, s.bl_desc); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ + const POSITION = primitive.attributes.POSITION; + if (!POSITION) { + continue; + } + meshCfg.localPositions = POSITION.value; + meshCfg.positions = new Float64Array(meshCfg.localPositions.length); - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES - 1; max_blindex >= 3; max_blindex--) { - if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) { - break; + if (primitive.attributes.NORMAL) { + meshCfg.normals = primitive.attributes.NORMAL.value; } - } - /* Update opt_len to include the bit length tree and counts */ - s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; - //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - // s->opt_len, s->static_len)); - return max_blindex; - } + if (primitive.attributes.TEXCOORD_0) { + meshCfg.uv = primitive.attributes.TEXCOORD_0.value; + } + if (primitive.indices) { + meshCfg.indices = primitive.indices.value; + } - /* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ - function send_all_trees(s, lcodes, dcodes, blcodes) -// deflate_state *s; -// int lcodes, dcodes, blcodes; /* number of codes for each tree */ - { - var rank; /* index in bl_order */ - - //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - // "too many codes"); - //Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes - 1, 5); - send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3); - } - //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ - //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ - //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); - } - - - /* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ - function detect_data_type(s) { - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - var black_mask = 0xf3ffc07f; - var n; + math.transformPositions3(worldMatrix, meshCfg.localPositions, meshCfg.positions); + const origin = math.vec3(); + const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy + if (rtcNeeded) { + meshCfg.origin = origin; + } - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>>= 1) { - if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) { - return Z_BINARY; + const material = primitive.material; + if (material) { + meshCfg.textureSetId = material._textureSetId; + meshCfg.color = material._attributes.color; + meshCfg.opacity = material._attributes.opacity; + meshCfg.metallic = material._attributes.metallic; + meshCfg.roughness = material._attributes.roughness; + } else { + meshCfg.color = new Float32Array([1.0, 1.0, 1.0]); + meshCfg.opacity = 1.0; + } + if (createEntity) { + if (createEntity.colorize) { + meshCfg.color = createEntity.colorize; + } + if (createEntity.opacity !== undefined && createEntity.opacity !== null) { + meshCfg.opacity = createEntity.opacity; + } } - } - /* Check for textual ("white-listed") bytes. */ - if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || - s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { - return Z_TEXT; + sceneModel.createMesh(meshCfg); + meshIds.push(meshCfg.id); } - for (n = 32; n < LITERALS; n++) { - if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { - return Z_TEXT; - } + if (createEntity) { + sceneModel.createEntity(utils.apply(createEntity, { + meshIds: meshIds, + isObject: true + })); + } else { + sceneModel.createEntity({ + meshIds: meshIds, + isObject: true + }); } - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; } + } + if (node.children) { + const children = node.children; + for (let i = 0, len = children.length; i < len; i++) { + const childNode = children[i]; + loadNode(ctx, childNode, matrix); + } + } +} - var static_init_done = false; +function error(ctx, msg) { + ctx.plugin.error(msg); +} - /* =========================================================================== - * Initialize the tree data structures for a new zlib stream. +/** + * @desc Default initial properties for {@link Entity}s loaded from models accompanied by metadata. + * + * When loading a model, plugins such as {@link XKTLoaderPlugin} create + * a tree of {@link Entity}s that represent the model. These loaders can optionally load metadata, to create + * a {@link MetaModel} corresponding to the root {@link Entity}, with a {@link MetaObject} corresponding to each + * object {@link Entity} within the tree. + * + * @type {{String:Object}} */ - function _tr_init(s) - { - - if (!static_init_done) { - tr_static_init(); - static_init_done = true; - } - - s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); - s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); - s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); +const IFCObjectDefaults = { - s.bi_buf = 0; - s.bi_valid = 0; + IfcOpeningElement: { + pickable: false, + visible: false + }, - /* Initialize the first block of the first file: */ - init_block(s); - } + IfcSpace: { + colorize: [0.137255, 0.403922, 0.870588], + pickable: false, + visible: false, + opacity: 0.4 + }, + IfcWindow: { + colorize: [0.137255, 0.403922, 0.870588], + opacity: 0.3 + }, - /* =========================================================================== - * Send a stored block - */ - function _tr_stored_block(s, buf, stored_len, last) -//DeflateState *s; -//charf *buf; /* input block */ -//ulg stored_len; /* length of input block */ -//int last; /* one if this is the last block for a file */ - { - send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ - copy_block(s, buf, stored_len, true); /* with header */ - } + IfcPlate: { + colorize: [0.8470588235, 0.427450980392, 0, 0.5], + opacity: 0.3 + }, + DEFAULT: { + } +}; - /* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. +/** + * {@link Viewer} plugin that loads models from [glTF](https://www.khronos.org/gltf/). + * + * * Loads all glTF formats, including embedded and binary formats. + * * Loads physically-based materials and textures. + * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. + * * Creates an {@link Entity} for each object within the model, which is indicated by each glTF ````node```` that has a ````name```` attribute. Those Entities will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. + * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. + * * Not recommended for large models. For best performance with large glTF datasets, we recommend first converting them + * to ````.xkt```` format (eg. using [convert2xkt](https://github.com/xeokit/xeokit-convert)), then loading + * the ````.xkt```` using {@link XKTLoaderPlugin}. + * + * ## Metadata + * + * GLTFLoaderPlugin can also load an accompanying JSON metadata file with each model, which creates a {@link MetaModel} corresponding + * to the model {@link Entity} and a {@link MetaObject} corresponding to each object {@link Entity}. + * + * Each {@link MetaObject} has a {@link MetaObject#type}, which indicates the classification of its corresponding {@link Entity}. When loading + * metadata, we can also provide GLTFLoaderPlugin with a custom lookup table of initial values to set on the properties of each type of {@link Entity}. By default, GLTFLoaderPlugin + * uses its own map of default colors and visibilities for IFC element types. + * + * ## Usage + * + * In the example below we'll load the Schependomlaan model from a [glTF file](http://xeokit.github.io/xeokit-sdk/examples/models/gltf/schependomlaan/), along + * with an accompanying JSON [IFC metadata file](http://xeokit.github.io/xeokit-sdk/examples/metaModels/schependomlaan/). + * + * This will create a bunch of {@link Entity}s that represents the model and its objects, along with a {@link MetaModel} and {@link MetaObject}s + * that hold their metadata. + * + * Since this model contains IFC types, the GLTFLoaderPlugin will set the initial colors of object {@link Entity}s according + * to the standard IFC element colors in the GLTFModel's current map. Override that with your own map via property {@link GLTFLoaderPlugin#objectDefaults}. + * + * Read more about this example in the user guide on [Viewing BIM Models Offline](https://www.notion.so/xeokit/Viewing-an-IFC-Model-with-xeokit-c373e48bc4094ff5b6e5c5700ff580ee). + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_glTF_OTCConferenceCenter)] + * + * ````javascript + * import {Viewer, GLTFLoaderPlugin} from "xeokit-sdk.es.js"; + * + * //------------------------------------------------------------------------------------------------------------------ + * // 1. Create a Viewer, + * // 2. Arrange the camera, + * // 3. Tweak the selection material (tone it down a bit) + * //------------------------------------------------------------------------------------------------------------------ + * + * // 1 + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * // 2 + * viewer.camera.orbitPitch(20); + * viewer.camera.orbitYaw(-45); + * + * // 3 + * viewer.scene.selectedMaterial.fillAlpha = 0.1; + * + * //------------------------------------------------------------------------------------------------------------------ + * // 1. Create a glTF loader plugin, + * // 2. Load a glTF building model and JSON IFC metadata + * // 3. Emphasis the edges to make it look nice + * //------------------------------------------------------------------------------------------------------------------ + * + * // 1 + * const gltfLoader = new GLTFLoaderPlugin(viewer); + * + * // 2 + * var model = gltfLoader.load({ // Returns an Entity that represents the model + * id: "myModel", + * src: "./models/gltf/OTCConferenceCenter/scene.gltf", + * metaModelSrc: "./models/gltf/OTCConferenceCenter/metaModel.json", // Creates a MetaModel (see below) + * edges: true + * }); + * + * model.on("loaded", () => { + * + * //-------------------------------------------------------------------------------------------------------------- + * // 1. Find metadata on the third storey + * // 2. Select all the objects in the building's third storey + * // 3. Fit the camera to all the objects on the third storey + * //-------------------------------------------------------------------------------------------------------------- + * + * // 1 + * const metaModel = viewer.metaScene.metaModels["myModel"]; // MetaModel with ID "myModel" + * const metaObject + * = viewer.metaScene.metaObjects["0u4wgLe6n0ABVaiXyikbkA"]; // MetaObject with ID "0u4wgLe6n0ABVaiXyikbkA" + * + * const name = metaObject.name; // "01 eerste verdieping" + * const type = metaObject.type; // "IfcBuildingStorey" + * const parent = metaObject.parent; // MetaObject with type "IfcBuilding" + * const children = metaObject.children; // Array of child MetaObjects + * const objectId = metaObject.id; // "0u4wgLe6n0ABVaiXyikbkA" + * const objectIds = viewer.metaScene.getObjectIDsInSubtree(objectId); // IDs of leaf sub-objects + * const aabb = viewer.scene.getAABB(objectIds); // Axis-aligned boundary of the leaf sub-objects + * + * // 2 + * viewer.scene.setObjectsSelected(objectIds, true); + * + * // 3 + * viewer.cameraFlight.flyTo(aabb); + * }); + * + * // Find the model Entity by ID + * model = viewer.scene.models["myModel"]; + * + * // Destroy the model + * model.destroy(); + * ```` + * + * ## Transforming + * + * We have the option to rotate, scale and translate each *````.glTF````* model as we load it. + * + * This lets us load multiple models, or even multiple copies of the same model, and position them apart from each other. + * + * In the example below, we'll scale our model to half its size, rotate it 90 degrees about its local X-axis, then + * translate it 100 units along its X axis. + * + * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_glTF_Duplex_transform)] + * + * ````javascript + * const model = gltfLoader.load({ + * src: "./models/gltf/Duplex/scene.gltf", + * metaModelSrc: "./models/gltf/Duplex/Duplex.json", + * rotation: [90,0,0], + * scale: [0.5, 0.5, 0.5], + * position: [100, 0, 0] + * }); + * ```` + * + * ## Including and excluding IFC types + * + * We can also load only those objects that have the specified IFC types. In the example below, we'll load only the + * objects that represent walls. + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_glTF_includeTypes_PlanView)] + * + * ````javascript + * const model = gltfLoader.load({ + * id: "myModel", + * src: "./models/gltf/OTCConferenceCenter/scene.gltf", + * metaModelSrc: "./models/gltf/OTCConferenceCenter/metaModel.json", + * includeTypes: ["IfcWallStandardCase"] + * }); + * ```` + * + * We can also load only those objects that **don't** have the specified IFC types. In the example below, we'll load only the + * objects that do not represent empty space. + * + * ````javascript + * const model = gltfLoader.load({ + * id: "myModel", + * src: "./models/gltf/OTCConferenceCenter/scene.gltf", + * metaModelSrc: "./models/gltf/OTCConferenceCenter/metaModel.json", + * excludeTypes: ["IfcSpace"] + * }); + * ```` + * @class GLTFLoaderPlugin */ - function _tr_align(s) { - send_bits(s, STATIC_TREES << 1, 3); - send_code(s, END_BLOCK, static_ltree); - bi_flush(s); - } - +class GLTFLoaderPlugin extends Plugin { - /* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. - */ - function _tr_flush_block(s, buf, stored_len, last) -//DeflateState *s; -//charf *buf; /* input block, or NULL if too old */ -//ulg stored_len; /* length of input block */ -//int last; /* one if this is the last block for a file */ - { - var opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - var max_blindex = 0; /* index of last bit length code of non zero freq */ + /** + * @constructor + * + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="GLTFLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Object} [cfg.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. + * @param {Object} [cfg.dataSource] A custom data source through which the GLTFLoaderPlugin can load metadata, glTF and binary attachments. Defaults to an instance of {@link GLTFDefaultDataSource}, which loads over HTTP. + */ + constructor(viewer, cfg = {}) { - /* Build the Huffman trees unless a stored block is forced */ - if (s.level > 0) { + super("GLTFLoader", viewer, cfg); + + this._sceneModelLoader = new GLTFVBOSceneModelLoader(this, cfg); - /* Check if the file is binary or text */ - if (s.strm.data_type === Z_UNKNOWN) { - s.strm.data_type = detect_data_type(s); - } + this.dataSource = cfg.dataSource; + this.objectDefaults = cfg.objectDefaults; + } - /* Construct the literal and distance trees */ - build_tree(s, s.l_desc); - // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); + /** + * Sets a custom data source through which the GLTFLoaderPlugin can load metadata, glTF and binary attachments. + * + * Default value is {@link GLTFDefaultDataSource}, which loads via an XMLHttpRequest. + * + * @type {Object} + */ + set dataSource(value) { + this._dataSource = value || new GLTFDefaultDataSource(); + } - build_tree(s, s.d_desc); - // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - // s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. + /** + * Gets the custom data source through which the GLTFLoaderPlugin can load metadata, glTF and binary attachments. + * + * Default value is {@link GLTFDefaultDataSource}, which loads via an XMLHttpRequest. + * + * @type {Object} */ + get dataSource() { + return this._dataSource; + } - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. + /** + * Sets map of initial default states for each loaded {@link Entity} that represents an object. + * + * Default value is {@link IFCObjectDefaults}. + * + * @type {{String: Object}} */ - max_blindex = build_bl_tree(s); + set objectDefaults(value) { + this._objectDefaults = value || IFCObjectDefaults; + } - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s.opt_len + 3 + 7) >>> 3; - static_lenb = (s.static_len + 3 + 7) >>> 3; + /** + * Gets map of initial default states for each loaded {@link Entity} that represents an object. + * + * Default value is {@link IFCObjectDefaults}. + * + * @type {{String: Object}} + */ + get objectDefaults() { + return this._objectDefaults; + } - // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - // s->last_lit)); + /** + * Loads a glTF model from a file into this GLTFLoaderPlugin's {@link Viewer}. + * + * @param {*} params Loading parameters. + * @param {String} [params.id] ID to assign to the root {@link Entity#id}, unique among all components in the Viewer's {@link Scene}, generated automatically by default. + * @param {String} [params.src] Path to a glTF file, as an alternative to the ````gltf```` parameter. + * @param {*} [params.gltf] glTF JSON, as an alternative to the ````src```` parameter. + * @param {String} [params.metaModelSrc] Path to an optional metadata file, as an alternative to the ````metaModelData```` parameter. + * @param {*} [params.metaModelData] JSON model metadata, as an alternative to the ````metaModelSrc```` parameter. + * @param {{String:Object}} [params.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. + * @param {String[]} [params.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. + * @param {String[]} [params.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. + * @param {Boolean} [params.edges=false] Whether or not xeokit renders the model with edges emphasized. + * @param {Number[]} [params.origin=[0,0,0]] The double-precision World-space origin of the model's coordinates. + * @param {Number[]} [params.position=[0,0,0]] The single-precision position, relative to ````origin````. + * @param {Number[]} [params.scale=[1,1,1]] The model's scale. + * @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. Relative to ````origin````. + * @param {Boolean} [params.saoEnabled=true] Indicates if Scalable Ambient Obscurance (SAO) is enabled for the model. SAO is configured by the Scene's {@link SAO} component. Only works when {@link SAO#enabled} is also ````true```` + * @param {Boolean} [params.pbrEnabled=true] Indicates if physically-based rendering (PBR) is enabled for the model. Overrides ````colorTextureEnabled````. Only works when {@link Scene#pbrEnabled} is also ````true````. + * @param {Boolean} [params.colorTextureEnabled=true] Indicates if base color texture rendering is enabled for the model. Overridden by ````pbrEnabled````. Only works when {@link Scene#colorTextureEnabled} is also ````true````. + * @param {Boolean} [params.backfaces=false] When true, allows visible backfaces, wherever specified in the glTF. When false, ignores backfaces. + * @param {Number} [params.edgeThreshold=10] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. + * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} + */ + load(params = {}) { - if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + if (params.id && this.viewer.scene.components[params.id]) { + this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); + delete params.id; + } - } else { - // Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } + const sceneModel = new VBOSceneModel(this.viewer.scene, utils.apply(params, { + isModel: true + })); - if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) { - /* 4: two words for the lengths */ + const modelId = sceneModel.id; // In case ID was auto-generated - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, last); + if (!params.src && !params.gltf) { + this.error("load() param expected: src or gltf"); + return sceneModel; // Return new empty model + } - } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) { + if (params.metaModelSrc || params.metaModelData) { - send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); - compress_block(s, static_ltree, static_dtree); + const objectDefaults = params.objectDefaults || this._objectDefaults || IFCObjectDefaults; - } else { - send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); - send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); - compress_block(s, s.dyn_ltree, s.dyn_dtree); - } - // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); + const processMetaModelData = (metaModelData) => { - if (last) { - bi_windup(s); - } - // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - // s->compressed_len-7*last)); - } + this.viewer.metaScene.createMetaModel(modelId, metaModelData, { + includeTypes: params.includeTypes, + excludeTypes: params.excludeTypes + }); - /* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ - function _tr_tally(s, dist, lc) -// deflate_state *s; -// unsigned dist; /* distance of matched string */ -// unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ - { - //var out_length, in_length, dcode; + this.viewer.scene.canvas.spinner.processes--; - s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; - s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + let includeTypes; + if (params.includeTypes) { + includeTypes = {}; + for (let i = 0, len = params.includeTypes.length; i < len; i++) { + includeTypes[params.includeTypes[i]] = true; + } + } + if (params.excludeTypes) { + if (!includeTypes) { + includeTypes = {}; + } + for (let i = 0, len = params.excludeTypes.length; i < len; i++) { + includeTypes[params.excludeTypes[i]] = true; + } + } - s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; - s.last_lit++; + params.readableGeometry = false; - if (dist === 0) { - /* lc is the unmatched char */ - s.dyn_ltree[lc * 2]/*.Freq*/++; - } else { - s.matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - //Assert((ush)dist < (ush)MAX_DIST(s) && - // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s.dyn_ltree[(_length_code[lc] + LITERALS + 1) * 2]/*.Freq*/++; - s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; - } - -// (!) This block is disabled in zlib defaults, -// don't enable it for binary compatibility - -//#ifdef TRUNCATE_BLOCK -// /* Try to guess if it is profitable to stop the current block here */ -// if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { -// /* Compute an upper bound for the compressed length */ -// out_length = s.last_lit*8; -// in_length = s.strstart - s.block_start; -// -// for (dcode = 0; dcode < D_CODES; dcode++) { -// out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); -// } -// out_length >>>= 3; -// //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", -// // s->last_lit, in_length, out_length, -// // 100L - out_length*100L/in_length)); -// if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { -// return true; -// } -// } -//#endif - - return (s.last_lit === s.lit_bufsize - 1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ - } + params.handleGLTFNode = (modelId, glTFNode, actions) => { - exports._tr_init = _tr_init; - exports._tr_stored_block = _tr_stored_block; - exports._tr_flush_block = _tr_flush_block; - exports._tr_tally = _tr_tally; - exports._tr_align = _tr_align; + const name = glTFNode.name; - },{"../utils/common":3}],15:[function(require,module,exports){ + if (!name) { + return true; // Continue descending this node subtree + } -// (C) 1995-2013 Jean-loup Gailly and Mark Adler -// (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - - function ZStream() { - /* next input byte */ - this.input = null; // JS specific, because we have no pointers - this.next_in = 0; - /* number of bytes available at input */ - this.avail_in = 0; - /* total number of input bytes read so far */ - this.total_in = 0; - /* next output byte should be put there */ - this.output = null; // JS specific, because we have no pointers - this.next_out = 0; - /* remaining free space at output */ - this.avail_out = 0; - /* total number of bytes output so far */ - this.total_out = 0; - /* last error message, NULL if no error */ - this.msg = ''/*Z_NULL*/; - /* not visible by applications */ - this.state = null; - /* best guess about the data type: binary or text */ - this.data_type = 2/*Z_UNKNOWN*/; - /* adler32 value of the uncompressed data */ - this.adler = 0; - } - - module.exports = ZStream; - - },{}],"/":[function(require,module,exports){ - - var assign = require('./lib/utils/common').assign; - - var deflate = require('./lib/deflate'); - var inflate = require('./lib/inflate'); - var constants = require('./lib/zlib/constants'); - - var pako = {}; - - assign(pako, deflate, inflate, constants); - - module.exports = pako; - - },{"./lib/deflate":1,"./lib/inflate":2,"./lib/utils/common":3,"./lib/zlib/constants":6}]},{},[])("/") -}); + const nodeId = name; + const metaObject = this.viewer.metaScene.metaObjects[nodeId]; + const type = (metaObject ? metaObject.type : "DEFAULT") || "DEFAULT"; -var p = /*#__PURE__*/Object.freeze({ - __proto__: null -}); + actions.createEntity = { + id: nodeId, + isObject: true // Registers the Entity in Scene#objects + }; -/* + const props = objectDefaults[type]; - Parser for .XKT Format V1 + if (props) { // Set Entity's initial rendering state for recognized type -.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + if (props.visible === false) { + actions.createEntity.visible = false; + } - DEPRECATED + if (props.colorize) { + actions.createEntity.colorize = props.colorize; + } - */ + if (props.pickable === false) { + actions.createEntity.pickable = false; + } -let pako$9 = window.pako || p; -if (!pako$9.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$9 = pako$9.default; -} + if (props.opacity !== undefined && props.opacity !== null) { + actions.createEntity.opacity = props.opacity; + } + } -const decompressColor$9 = (function () { - const color2 = new Float32Array(3); - return function (color) { - color2[0] = color[0] / 255.0; - color2[1] = color[1] / 255.0; - color2[2] = color[2] / 255.0; - return color2; - }; -})(); + return true; // Continue descending this glTF node subtree + }; -function extract$9(elements) { - return { - positions: elements[0], - normals: elements[1], - indices: elements[2], - edgeIndices: elements[3], - meshPositions: elements[4], - meshIndices: elements[5], - meshEdgesIndices: elements[6], - meshColors: elements[7], - entityIDs: elements[8], - entityMeshes: elements[9], - entityIsObjects: elements[10], - positionsDecodeMatrix: elements[11] - }; -} + if (params.src) { + this._sceneModelLoader.load(this, sceneModel, params.src, params); + } else { + this._sceneModelLoader.parse(this, sceneModel, params.gltf, params); + } + }; -function inflate$9(deflatedData) { - return { - positions: new Uint16Array(pako$9.inflate(deflatedData.positions).buffer), - normals: new Int8Array(pako$9.inflate(deflatedData.normals).buffer), - indices: new Uint32Array(pako$9.inflate(deflatedData.indices).buffer), - edgeIndices: new Uint32Array(pako$9.inflate(deflatedData.edgeIndices).buffer), - meshPositions: new Uint32Array(pako$9.inflate(deflatedData.meshPositions).buffer), - meshIndices: new Uint32Array(pako$9.inflate(deflatedData.meshIndices).buffer), - meshEdgesIndices: new Uint32Array(pako$9.inflate(deflatedData.meshEdgesIndices).buffer), - meshColors: new Uint8Array(pako$9.inflate(deflatedData.meshColors).buffer), - entityIDs: pako$9.inflate(deflatedData.entityIDs, {to: 'string'}), - entityMeshes: new Uint32Array(pako$9.inflate(deflatedData.entityMeshes).buffer), - entityIsObjects: new Uint8Array(pako$9.inflate(deflatedData.entityIsObjects).buffer), - positionsDecodeMatrix: new Float32Array(pako$9.inflate(deflatedData.positionsDecodeMatrix).buffer) - }; -} + if (params.metaModelSrc) { -function load$9(viewer, options, inflatedData, sceneModel) { + const metaModelSrc = params.metaModelSrc; - sceneModel.positionsCompression = "precompressed"; - sceneModel.normalsCompression = "precompressed"; + this.viewer.scene.canvas.spinner.processes++; - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - const meshPositions = inflatedData.meshPositions; - const meshIndices = inflatedData.meshIndices; - const meshEdgesIndices = inflatedData.meshEdgesIndices; - const meshColors = inflatedData.meshColors; - const entityIDs = JSON.parse(inflatedData.entityIDs); - const entityMeshes = inflatedData.entityMeshes; - const entityIsObjects = inflatedData.entityIsObjects; - const numMeshes = meshPositions.length; - const numEntities = entityMeshes.length; + this._dataSource.getMetaModel(metaModelSrc, (metaModelData) => { - for (let i = 0; i < numEntities; i++) { + this.viewer.scene.canvas.spinner.processes--; - const xktEntityId = entityIDs [i]; - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; + processMetaModelData(metaModelData); - if (metaObject) { + }, (errMsg) => { + this.error(`load(): Failed to load model metadata for model '${modelId} from '${metaModelSrc}' - ${errMsg}`); + this.viewer.scene.canvas.spinner.processes--; + }); - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } + } else if (params.metaModelData) { - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; + processMetaModelData(params.metaModelData); } - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; - - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; - } - } } else { - if (options.excludeUnclassifiedObjects) { - continue; - } - } - const lastEntity = (i === numEntities - 1); - const meshIds = []; + params.handleGLTFNode = (modelId, glTFNode, actions) => { - for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshes.length : entityMeshes [i + 1]; j < jlen; j++) { + const name = glTFNode.name; - const lastMesh = (j === (numMeshes - 1)); - const meshId = entityId + ".mesh." + j; + if (!name) { + return true; // Continue descending this node subtree + } - const color = decompressColor$9(meshColors.subarray((j * 4), (j * 4) + 3)); - const opacity = meshColors[(j * 4) + 3] / 255.0; + const id = name; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - primitive: "triangles", - positionsCompressed: positions.subarray(meshPositions [j], lastMesh ? positions.length : meshPositions [j + 1]), - normalsCompressed: normals.subarray(meshPositions [j], lastMesh ? positions.length : meshPositions [j + 1]), - indices: indices.subarray(meshIndices [j], lastMesh ? indices.length : meshIndices [j + 1]), - edgeIndices: edgeIndices.subarray(meshEdgesIndices [j], lastMesh ? edgeIndices.length : meshEdgesIndices [j + 1]), - positionsDecodeMatrix: inflatedData.positionsDecodeMatrix, - color: color, - opacity: opacity - })); + actions.createEntity = { // Create an Entity for this glTF scene node + id: id, + isObject: true // Registers the Entity in Scene#objects + }; - meshIds.push(meshId); + return true; // Continue descending this glTF node subtree + }; + + if (params.src) { + this._sceneModelLoader.load(this, sceneModel, params.src, params); + } else { + this._sceneModelLoader.parse(this, sceneModel, params.gltf, params); + } } - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: (entityIsObjects [i] === 1), - meshIds: meshIds - })); - } -} + sceneModel.once("destroyed", () => { + this.viewer.metaScene.destroyMetaModel(modelId); + }); -/** @private */ -const ParserV1 = { - version: 1, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$9(elements); - const inflatedData = inflate$9(deflatedData); - load$9(viewer, options, inflatedData, sceneModel); + return sceneModel; } -}; - -/* - -Parser for .XKT Format V2 - -DEPRECATED - -.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format - - */ -let pako$8 = window.pako || p; -if (!pako$8.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$8 = pako$8.default; + /** + * Destroys this GLTFLoaderPlugin. + */ + destroy() { + super.destroy(); + } } -function extract$8(elements) { - return { - - positions: elements[0], - normals: elements[1], - indices: elements[2], - edgeIndices: elements[3], +/** + * @private + */ +function CubeTextureCanvas(viewer, cfg = {}) { - meshPositions: elements[4], - meshIndices: elements[5], - meshEdgesIndices: elements[6], - meshColors: elements[7], + const cubeColor = "lightgrey"; + const cubeHighlightColor = cfg.hoverColor || "rgba(0,0,0,0.4)"; - entityIDs: elements[8], - entityMeshes: elements[9], - entityIsObjects: elements[10], + const height = 500; + const width = height + (height / 3); + const scale = width / 24; - positionsDecodeMatrix: elements[11], + const facesZUp = [ + {boundary: [6, 6, 6, 6], color: cfg.frontColor || cfg.color || "#55FF55"}, + {boundary: [18, 6, 6, 6], color: cfg.backColor || cfg.color || "#55FF55"}, + {boundary: [12, 6, 6, 6], color: cfg.leftColor || cfg.color || "#FF5555"}, + {boundary: [0, 6, 6, 6], color: cfg.rightColor || cfg.color || "#FF5555"}, + {boundary: [6, 0, 6, 6], color: cfg.topColor || cfg.color || "#7777FF"}, + {boundary: [6, 12, 6, 6], color: cfg.bottomColor || cfg.color || "#7777FF"} + ]; - entityMeshIds: elements[12], - entityMatrices: elements[13], - entityUsesInstancing: elements[14] - }; -} + const areasZUp = [ + {label: "NavCube.front", boundaries: [[7, 7, 4, 4]], dir: [0, 1, 0], up: [0, 0, 1]}, + {label: "NavCube.back", boundaries: [[19, 7, 4, 4]], dir: [0, -1, 0], up: [0, 0, 1]}, + {label: "NavCube.right", boundaries: [[13, 7, 4, 4]], dir: [-1, 0, 0], up: [0, 0, 1]}, + {label: "NavCube.left", boundaries: [[1, 7, 4, 4]], dir: [1, 0, 0], up: [0, 0, 1]}, + {label: "NavCube.top", boundaries: [[7, 1, 4, 4]], dir: [0, 0, -1], up: [0, 1, 0]}, + {label: "NavCube.bottom", boundaries: [[7, 13, 4, 4]], dir: [0, 0, 1], up: [0, -1, 0]}, + {boundaries: [[7, 5, 4, 2]], dir: [0, 1, -1], up: [0, 1, 1]}, + {boundaries: [[1, 6, 4, 1], [6, 1, 1, 4]], dir: [1, 0, -1], up: [1, 0, 1]}, + {boundaries: [[7, 0, 4, 1], [19, 6, 4, 1]], dir: [0, -1, -1], up: [0, -1, 1]}, + {boundaries: [[13, 6, 4, 1], [11, 1, 1, 4]], dir: [-1, 0, -1], up: [-1, 0, 1]}, + {boundaries: [[7, 11, 4, 2]], dir: [0, 1, 1], up: [0, -1, 1]}, + {boundaries: [[1, 11, 4, 1], [6, 13, 1, 4]], dir: [1, 0, 1], up: [-1, 0, 1]}, + {boundaries: [[7, 17, 4, 1], [19, 11, 4, 1]], dir: [0, -1, 1], up: [0, 1, 1]}, + {boundaries: [[13, 11, 4, 1], [11, 13, 1, 4]], dir: [-1, 0, 1], up: [1, 0, 1]}, + {boundaries: [[5, 7, 2, 4]], dir: [1, 1, 0], up: [0, 0, 1]}, + {boundaries: [[11, 7, 2, 4]], dir: [-1, 1, 0], up: [0, 0, 1]}, + {boundaries: [[17, 7, 2, 4]], dir: [-1, -1, 0], up: [0, 0, 1]}, + {boundaries: [[0, 7, 1, 4], [23, 7, 1, 4]], dir: [1, -1, 0], up: [0, 0, 1]}, + {boundaries: [[5, 11, 2, 2]], dir: [1, 1, 1], up: [-1, -1, 1]}, + {boundaries: [[23, 11, 1, 1], [6, 17, 1, 1], [0, 11, 1, 1]], dir: [1, -1, 1], up: [-1, 1, 1]}, + {boundaries: [[5, 5, 2, 2]], dir: [1, 1, -1], up: [1, 1, 1]}, + {boundaries: [[11, 17, 1, 1], [17, 11, 2, 1]], dir: [-1, -1, 1], up: [1, 1, 1]}, + {boundaries: [[17, 6, 2, 1], [11, 0, 1, 1]], dir: [-1, -1, -1], up: [-1, -1, 1]}, + {boundaries: [[11, 11, 2, 2]], dir: [-1, 1, 1], up: [1, -1, 1]}, + {boundaries: [[0, 6, 1, 1], [6, 0, 1, 1], [23, 6, 1, 1]], dir: [1, -1, -1], up: [1, -1, 1]}, + {boundaries: [[11, 5, 2, 2]], dir: [-1, 1, -1], up: [-1, 1, 1]} + ]; -function inflate$8(deflatedData) { - return { - positions: new Uint16Array(pako$8.inflate(deflatedData.positions).buffer), - normals: new Int8Array(pako$8.inflate(deflatedData.normals).buffer), - indices: new Uint32Array(pako$8.inflate(deflatedData.indices).buffer), - edgeIndices: new Uint32Array(pako$8.inflate(deflatedData.edgeIndices).buffer), + [ + {boundary: [6, 6, 6, 6], color: cfg.frontColor || cfg.color || "#55FF55"}, + {boundary: [18, 6, 6, 6], color: cfg.backColor || cfg.color || "#55FF55"}, + {boundary: [12, 6, 6, 6], color: cfg.leftColor || cfg.color || "#FF5555"}, + {boundary: [0, 6, 6, 6], color: cfg.rightColor || cfg.color || "#FF5555"}, + {boundary: [6, 0, 6, 6], color: cfg.topColor || cfg.color || "#7777FF"}, + {boundary: [6, 12, 6, 6], color: cfg.bottomColor || cfg.color || "#7777FF"} + ]; - meshPositions: new Uint32Array(pako$8.inflate(deflatedData.meshPositions).buffer), - meshIndices: new Uint32Array(pako$8.inflate(deflatedData.meshIndices).buffer), - meshEdgesIndices: new Uint32Array(pako$8.inflate(deflatedData.meshEdgesIndices).buffer), - meshColors: new Uint8Array(pako$8.inflate(deflatedData.meshColors).buffer), + const areasYUp = [ - entityIDs: pako$8.inflate(deflatedData.entityIDs, {to: 'string'}), - entityMeshes: new Uint32Array(pako$8.inflate(deflatedData.entityMeshes).buffer), - entityIsObjects: new Uint8Array(pako$8.inflate(deflatedData.entityIsObjects).buffer), + // Faces - positionsDecodeMatrix: new Float32Array(pako$8.inflate(deflatedData.positionsDecodeMatrix).buffer), + {yUp: "", label: "NavCube.front", boundaries: [[7, 7, 4, 4]], dir: [0, 0, -1], up: [0, 1, 0]}, + {label: "NavCube.back", boundaries: [[19, 7, 4, 4]], dir: [0, 0, 1], up: [0, 1, 0]}, + {label: "NavCube.right", boundaries: [[13, 7, 4, 4]], dir: [-1, 0, 0], up: [0, 1, 0]}, + {label: "NavCube.left", boundaries: [[1, 7, 4, 4]], dir: [1, 0, 0], up: [0, 1, 0]}, + {label: "NavCube.top", boundaries: [[7, 1, 4, 4]], dir: [0, -1, 0], up: [0, 0, -1]}, + {label: "NavCube.bottom", boundaries: [[7, 13, 4, 4]], dir: [0, 1, 0], up: [0, 0, 1]}, + {boundaries: [[7, 5, 4, 2]], dir: [0, -0.7071, -0.7071], up: [0, 0.7071, -0.7071]}, // Top-front edge + {boundaries: [[1, 6, 4, 1], [6, 1, 1, 4]], dir: [1, -1, 0], up: [1, 1, 0]}, // Top-left edge + {boundaries: [[7, 0, 4, 1], [19, 6, 4, 1]], dir: [0, -0.7071, 0.7071], up: [0, 0.7071, 0.7071]}, // Top-back edge + {boundaries: [[13, 6, 4, 1], [11, 1, 1, 4]], dir: [-1, -1, 0], up: [-1, 1, 0]}, // Top-right edge + {boundaries: [[7, 11, 4, 2]], dir: [0, 1, -1], up: [0, 1, 1]}, // Bottom-front edge + {boundaries: [[1, 11, 4, 1], [6, 13, 1, 4]], dir: [1, 1, 0], up: [-1, 1, 0]}, // Bottom-left edge + {boundaries: [[7, 17, 4, 1], [19, 11, 4, 1]], dir: [0, 1, 1], up: [0, 1, -1]}, // Bottom-back edge + {boundaries: [[13, 11, 4, 1], [11, 13, 1, 4]], dir: [-1, 1, 0], up: [1, 1, 0]}, // Bottom-right edge + {boundaries: [[5, 7, 2, 4]], dir: [1, 0, -1], up: [0, 1, 0]},// Front-left edge + {boundaries: [[11, 7, 2, 4]], dir: [-1, 0, -1], up: [0, 1, 0]}, // Front-right edge + {boundaries: [[17, 7, 2, 4]], dir: [-1, 0, 1], up: [0, 1, 0]},// Back-right edge + {boundaries: [[0, 7, 1, 4], [23, 7, 1, 4]], dir: [1, 0, 1], up: [0, 1, 0]},// Back-left edge + {boundaries: [[5, 11, 2, 2]], "dir": [0.5, 0.7071, -0.5], "up": [-0.5, 0.7071, 0.5]}, // Bottom-left-front corner + {boundaries: [[23, 11, 1, 1], [6, 17, 1, 1], [0, 11, 1, 1]],"dir": [0.5, 0.7071, 0.5],"up": [-0.5, 0.7071, -0.5]},// Bottom-back-left corner + {boundaries: [[5, 5, 2, 2]], "dir": [0.5, -0.7071, -0.5], "up": [0.5, 0.7071, -0.5]}, // Left-front-top corner + {boundaries: [[11, 17, 1, 1], [17, 11, 2, 1]], "dir": [-0.5, 0.7071, 0.5], "up": [0.5, 0.7071, -0.5]}, // Bottom-back-right corner + {boundaries: [[17, 6, 2, 1], [11, 0, 1, 1]], "dir": [-0.5, -0.7071, 0.5], "up": [-0.5, 0.7071, 0.5]}, // Top-back-right corner + {boundaries: [[11, 11, 2, 2]], "dir": [-0.5, 0.7071, -0.5], "up": [0.5, 0.7071, 0.5]}, // Bottom-front-right corner + {boundaries: [[0, 6, 1, 1], [6, 0, 1, 1], [23, 6, 1, 1]], "dir": [0.5, -0.7071, 0.5], "up": [0.5, 0.7071, 0.5]},// Top-back-left corner + {boundaries: [[11, 5, 2, 2]], "dir": [-0.5, -0.7071, -0.5], "up": [-0.5, 0.7071, -0.5]}// Top-front-right corner + ]; - entityMeshIds: new Uint32Array(pako$8.inflate(deflatedData.entityMeshIds).buffer), - entityMatrices: new Float32Array(pako$8.inflate(deflatedData.entityMatrices).buffer), - entityUsesInstancing: new Uint8Array(pako$8.inflate(deflatedData.entityUsesInstancing).buffer) - }; -} + for (let i = 0, len = areasZUp.length; i < len; i++) { + math.normalizeVec3(areasZUp[i].dir, areasZUp[i].dir); + math.normalizeVec3(areasZUp[i].up, areasZUp[i].up); + } -const decompressColor$8 = (function () { - const color2 = new Float32Array(3); - return function (color) { - color2[0] = color[0] / 255.0; - color2[1] = color[1] / 255.0; - color2[2] = color[2] / 255.0; - return color2; - }; -})(); + for (let i = 0, len = areasYUp.length; i < len; i++) { + math.normalizeVec3(areasYUp[i].dir, areasYUp[i].dir); + math.normalizeVec3(areasYUp[i].up, areasYUp[i].up); + } + var areas = areasYUp; -function load$8(viewer, options, inflatedData, sceneModel) { + this._textureCanvas = document.createElement('canvas'); + this._textureCanvas.width = width; + this._textureCanvas.height = height; + this._textureCanvas.style.width = width + "px"; + this._textureCanvas.style.height = height + "px"; + this._textureCanvas.style.padding = "0"; + this._textureCanvas.style.margin = "0"; + this._textureCanvas.style.top = "0"; + this._textureCanvas.style.background = cubeColor; + this._textureCanvas.style.position = "absolute"; + this._textureCanvas.style.opacity = "1.0"; + this._textureCanvas.style.visibility = "hidden"; + this._textureCanvas.style["z-index"] = 2000000; - sceneModel.positionsCompression = "precompressed"; - sceneModel.normalsCompression = "precompressed"; + const body = document.getElementsByTagName("body")[0]; + body.appendChild(this._textureCanvas); - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - const meshPositions = inflatedData.meshPositions; - const meshIndices = inflatedData.meshIndices; - const meshEdgesIndices = inflatedData.meshEdgesIndices; - const meshColors = inflatedData.meshColors; - const entityIDs = JSON.parse(inflatedData.entityIDs); - const entityMeshes = inflatedData.entityMeshes; - const entityIsObjects = inflatedData.entityIsObjects; - const entityMeshIds = inflatedData.entityMeshIds; - const entityMatrices = inflatedData.entityMatrices; - const entityUsesInstancing = inflatedData.entityUsesInstancing; + const context = this._textureCanvas.getContext("2d"); - const numMeshes = meshPositions.length; - const numEntities = entityMeshes.length; + let zUp = false; - const alreadyCreatedGeometries = {}; + function paint() { - for (let i = 0; i < numEntities; i++) { + for (let i = 0, len = facesZUp.length; i < len; i++) { + const face = facesZUp[i]; + const boundary = face.boundary; + const xmin = Math.round(boundary[0] * scale); + const ymin = Math.round(boundary[1] * scale); + const width = Math.round(boundary[2] * scale); + const height = Math.round(boundary[3] * scale); + context.fillStyle = face.color; + context.fillRect(xmin, ymin, width, height); + } - const xktEntityId = entityIDs [i]; - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; - const entityMatrix = entityMatrices.subarray((i * 16), (i * 16) + 16); + for (let i = 0, len = areas.length; i < len; i++) { + let xmin; + let ymin; + let width; + let height; + const area = areas[i]; - if (metaObject) { - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; + const boundaries = area.boundaries; + for (var j = 0, lenj = boundaries.length; j < lenj; j++) { + const boundary = boundaries[j]; + xmin = Math.round(boundary[0] * scale); + ymin = Math.round(boundary[1] * scale); + width = Math.round(boundary[2] * scale); + height = Math.round(boundary[3] * scale); + if (area.highlighted) { + context.fillStyle = area.highlighted ? cubeHighlightColor : (area.color || cubeColor); + context.fillRect(xmin, ymin, width, height); } } - } else { - if (options.excludeUnclassifiedObjects) { - continue; + if (area.label) { + context.fillStyle = "black"; + context.font = '60px sans-serif'; + context.textAlign = "center"; + var xcenter = xmin + (width * 0.5); + var ycenter = ymin + (height * 0.7); + context.fillText(translateLabel(area.label), xcenter, ycenter, 80); } } - const lastEntity = (i === numEntities - 1); - - const meshIds = []; + viewer.scene.glRedraw(); + } - for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshIds.length : entityMeshes [i + 1]; j < jlen; j++) { + const translateLabel = (function () { - const jj = entityMeshIds [j]; + const swizzleYUp = { + "NavCube.front": "NavCube.front", + "NavCube.back": "NavCube.back", + "NavCube.right": "NavCube.right", + "NavCube.left": "NavCube.left", + "NavCube.top": "NavCube.top", + "NavCube.bottom": "NavCube.bottom" + }; - const lastMesh = (jj === (numMeshes - 1)); - const meshId = entityId + ".mesh." + jj; + const swizzleZUp = { + "NavCube.front": "NavCube.front", + "NavCube.back": "NavCube.back", + "NavCube.right": "NavCube.right", + "NavCube.left": "NavCube.left", + "NavCube.top": "NavCube.top", + "NavCube.bottom": "NavCube.bottom" + }; - const color = decompressColor$8(meshColors.subarray((jj * 4), (jj * 4) + 3)); - const opacity = meshColors[(jj * 4) + 3] / 255.0; - - const tmpPositions = positions.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); - const tmpNormals = normals.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); - const tmpIndices = indices.subarray(meshIndices [jj], lastMesh ? indices.length : meshIndices [jj + 1]); - const tmpEdgeIndices = edgeIndices.subarray(meshEdgesIndices [jj], lastMesh ? edgeIndices.length : meshEdgesIndices [jj + 1]); + const defaultLabels = { + "NavCube.front": "FRONT", + "NavCube.back": "BACK", + "NavCube.right": "RIGHT", + "NavCube.left": "LEFT", + "NavCube.top": "TOP", + "NavCube.bottom": "BOTTOM" + }; - if (entityUsesInstancing [i] === 1) { + return function (key) { + const swizzle = zUp ? swizzleZUp : swizzleYUp; + const swizzledKey = swizzle ? swizzle[key] : null; + if (swizzledKey) { + return viewer.localeService.translate(swizzledKey) || defaultLabels[swizzledKey] || swizzledKey; + } + return key; + }; + })(); - const geometryId = "geometry." + jj; + this.setZUp = function () { + zUp = true; + areas = areasZUp; + this.clear(); + }; - if (!(geometryId in alreadyCreatedGeometries)) { + this.setYUp = function () { + zUp = false; + areas = areasYUp; + this.clear(); + }; - sceneModel.createGeometry({ - id: geometryId, - positionsCompressed: tmpPositions, - normalsCompressed: tmpNormals, - indices: tmpIndices, - edgeIndices: tmpEdgeIndices, - primitive: "triangles", - positionsDecodeMatrix: inflatedData.positionsDecodeMatrix, - }); + this.clear = function () { + context.fillStyle = cubeColor; + context.fillRect(0, 0, width, height); + for (var i = 0, len = areas.length; i < len; i++) { + const area = areas[i]; + area.highlighted = false; + } + paint(); + }; - alreadyCreatedGeometries [geometryId] = true; + this.getArea = function (uv) { + const s = uv[0] * width; + const t = height - (uv[1] * height); // Correct for our texture Y-flipping + for (var i = 0, len = areas.length; i < len; i++) { + const area = areas[i]; + const boundaries = area.boundaries; + for (var j = 0, lenj = boundaries.length; j < lenj; j++) { + const boundary = boundaries[j]; + if (s >= (boundary[0] * scale) && s <= ((boundary[0] + boundary[2]) * scale) && t >= (boundary[1] * scale) && t <= ((boundary[1] + boundary[3]) * scale)) { + return i; } + } + } + return -1; + }; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - color: color, - opacity: opacity, - matrix: entityMatrix, - geometryId: geometryId, - })); - - meshIds.push(meshId); - - } else { + this.setAreaHighlighted = function (areaId, highlighted) { + var area = areas[areaId]; + if (!area) { + throw "Area not found: " + areaId; + } + area.highlighted = !!highlighted; + paint(); + }; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - primitive: "triangles", - positionsCompressed: tmpPositions, - normalsCompressed: tmpNormals, - indices: tmpIndices, - edgeIndices: tmpEdgeIndices, - positionsDecodeMatrix: inflatedData.positionsDecodeMatrix, - color: color, - opacity: opacity - })); + this.getAreaDir = function (areaId) { + var area = areas[areaId]; + if (!area) { + throw "Unknown area: " + areaId; + } + return area.dir; + }; - meshIds.push(meshId); - } + this.getAreaUp = function (areaId) { + var area = areas[areaId]; + if (!area) { + throw "Unknown area: " + areaId; } + return area.up; + }; - if (meshIds.length) { + this.getImage = function () { + return this._textureCanvas; + }; - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: (entityIsObjects [i] === 1), - meshIds: meshIds - })); + this.destroy = function () { + if (this._textureCanvas) { + this._textureCanvas.parentNode.removeChild(this._textureCanvas); + this._textureCanvas = null; } - } + }; } -/** @private */ -const ParserV2 = { - version: 2, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$8(elements); - const inflatedData = inflate$8(deflatedData); - load$8(viewer, options, inflatedData, sceneModel); - } -}; +/** + * {@link Viewer} plugin that lets us look at the entire {@link Scene} from along a chosen axis or diagonal. + * + * [](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_NavCubePlugin) + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_NavCubePlugin)] + * + * ## Overview + * + * * Rotating the NavCube causes the Viewer's {@link Camera} to orbit its current + * point-of-interest. Conversely, orbiting the Camera causes the NavCube to rotate accordingly. + * * The faces of the NavCube are aligned with the Viewer's {@link Scene}'s World-space coordinate axis. Clicking on a face moves + * the Camera to look at the entire Scene along the corresponding axis. Clicking on an edge or a corner looks at + * the entire Scene along a diagonal. + * * The NavCube can be configured to either jump or fly the Camera to each new position. We can configure how tightly the + * NavCube fits the Scene to view, and when flying, we can configure how fast it flies. We can also configure whether the + * NavCube fits all objects to view, or just the currently visible objects. See below for a usage example. + * * Clicking the NavCube also sets {@link CameraControl#pivotPos} to the center of the fitted objects. + * + * ## Usage + * + * In the example below, we'll create a Viewer and add a NavCubePlugin, which will create a NavCube gizmo in the canvas + * with the given ID. Then we'll use the {@link XKTLoaderPlugin} to load a model into the Viewer's Scene. We can then + * use the NavCube to look at the model along each axis or diagonal. + * + * ````JavaScript + * import {Viewer, XKTLoaderPlugin, NavCubePlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [-3.93, 2.85, 27.01]; + * viewer.camera.look = [4.40, 3.72, 8.89]; + * viewer.camera.up = [-0.01, 0.99, 0.03]; + * + * const navCube = new NavCubePlugin(viewer, { + * + * canvasID: "myNavCubeCanvas", + * + * visible: true, // Initially visible (default) + * + * cameraFly: true, // Fly camera to each selected axis/diagonal + * cameraFitFOV: 45, // How much field-of-view the scene takes once camera has fitted it to view + * cameraFlyDuration: 0.5,// How long (in seconds) camera takes to fly to each new axis/diagonal + * + * fitVisible: false, // Fit whole scene, including invisible objects (default) + * + * synchProjection: false // Keep NavCube in perspective projection, even when camera switches to ortho (default) + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Duplex.ifc.xkt", + * edges: true + * }); + * ```` + */ +class NavCubePlugin extends Plugin { -/* + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg NavCubePlugin configuration. + * @param {String} [cfg.id="NavCube"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {String} [cfg.canvasId] ID of an existing HTML canvas to display the NavCube - either this or canvasElement is mandatory. When both values are given, the element reference is always preferred to the ID. + * @param {HTMLCanvasElement} [cfg.canvasElement] Reference of an existing HTML canvas to display the NavCube - either this or canvasId is mandatory. When both values are given, the element reference is always preferred to the ID. + * @param {Boolean} [cfg.visible=true] Initial visibility. + * @param {Boolean} [cfg.shadowVisible=true] Whether the shadow of the cube is visible. + * @param {String} [cfg.cameraFly=true] Whether the {@link Camera} flies or jumps to each selected axis or diagonal. + * @param {String} [cfg.cameraFitFOV=45] How much of the field-of-view, in degrees, that the 3D scene should fill the {@link Canvas} when the {@link Camera} moves to an axis or diagonal. + * @param {String} [cfg.cameraFlyDuration=0.5] When flying the {@link Camera} to each new axis or diagonal, how long, in seconds, that the Camera takes to get there. + * @param {String} [cfg.color="lightgrey] Custom uniform color for the faces of the NavCube. + * @param {String} [cfg.frontColor="#55FF55"] Custom color for the front face of the NavCube. Overrides ````color````. + * @param {String} [cfg.backColor="#55FF55"] Custom color for the back face of the NavCube. Overrides ````color````. + * @param {String} [cfg.leftColor="#FF5555"] Custom color for the left face of the NavCube. Overrides ````color````. + * @param {String} [cfg.rightColor="#FF5555"] Custom color for the right face of the NavCube. Overrides ````color````. + * @param {String} [cfg.topColor="#5555FF"] Custom color for the top face of the NavCube. Overrides ````color````. + * @param {String} [cfg.bottomColor="#5555FF"] Custom color for the bottom face of the NavCube. Overrides ````color````. + * @param {String} [cfg.hoverColor="rgba(0,0,0,0.4)"] Custom color for highlighting regions on the NavCube as we hover the pointer over them. + * @param {Boolean} [cfg.fitVisible=false] Sets whether the axis, corner and edge-aligned views will fit the + * view to the entire {@link Scene} or just to visible object-{@link Entity}s. Entitys are visible objects when {@link Entity#isObject} and {@link Entity#visible} are both ````true````. + * @param {Boolean} [cfg.synchProjection=false] Sets whether the NavCube switches between perspective and orthographic projections in synchrony with the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. + */ + constructor(viewer, cfg = {}) { -Parser for .XKT Format V3 + super("NavCube", viewer, cfg); -.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + viewer.navCube = this; - */ + var visible = true; -let pako$7 = window.pako || p; -if (!pako$7.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$7 = pako$7.default; -} + try { + this._navCubeScene = new Scene(viewer, { + canvasId: cfg.canvasId, + canvasElement: cfg.canvasElement, + transparent: true + }); -function extract$7(elements) { - return { - positions: elements[0], - normals: elements[1], - indices: elements[2], - edgeIndices: elements[3], - meshPositions: elements[4], - meshIndices: elements[5], - meshEdgesIndices: elements[6], - meshColors: elements[7], - entityIDs: elements[8], - entityMeshes: elements[9], - entityIsObjects: elements[10], - instancedPositionsDecodeMatrix: elements[11], - batchedPositionsDecodeMatrix: elements[12], - entityMeshIds: elements[13], - entityMatrices: elements[14], - entityUsesInstancing: elements[15] - }; -} + this._navCubeCanvas = this._navCubeScene.canvas.canvas; -function inflate$7(deflatedData) { - return { - positions: new Uint16Array(pako$7.inflate(deflatedData.positions).buffer), - normals: new Int8Array(pako$7.inflate(deflatedData.normals).buffer), - indices: new Uint32Array(pako$7.inflate(deflatedData.indices).buffer), - edgeIndices: new Uint32Array(pako$7.inflate(deflatedData.edgeIndices).buffer), - meshPositions: new Uint32Array(pako$7.inflate(deflatedData.meshPositions).buffer), - meshIndices: new Uint32Array(pako$7.inflate(deflatedData.meshIndices).buffer), - meshEdgesIndices: new Uint32Array(pako$7.inflate(deflatedData.meshEdgesIndices).buffer), - meshColors: new Uint8Array(pako$7.inflate(deflatedData.meshColors).buffer), - entityIDs: pako$7.inflate(deflatedData.entityIDs, {to: 'string'}), - entityMeshes: new Uint32Array(pako$7.inflate(deflatedData.entityMeshes).buffer), - entityIsObjects: new Uint8Array(pako$7.inflate(deflatedData.entityIsObjects).buffer), - instancedPositionsDecodeMatrix: new Float32Array(pako$7.inflate(deflatedData.instancedPositionsDecodeMatrix).buffer), - batchedPositionsDecodeMatrix: new Float32Array(pako$7.inflate(deflatedData.batchedPositionsDecodeMatrix).buffer), - entityMeshIds: new Uint32Array(pako$7.inflate(deflatedData.entityMeshIds).buffer), - entityMatrices: new Float32Array(pako$7.inflate(deflatedData.entityMatrices).buffer), - entityUsesInstancing: new Uint8Array(pako$7.inflate(deflatedData.entityUsesInstancing).buffer) - }; -} + this._navCubeScene.input.keyboardEnabled = false; // Don't want keyboard input in the NavCube -const decompressColor$7 = (function () { - const color2 = new Float32Array(3); - return function (color) { - color2[0] = color[0] / 255.0; - color2[1] = color[1] / 255.0; - color2[2] = color[2] / 255.0; - return color2; - }; -})(); + } catch (error) { + this.error(error); + return; + } -function load$7(viewer, options, inflatedData, sceneModel) { + const navCubeScene = this._navCubeScene; - sceneModel.positionsCompression = "precompressed"; - sceneModel.normalsCompression = "precompressed"; + navCubeScene.clearLights(); - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - const meshPositions = inflatedData.meshPositions; - const meshIndices = inflatedData.meshIndices; - const meshEdgesIndices = inflatedData.meshEdgesIndices; - const meshColors = inflatedData.meshColors; - const entityIDs = JSON.parse(inflatedData.entityIDs); - const entityMeshes = inflatedData.entityMeshes; - const entityIsObjects = inflatedData.entityIsObjects; - const entityMeshIds = inflatedData.entityMeshIds; - const entityMatrices = inflatedData.entityMatrices; - const entityUsesInstancing = inflatedData.entityUsesInstancing; + new DirLight(navCubeScene, {dir: [0.4, -0.4, 0.8], color: [0.8, 1.0, 1.0], intensity: 1.0, space: "view"}); + new DirLight(navCubeScene, {dir: [-0.8, -0.3, -0.4], color: [0.8, 0.8, 0.8], intensity: 1.0, space: "view"}); + new DirLight(navCubeScene, {dir: [0.8, -0.6, -0.8], color: [1.0, 1.0, 1.0], intensity: 1.0, space: "view"}); - const numMeshes = meshPositions.length; - const numEntities = entityMeshes.length; + this._navCubeCamera = navCubeScene.camera; + this._navCubeCamera.ortho.scale = 7.0; + this._navCubeCamera.ortho.near = 0.1; + this._navCubeCamera.ortho.far = 2000; - const _alreadyCreatedGeometries = {}; + navCubeScene.edgeMaterial.edgeColor = [0.2, 0.2, 0.2]; + navCubeScene.edgeMaterial.edgeAlpha = 0.6; - for (let i = 0; i < numEntities; i++) { + this._zUp = Boolean(viewer.camera.zUp); - const xktEntityId = entityIDs [i]; - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; - const entityMatrix = entityMatrices.subarray((i * 16), (i * 16) + 16); + var self = this; - if (metaObject) { + this._synchCamera = (function () { + var matrix = math.rotationMat4c(-90 * math.DEGTORAD, 1, 0, 0); + var eyeLookVec = math.vec3(); + var eyeLookVecCube = math.vec3(); + var upCube = math.vec3(); + return function () { + var eye = viewer.camera.eye; + var look = viewer.camera.look; + var up = viewer.camera.up; + eyeLookVec = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(eye, look, eyeLookVec)), 5); + if (self._zUp) { // +Z up + math.transformVec3(matrix, eyeLookVec, eyeLookVecCube); + math.transformVec3(matrix, up, upCube); + self._navCubeCamera.look = [0, 0, 0]; + self._navCubeCamera.eye = math.transformVec3(matrix, eyeLookVec, eyeLookVecCube); + self._navCubeCamera.up = math.transformPoint3(matrix, up, upCube); + } else { // +Y up + self._navCubeCamera.look = [0, 0, 0]; + self._navCubeCamera.eye = eyeLookVec; + self._navCubeCamera.up = up; + } + }; + }()); - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } + this._cubeTextureCanvas = new CubeTextureCanvas(viewer, cfg); - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } + this._cubeSampler = new Texture(navCubeScene, { + image: this._cubeTextureCanvas.getImage(), + flipY: true, + wrapS: ClampToEdgeWrapping, + wrapT: ClampToEdgeWrapping + }); - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + this._cubeMesh = new Mesh(navCubeScene, { + geometry: new ReadableGeometry(navCubeScene, { + primitive: "triangles", + normals: [ + 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, + 0, 1, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, -1, + 0, 0, -1, 0, 0, -1, 0, 0, -1 + ], + positions: [ + 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, 1, 1, 1, -1, -1, + 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, + 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1 + ], + uv: [ + 0.5, 0.6666, 0.25, 0.6666, 0.25, 0.3333, 0.5, 0.3333, 0.5, 0.6666, 0.5, 0.3333, 0.75, 0.3333, 0.75, 0.6666, + 0.5, 0.6666, 0.5, 1, 0.25, 1, 0.25, 0.6666, 0.25, 0.6666, 0.0, 0.6666, 0.0, 0.3333, 0.25, 0.3333, + 0.25, 0, 0.50, 0, 0.50, 0.3333, 0.25, 0.3333, 0.75, 0.3333, 1.0, 0.3333, 1.0, 0.6666, 0.75, 0.6666 + ], + indices: [ + 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, + 18, 19, 20, 21, 22, 20, 22, 23 + ] + }), + material: new PhongMaterial(navCubeScene, { + diffuse: [0.4, 0.4, 0.4], + specular: [0.4, 0.4, 0.4], + emissive: [.6, .6, .6], + diffuseMap: this._cubeSampler, + emissiveMap: this._cubeSampler + }), + visible: !!visible, + edges: true + }); - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; - } + this._shadow = cfg.shadowVisible === false ? null : new Mesh(navCubeScene, { + geometry: new ReadableGeometry(navCubeScene, buildCylinderGeometry({ + center: [0, 0, 0], + radiusTop: 0.001, + radiusBottom: 1.4, + height: 0.01, + radialSegments: 20, + heightSegments: 1, + openEnded: true + })), + material: new PhongMaterial(navCubeScene, { + diffuse: [0.0, 0.0, 0.0], specular: [0, 0, 0], emissive: [0.0, 0.0, 0.0], alpha: 0.5 + }), + position: [0, -1.5, 0], + visible: !!visible, + pickable: false, + backfaces: false + }); + + this._onCameraMatrix = viewer.camera.on("matrix", this._synchCamera); + this._onCameraWorldAxis = viewer.camera.on("worldAxis", () => { + if (viewer.camera.zUp) { + this._zUp = true; + this._cubeTextureCanvas.setZUp(); + this._repaint(); + this._synchCamera(); + } else if (viewer.camera.yUp) { + this._zUp = false; + this._cubeTextureCanvas.setYUp(); + this._repaint(); + this._synchCamera(); } - } else { - if (options.excludeUnclassifiedObjects) { - continue; + }); + this._onCameraFOV = viewer.camera.perspective.on("fov", (fov) => { + if (this._synchProjection) { + this._navCubeCamera.perspective.fov = fov; + } + }); + this._onCameraProjection = viewer.camera.on("projection", (projection) => { + if (this._synchProjection) { + this._navCubeCamera.projection = (projection === "ortho" || projection === "perspective") ? projection : "perspective"; } + }); + + var lastAreaId = -1; + + function actionMove(posX, posY) { + var yawInc = (posX - lastX) * -sensitivity; + var pitchInc = (posY - lastY) * -sensitivity; + viewer.camera.orbitYaw(yawInc); + viewer.camera.orbitPitch(-pitchInc); + lastX = posX; + lastY = posY; } - const lastEntity = (i === numEntities - 1); + function getCoordsWithinElement(event) { + var coords = [0, 0]; + if (!event) { + event = window.event; + coords[0] = event.x; + coords[1] = event.y; + } else { + var element = event.target; + var totalOffsetLeft = 0; + var totalOffsetTop = 0; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + coords[0] = event.pageX - totalOffsetLeft; + coords[1] = event.pageY - totalOffsetTop; + } + return coords; + } - const meshIds = []; + { + var downX = null; + var downY = null; + var down = false; + var over = false; + var sensitivity = 0.5; - for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshIds.length : entityMeshes [i + 1]; j < jlen; j++) { - var jj = entityMeshIds [j]; + var lastX; + var lastY; - const lastMesh = (jj === (numMeshes - 1)); - const meshId = entityId + ".mesh." + jj; - const color = decompressColor$7(meshColors.subarray((jj * 4), (jj * 4) + 3)); - const opacity = meshColors[(jj * 4) + 3] / 255.0; + self._navCubeCanvas.addEventListener("mouseenter", self._onMouseEnter = function (e) { + over = true; + }); - var tmpPositions = positions.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); - var tmpNormals = normals.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); - var tmpIndices = indices.subarray(meshIndices [jj], lastMesh ? indices.length : meshIndices [jj + 1]); - var tmpEdgeIndices = edgeIndices.subarray(meshEdgesIndices [jj], lastMesh ? edgeIndices.length : meshEdgesIndices [jj + 1]); - if (entityUsesInstancing [i] === 1) { - var geometryId = "geometry." + jj; + self._navCubeCanvas.addEventListener("mouseleave", self._onMouseLeave = function (e) { + over = false; + }); - if (!(geometryId in _alreadyCreatedGeometries)) { + self._navCubeCanvas.addEventListener("mousedown", self._onMouseDown = function (e) { + if (e.which !== 1) { + return; + } + downX = e.x; + downY = e.y; + lastX = e.clientX; + lastY = e.clientY; + var canvasPos = getCoordsWithinElement(e); + var hit = navCubeScene.pick({ + canvasPos: canvasPos + }); + if (hit) { + down = true; - sceneModel.createGeometry({ - id: geometryId, - positionsCompressed: tmpPositions, - normalsCompressed: tmpNormals, - indices: tmpIndices, - edgeIndices: tmpEdgeIndices, - primitive: "triangles", - positionsDecodeMatrix: inflatedData.instancedPositionsDecodeMatrix - }); + } else { + down = false; + } + }); - _alreadyCreatedGeometries [geometryId] = true; + document.addEventListener("mouseup", self._onMouseUp = function (e) { + if (e.which !== 1) {// Left button + return; + } + down = false; + if (downX === null) { + return; + } + var canvasPos = getCoordsWithinElement(e); + var hit = navCubeScene.pick({ + canvasPos: canvasPos, + pickSurface: true + }); + if (hit) { + if (hit.uv) { + var areaId = self._cubeTextureCanvas.getArea(hit.uv); + if (areaId >= 0) { + document.body.style.cursor = "pointer"; + if (lastAreaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); + self._repaint(); + lastAreaId = -1; + } + if (areaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(areaId, true); + lastAreaId = areaId; + self._repaint(); + if (e.x < (downX - 3) || e.x > (downX + 3) || e.y < (downY - 3) || e.y > (downY + 3)) { + return; + } + var dir = self._cubeTextureCanvas.getAreaDir(areaId); + if (dir) { + var up = self._cubeTextureCanvas.getAreaUp(areaId); + flyTo(dir, up, function () { + if (lastAreaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); + self._repaint(); + lastAreaId = -1; + } + document.body.style.cursor = "pointer"; + if (lastAreaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); + self._repaint(); + lastAreaId = -1; + } + if (areaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(areaId, false); + lastAreaId = -1; + self._repaint(); + } + }); + } + } + } + } } + }); - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - color: color, - opacity: opacity, - matrix: entityMatrix, - geometryId: geometryId, - })); + document.addEventListener("mousemove", self._onMouseMove = function (e) { + if (lastAreaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); + self._repaint(); + lastAreaId = -1; + } + if (e.buttons === 1 && !down) { + return; + } + if (down) { + var posX = e.clientX; + var posY = e.clientY; + document.body.style.cursor = "move"; + actionMove(posX, posY); + return; + } + if (!over) { + return; + } + var canvasPos = getCoordsWithinElement(e); + var hit = navCubeScene.pick({ + canvasPos: canvasPos, + pickSurface: true + }); + if (hit) { + if (hit.uv) { + document.body.style.cursor = "pointer"; + var areaId = self._cubeTextureCanvas.getArea(hit.uv); + if (areaId === lastAreaId) { + return; + } + if (lastAreaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); + } + if (areaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(areaId, true); + self._repaint(); + lastAreaId = areaId; + } + } + } else { + document.body.style.cursor = "default"; + if (lastAreaId >= 0) { + self._cubeTextureCanvas.setAreaHighlighted(lastAreaId, false); + self._repaint(); + lastAreaId = -1; + } + } + }); - meshIds.push(meshId); + var flyTo = (function () { + var center = math.vec3(); + return function (dir, up, ok) { + var aabb = self._fitVisible ? viewer.scene.getAABB(viewer.scene.visibleObjectIds) : viewer.scene.aabb; + var diag = math.getAABB3Diag(aabb); + math.getAABB3Center(aabb, center); + var dist = Math.abs(diag / Math.tan(self._cameraFitFOV * math.DEGTORAD)); + viewer.cameraControl.pivotPos = center; + if (self._cameraFly) { + viewer.cameraFlight.flyTo({ + look: center, + eye: [center[0] - (dist * dir[0]), center[1] - (dist * dir[1]), center[2] - (dist * dir[2])], + up: up || [0, 1, 0], + orthoScale: diag * 1.1, + fitFOV: self._cameraFitFOV, + duration: self._cameraFlyDuration + }, ok); + } else { + viewer.cameraFlight.jumpTo({ + look: center, + eye: [center[0] - (dist * dir[0]), center[1] - (dist * dir[1]), center[2] - (dist * dir[2])], + up: up || [0, 1, 0], + orthoScale: diag * 1.1, + fitFOV: self._cameraFitFOV + }, ok); + } + }; + })(); + } - } else { + this._onUpdated = viewer.localeService.on("updated", () => { + this._cubeTextureCanvas.clear(); + this._repaint(); + }); - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - primitive: "triangles", - positionsCompressed: tmpPositions, - normalsCompressed: tmpNormals, - indices: tmpIndices, - edgeIndices: tmpEdgeIndices, - positionsDecodeMatrix: inflatedData.batchedPositionsDecodeMatrix, - color: color, - opacity: opacity - })); + this.setVisible(cfg.visible); + this.setCameraFitFOV(cfg.cameraFitFOV); + this.setCameraFly(cfg.cameraFly); + this.setCameraFlyDuration(cfg.cameraFlyDuration); + this.setFitVisible(cfg.fitVisible); + this.setSynchProjection(cfg.synchProjection); + } - meshIds.push(meshId); - } + send(name, value) { + switch (name) { + case "language": + this._cubeTextureCanvas.clear(); + this._repaint(); // CubeTextureCanvas gets language from Viewer + break; } + } - if (meshIds.length) { - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: (entityIsObjects [i] === 1), - meshIds: meshIds - })); - } + _repaint() { + const image = this._cubeTextureCanvas.getImage(); + this._cubeMesh.material.diffuseMap.image = image; + this._cubeMesh.material.emissiveMap.image = image; } -} -/** @private */ -const ParserV3 = { - version: 3, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$7(elements); - const inflatedData = inflate$7(deflatedData); - load$7(viewer, options, inflatedData, sceneModel); + /** + * Sets if the NavCube is visible. + * + * @param {Boolean} visible Whether or not the NavCube is visible. + */ + setVisible(visible = true) { + if (!this._navCubeCanvas) { + return; + } + this._cubeMesh.visible = visible; + if (this._shadow) { + this._shadow.visible = visible; + } + this._navCubeCanvas.style.visibility = visible ? "visible" : "hidden"; } -}; -/* + /** + * Gets if the NavCube is visible. + * + * @return {Boolean} True when the NavCube is visible. + */ + getVisible() { + if (!this._navCubeCanvas) { + return false; + } + return this._cubeMesh.visible; + } -Parser for .XKT Format V4 -.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + /** + * Sets whether the axis, corner and edge-aligned views will fit the + * view to the entire {@link Scene} or just to visible object-{@link Entity}s. + * + * Entitys are visible objects when {@link Entity#isObject} and {@link Entity#visible} are both ````true````. + * + * @param {Boolean} fitVisible Set ````true```` to fit only visible object-Entitys. + */ + setFitVisible(fitVisible = false) { + this._fitVisible = fitVisible; + } - */ + /** + * Gets whether the axis, corner and edge-aligned views will fit the + * view to the entire {@link Scene} or just to visible object-{@link Entity}s. + * + * Entitys are visible objects when {@link Entity#isObject} and {@link Entity#visible} are both ````true````. + * + * @return {Boolean} True when fitting only visible object-Entitys. + */ + getFitVisible() { + return this._fitVisible; + } -let pako$6 = window.pako || p; -if (!pako$6.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$6 = pako$6.default; -} + /** + * Sets whether the {@link Camera} flies or jumps to each selected axis or diagonal. + * + * Default is ````true````, to fly. + * + * @param {Boolean} cameraFly Set ````true```` to fly, else ````false```` to jump. + */ + setCameraFly(cameraFly = true) { + this._cameraFly = cameraFly; + } -function extract$6(elements) { - return { - positions: elements[0], - normals: elements[1], - indices: elements[2], - edgeIndices: elements[3], - decodeMatrices: elements[4], - matrices: elements[5], - eachPrimitivePositionsAndNormalsPortion: elements[6], - eachPrimitiveIndicesPortion: elements[7], - eachPrimitiveEdgeIndicesPortion: elements[8], - eachPrimitiveDecodeMatricesPortion: elements[9], - eachPrimitiveColor: elements[10], - primitiveInstances: elements[11], - eachEntityId: elements[12], - eachEntityPrimitiveInstancesPortion: elements[13], - eachEntityMatricesPortion: elements[14], - eachEntityMatrix: elements[15] - }; -} + /** + * Gets whether the {@link Camera} flies or jumps to each selected axis or diagonal. + * + * Default is ````true````, to fly. + * + * @returns {Boolean} Returns ````true```` to fly, else ````false```` to jump. + */ + getCameraFly() { + return this._cameraFly; + } -function inflate$6(deflatedData) { - return { - positions: new Uint16Array(pako$6.inflate(deflatedData.positions).buffer), - normals: new Int8Array(pako$6.inflate(deflatedData.normals).buffer), - indices: new Uint32Array(pako$6.inflate(deflatedData.indices).buffer), - edgeIndices: new Uint32Array(pako$6.inflate(deflatedData.edgeIndices).buffer), - decodeMatrices: new Float32Array(pako$6.inflate(deflatedData.decodeMatrices).buffer), - matrices: new Float32Array(pako$6.inflate(deflatedData.matrices).buffer), - eachPrimitivePositionsAndNormalsPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitivePositionsAndNormalsPortion).buffer), - eachPrimitiveIndicesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitiveIndicesPortion).buffer), - eachPrimitiveEdgeIndicesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitiveEdgeIndicesPortion).buffer), - eachPrimitiveDecodeMatricesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitiveDecodeMatricesPortion).buffer), - eachPrimitiveColor: new Uint8Array(pako$6.inflate(deflatedData.eachPrimitiveColor).buffer), - primitiveInstances: new Uint32Array(pako$6.inflate(deflatedData.primitiveInstances).buffer), - eachEntityId: pako$6.inflate(deflatedData.eachEntityId, {to: 'string'}), - eachEntityPrimitiveInstancesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachEntityPrimitiveInstancesPortion).buffer), - eachEntityMatricesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachEntityMatricesPortion).buffer) - }; -} + /** + * Sets how much of the field-of-view, in degrees, that the {@link Scene} should + * fill the canvas when flying or jumping the {@link Camera} to each selected axis or diagonal. + * + * Default value is ````45````. + * + * @param {Number} cameraFitFOV New FOV value. + */ + setCameraFitFOV(cameraFitFOV = 45) { + this._cameraFitFOV = cameraFitFOV; + } -const decompressColor$6 = (function () { - const color2 = new Float32Array(3); - return function (color) { - color2[0] = color[0] / 255.0; - color2[1] = color[1] / 255.0; - color2[2] = color[2] / 255.0; - return color2; - }; -})(); + /** + * Gets how much of the field-of-view, in degrees, that the {@link Scene} should + * fill the canvas when flying or jumping the {@link Camera} to each selected axis or diagonal. + * + * Default value is ````45````. + * + * @returns {Number} Current FOV value. + */ + getCameraFitFOV() { + return this._cameraFitFOV; + } -function load$6(viewer, options, inflatedData, sceneModel) { + /** + * When flying the {@link Camera} to each new axis or diagonal, sets how long, in seconds, that the Camera takes to get there. + * + * Default is ````0.5````. + * + * @param {Boolean} cameraFlyDuration Camera flight duration in seconds. + */ + setCameraFlyDuration(cameraFlyDuration = 0.5) { + this._cameraFlyDuration = cameraFlyDuration; + } - sceneModel.positionsCompression = "precompressed"; - sceneModel.normalsCompression = "precompressed"; + /** + * When flying the {@link Camera} to each new axis or diagonal, gets how long, in seconds, that the Camera takes to get there. + * + * Default is ````0.5````. + * + * @returns {Boolean} Camera flight duration in seconds. + */ + getCameraFlyDuration() { + return this._cameraFlyDuration; + } - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - const decodeMatrices = inflatedData.decodeMatrices; - const matrices = inflatedData.matrices; + /** + * Sets whether the NavCube switches between perspective and orthographic projections in synchrony with + * the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. + * + * @param {Boolean} synchProjection Set ````true```` to keep NavCube projection synchronized with {@link Camera#projection}. + */ + setSynchProjection(synchProjection = false) { + this._synchProjection = synchProjection; + } - const eachPrimitivePositionsAndNormalsPortion = inflatedData.eachPrimitivePositionsAndNormalsPortion; - const eachPrimitiveIndicesPortion = inflatedData.eachPrimitiveIndicesPortion; - const eachPrimitiveEdgeIndicesPortion = inflatedData.eachPrimitiveEdgeIndicesPortion; - const eachPrimitiveDecodeMatricesPortion = inflatedData.eachPrimitiveDecodeMatricesPortion; - const eachPrimitiveColor = inflatedData.eachPrimitiveColor; + /** + * Gets whether the NavCube switches between perspective and orthographic projections in synchrony with + * the {@link Camera}. When ````false````, the NavCube will always be rendered with perspective projection. + * + * @return {Boolean} True when NavCube projection is synchronized with {@link Camera#projection}. + */ + getSynchProjection() { + return this._synchProjection; + } - const primitiveInstances = inflatedData.primitiveInstances; + /** + * Destroys this NavCubePlugin. + * + * Does not destroy the canvas the NavCubePlugin was configured with. + */ + destroy() { - const eachEntityId = JSON.parse(inflatedData.eachEntityId); - const eachEntityPrimitiveInstancesPortion = inflatedData.eachEntityPrimitiveInstancesPortion; - const eachEntityMatricesPortion = inflatedData.eachEntityMatricesPortion; + if (this._navCubeCanvas) { - const numPrimitives = eachPrimitivePositionsAndNormalsPortion.length; - const numPrimitiveInstances = primitiveInstances.length; - const primitiveInstanceCounts = new Uint8Array(numPrimitives); // For each mesh, how many times it is instanced - const orderedPrimitiveIndexes = new Uint32Array(numPrimitives); // For each mesh, its index sorted into runs that share the same decode matrix + this.viewer.localeService.off(this._onUpdated); + this.viewer.camera.off(this._onCameraMatrix); + this.viewer.camera.off(this._onCameraWorldAxis); + this.viewer.camera.perspective.off(this._onCameraFOV); + this.viewer.camera.off(this._onCameraProjection); - const numEntities = eachEntityId.length; + this._navCubeCanvas.removeEventListener("mouseenter", this._onMouseEnter); + this._navCubeCanvas.removeEventListener("mouseleave", this._onMouseLeave); + this._navCubeCanvas.removeEventListener("mousedown", this._onMouseDown); - // Get lookup that orders primitives into runs that share the same decode matrices; - // this is used to create meshes in batches that use the same decode matrix + document.removeEventListener("mousemove", this._onMouseMove); + document.removeEventListener("mouseup", this._onMouseUp); - for (let primitiveIndex = 0; primitiveIndex < numPrimitives; primitiveIndex++) { - orderedPrimitiveIndexes[primitiveIndex] = primitiveIndex; - } + this._navCubeCanvas = null; + this._cubeTextureCanvas.destroy(); + this._cubeTextureCanvas = null; - orderedPrimitiveIndexes.sort((i1, i2) => { - if (eachPrimitiveDecodeMatricesPortion[i1] < eachPrimitiveDecodeMatricesPortion[i2]) { - return -1; - } - if (eachPrimitiveDecodeMatricesPortion[i1] > eachPrimitiveDecodeMatricesPortion[i2]) { - return 1; + this._onMouseEnter = null; + this._onMouseLeave = null; + this._onMouseDown = null; + this._onMouseMove = null; + this._onMouseUp = null; } - return 0; - }); - // Count instances of each primitive + this._navCubeScene.destroy(); + this._navCubeScene = null; + this._cubeMesh = null; + this._shadow = null; - for (let primitiveInstanceIndex = 0; primitiveInstanceIndex < numPrimitiveInstances; primitiveInstanceIndex++) { - const primitiveIndex = primitiveInstances[primitiveInstanceIndex]; - primitiveInstanceCounts[primitiveIndex]++; + super.destroy(); } +} - // Map batched primitives to the entities that will use them +const tempVec3a$4 = math.vec3(); - const batchedPrimitiveEntityIndexes = {}; +/** + * @private + */ +class OBJSceneGraphLoader { - for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + /** + * Loads OBJ and MTL from file(s) into a {@link Node}. + * + * @static + * @param {Node} modelNode Node to load into. + * @param {String} src Path to OBJ file. + * @param {Object} params Loading options. + */ + load(modelNode, src, params = {}) { - const lastEntityIndex = (numEntities - 1); - const atLastEntity = (entityIndex === lastEntityIndex); - const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; - const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + var spinner = modelNode.scene.canvas.spinner; + spinner.processes++; - for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + loadOBJ(modelNode, src, function (state) { + loadMTLs(modelNode, state, function () { - const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; - const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; - const isInstancedPrimitive = (primitiveInstanceCount > 1); - - if (!isInstancedPrimitive) { - batchedPrimitiveEntityIndexes[primitiveIndex] = entityIndex; - } - } - } - - // Create 1) geometries for instanced primitives, and 2) meshes for batched primitives. We create all the - // batched meshes now, before we create entities, because we're creating the batched meshes in runs that share - // the same decode matrices. Each run of meshes with the same decode matrix will end up in the same - // BatchingLayer; the VBOSceneModel#createMesh() method starts a new BatchingLayer each time the decode - // matrix has changed since the last invocation of that method, hence why we need to order batched meshes - // in runs like this. - - for (let primitiveIndex = 0; primitiveIndex < numPrimitives; primitiveIndex++) { - - const orderedPrimitiveIndex = orderedPrimitiveIndexes[primitiveIndex]; - - const atLastPrimitive = (orderedPrimitiveIndex === (numPrimitives - 1)); - - const primitiveInstanceCount = primitiveInstanceCounts[orderedPrimitiveIndex]; - const isInstancedPrimitive = (primitiveInstanceCount > 1); - - const color = decompressColor$6(eachPrimitiveColor.subarray((orderedPrimitiveIndex * 4), (orderedPrimitiveIndex * 4) + 3)); - const opacity = eachPrimitiveColor[(orderedPrimitiveIndex * 4) + 3] / 255.0; - - const primitivePositions = positions.subarray(eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex], atLastPrimitive ? positions.length : eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex + 1]); - const primitiveNormals = normals.subarray(eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex], atLastPrimitive ? normals.length : eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex + 1]); - const primitiveIndices = indices.subarray(eachPrimitiveIndicesPortion [orderedPrimitiveIndex], atLastPrimitive ? indices.length : eachPrimitiveIndicesPortion [orderedPrimitiveIndex + 1]); - const primitiveEdgeIndices = edgeIndices.subarray(eachPrimitiveEdgeIndicesPortion [orderedPrimitiveIndex], atLastPrimitive ? edgeIndices.length : eachPrimitiveEdgeIndicesPortion [orderedPrimitiveIndex + 1]); - const primitiveDecodeMatrix = decodeMatrices.subarray(eachPrimitiveDecodeMatricesPortion [orderedPrimitiveIndex], eachPrimitiveDecodeMatricesPortion [orderedPrimitiveIndex] + 16); - - if (isInstancedPrimitive) { - - // Primitive instanced by more than one entity, and has positions in Model-space + createMeshes(modelNode, state); - var geometryId = "geometry" + orderedPrimitiveIndex; // These IDs are local to the VBOSceneModel + spinner.processes--; - sceneModel.createGeometry({ - id: geometryId, - primitive: "triangles", - positionsCompressed: primitivePositions, - normalsCompressed: primitiveNormals, - indices: primitiveIndices, - edgeIndices: primitiveEdgeIndices, - positionsDecodeMatrix: primitiveDecodeMatrix + core.scheduleTask(function () { + modelNode.fire("loaded", true, false); + }); }); + }); + } - } else { - - // Primitive is used only by one entity, and has positions pre-transformed into World-space - - const meshId = orderedPrimitiveIndex; // These IDs are local to the VBOSceneModel - - const entityIndex = batchedPrimitiveEntityIndexes[orderedPrimitiveIndex]; - eachEntityId[entityIndex]; - - const meshDefaults = {}; // TODO: get from lookup from entity IDs - - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - primitive: "triangles", - positionsCompressed: primitivePositions, - normalsCompressed: primitiveNormals, - indices: primitiveIndices, - edgeIndices: primitiveEdgeIndices, - positionsDecodeMatrix: primitiveDecodeMatrix, - color: color, - opacity: opacity - })); + /** + * Parses OBJ and MTL text strings into a {@link Node}. + * + * @static + * @param {Node} modelNode Node to load into. + * @param {String} objText OBJ text string. + * @param {String} [mtlText] MTL text string. + * @param {String} [basePath] Base path for external resources. + */ + parse(modelNode, objText, mtlText, basePath) { + if (!objText) { + this.warn("load() param expected: objText"); + return; + } + var state = parseOBJ(modelNode, objText, null); + if (mtlText) { + parseMTL(modelNode, mtlText, basePath); } + createMeshes(modelNode, state); + modelNode.src = null; + modelNode.fire("loaded", true, false); } +} - let countInstances = 0; - - for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { - - const lastEntityIndex = (numEntities - 1); - const atLastEntity = (entityIndex === lastEntityIndex); - const entityId = eachEntityId[entityIndex]; - const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; - const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; +//-------------------------------------------------------------------------------------------- +// Loads OBJ +// +// Parses OBJ into an intermediate state object. The object will contain geometry data +// and material IDs from which meshes can be created later. The object will also +// contain a list of filenames of the MTL files referenced by the OBJ, is any. +// +// Originally based on the THREE.js OBJ and MTL loaders: +// +// https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/OBJLoader.js +// https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/MTLLoader.js +//-------------------------------------------------------------------------------------------- - const meshIds = []; +var loadOBJ = function (modelNode, url, ok) { + loadFile(url, function (text) { + var state = parseOBJ(modelNode, text, url); + ok(state); + }, + function (error) { + modelNode.error(error); + }); +}; - for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { +var parseOBJ = (function () { - const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; - const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; - const isInstancedPrimitive = (primitiveInstanceCount > 1); + const regexp = { + // v float float float + vertex_pattern: /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/, + // vn float float float + normal_pattern: /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/, + // vt float float + uv_pattern: /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/, + // f vertex vertex vertex + face_vertex: /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/, + // f vertex/uv vertex/uv vertex/uv + face_vertex_uv: /^f\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+))?/, + // f vertex/uv/normal vertex/uv/normal vertex/uv/normal + face_vertex_uv_normal: /^f\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+)\/(-?\d+))?/, + // f vertex//normal vertex//normal vertex//normal + face_vertex_normal: /^f\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)(?:\s+(-?\d+)\/\/(-?\d+))?/, + // o object_name | g group_name + object_pattern: /^[og]\s*(.+)?/, + // s boolean + smoothing_pattern: /^s\s+(\d+|on|off)/, + // mtllib file_reference + material_library_pattern: /^mtllib /, + // usemtl material_name + material_use_pattern: /^usemtl / + }; - if (isInstancedPrimitive) { + return function (modelNode, text, url) { - const meshDefaults = {}; // TODO: get from lookup from entity IDs + url = url || ""; - const meshId = "instance." + countInstances++; - const geometryId = "geometry" + primitiveIndex; - const matricesIndex = (eachEntityMatricesPortion [entityIndex]) * 16; - const matrix = matrices.subarray(matricesIndex, matricesIndex + 16); + var state = { + src: url, + basePath: getBasePath(url), + objects: [], + object: {}, + positions: [], + normals: [], + uv: [], + materialLibraries: {} + }; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - matrix: matrix - })); + startObject(state, "", false); - meshIds.push(meshId); + // Parts of this parser logic are derived from the THREE.js OBJ loader: + // https://github.com/mrdoob/three.js/blob/dev/examples/js/loaders/OBJLoader.js - } else { - meshIds.push(primitiveIndex); - } + if (text.indexOf('\r\n') !== -1) { + // This is faster than String.split with regex that splits on both + text = text.replace('\r\n', '\n'); } - if (meshIds.length > 0) { - - const entityDefaults = {}; // TODO: get from lookup from entity IDs - - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, ///////////////// TODO: If metaobject exists - meshIds: meshIds - })); - } - } -} + var lines = text.split('\n'); + var line = '', lineFirstChar = '', lineSecondChar = ''; + var lineLength = 0; + var result = []; -/** @private */ -const ParserV4 = { - version: 4, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$6(elements); - const inflatedData = inflate$6(deflatedData); - load$6(viewer, options, inflatedData, sceneModel); - } -}; + // Faster to just trim left side of the line. Use if available. + var trimLeft = (typeof ''.trimLeft === 'function'); -/* + for (var i = 0, l = lines.length; i < l; i++) { - Parser for .XKT Format V5 + line = lines[i]; -.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + line = trimLeft ? line.trimLeft() : line.trim(); - */ + lineLength = line.length; -let pako$5 = window.pako || p; -if (!pako$5.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$5 = pako$5.default; -} + if (lineLength === 0) { + continue; + } -function extract$5(elements) { - return { - positions: elements[0], - normals: elements[1], - indices: elements[2], - edgeIndices: elements[3], - matrices: elements[4], - eachPrimitivePositionsAndNormalsPortion: elements[5], - eachPrimitiveIndicesPortion: elements[6], - eachPrimitiveEdgeIndicesPortion: elements[7], - eachPrimitiveColor: elements[8], - primitiveInstances: elements[9], - eachEntityId: elements[10], - eachEntityPrimitiveInstancesPortion: elements[11], - eachEntityMatricesPortion: elements[12] - }; -} + lineFirstChar = line.charAt(0); -function inflate$5(deflatedData) { - return { - positions: new Float32Array(pako$5.inflate(deflatedData.positions).buffer), - normals: new Int8Array(pako$5.inflate(deflatedData.normals).buffer), - indices: new Uint32Array(pako$5.inflate(deflatedData.indices).buffer), - edgeIndices: new Uint32Array(pako$5.inflate(deflatedData.edgeIndices).buffer), - matrices: new Float32Array(pako$5.inflate(deflatedData.matrices).buffer), - eachPrimitivePositionsAndNormalsPortion: new Uint32Array(pako$5.inflate(deflatedData.eachPrimitivePositionsAndNormalsPortion).buffer), - eachPrimitiveIndicesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachPrimitiveIndicesPortion).buffer), - eachPrimitiveEdgeIndicesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachPrimitiveEdgeIndicesPortion).buffer), - eachPrimitiveColor: new Uint8Array(pako$5.inflate(deflatedData.eachPrimitiveColor).buffer), - primitiveInstances: new Uint32Array(pako$5.inflate(deflatedData.primitiveInstances).buffer), - eachEntityId: pako$5.inflate(deflatedData.eachEntityId, {to: 'string'}), - eachEntityPrimitiveInstancesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachEntityPrimitiveInstancesPortion).buffer), - eachEntityMatricesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachEntityMatricesPortion).buffer) - }; -} + if (lineFirstChar === '#') { + continue; + } -const decompressColor$5 = (function () { - const color2 = new Float32Array(3); - return function (color) { - color2[0] = color[0] / 255.0; - color2[1] = color[1] / 255.0; - color2[2] = color[2] / 255.0; - return color2; - }; -})(); + if (lineFirstChar === 'v') { -function load$5(viewer, options, inflatedData, sceneModel) { + lineSecondChar = line.charAt(1); - sceneModel.positionsCompression = "disabled"; // Positions in XKT V4 are floats, which we never quantize, for precision with big models - sceneModel.normalsCompression = "precompressed"; // Normals are oct-encoded though + if (lineSecondChar === ' ' && (result = regexp.vertex_pattern.exec(line)) !== null) { - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - const matrices = inflatedData.matrices; + // 0 1 2 3 + // ['v 1.0 2.0 3.0', '1.0', '2.0', '3.0'] - const eachPrimitivePositionsAndNormalsPortion = inflatedData.eachPrimitivePositionsAndNormalsPortion; - const eachPrimitiveIndicesPortion = inflatedData.eachPrimitiveIndicesPortion; - const eachPrimitiveEdgeIndicesPortion = inflatedData.eachPrimitiveEdgeIndicesPortion; - const eachPrimitiveColor = inflatedData.eachPrimitiveColor; + state.positions.push( + parseFloat(result[1]), + parseFloat(result[2]), + parseFloat(result[3]) + ); - const primitiveInstances = inflatedData.primitiveInstances; + } else if (lineSecondChar === 'n' && (result = regexp.normal_pattern.exec(line)) !== null) { - const eachEntityId = JSON.parse(inflatedData.eachEntityId); - const eachEntityPrimitiveInstancesPortion = inflatedData.eachEntityPrimitiveInstancesPortion; - const eachEntityMatricesPortion = inflatedData.eachEntityMatricesPortion; + // 0 1 2 3 + // ['vn 1.0 2.0 3.0', '1.0', '2.0', '3.0'] - const numPrimitives = eachPrimitivePositionsAndNormalsPortion.length; - const numPrimitiveInstances = primitiveInstances.length; - const primitiveInstanceCounts = new Uint8Array(numPrimitives); // For each mesh, how many times it is instanced + state.normals.push( + parseFloat(result[1]), + parseFloat(result[2]), + parseFloat(result[3]) + ); - const numEntities = eachEntityId.length; + } else if (lineSecondChar === 't' && (result = regexp.uv_pattern.exec(line)) !== null) { - // Count instances of each primitive + // 0 1 2 + // ['vt 0.1 0.2', '0.1', '0.2'] - for (let primitiveInstanceIndex = 0; primitiveInstanceIndex < numPrimitiveInstances; primitiveInstanceIndex++) { - const primitiveIndex = primitiveInstances[primitiveInstanceIndex]; - primitiveInstanceCounts[primitiveIndex]++; - } + state.uv.push( + parseFloat(result[1]), + parseFloat(result[2]) + ); - // Map batched primitives to the entities that will use them + } else { - const batchedPrimitiveEntityIndexes = {}; + modelNode.error('Unexpected vertex/normal/uv line: \'' + line + '\''); + return; + } - for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + } else if (lineFirstChar === 'f') { - const lastEntityIndex = (numEntities - 1); - const atLastEntity = (entityIndex === lastEntityIndex); - const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; - const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + if ((result = regexp.face_vertex_uv_normal.exec(line)) !== null) { - for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + // f vertex/uv/normal vertex/uv/normal vertex/uv/normal + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // ['f 1/1/1 2/2/2 3/3/3', '1', '1', '1', '2', '2', '2', '3', '3', '3', undefined, undefined, undefined] - const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; - const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; - const isInstancedPrimitive = (primitiveInstanceCount > 1); + addFace(state, + result[1], result[4], result[7], result[10], + result[2], result[5], result[8], result[11], + result[3], result[6], result[9], result[12] + ); - if (!isInstancedPrimitive) { - batchedPrimitiveEntityIndexes[primitiveIndex] = entityIndex; - } - } - } + } else if ((result = regexp.face_vertex_uv.exec(line)) !== null) { - // Create geometries for instanced primitives and meshes for batched primitives. + // f vertex/uv vertex/uv vertex/uv + // 0 1 2 3 4 5 6 7 8 + // ['f 1/1 2/2 3/3', '1', '1', '2', '2', '3', '3', undefined, undefined] - for (let primitiveIndex = 0; primitiveIndex < numPrimitives; primitiveIndex++) { + addFace(state, + result[1], result[3], result[5], result[7], + result[2], result[4], result[6], result[8] + ); - const atLastPrimitive = (primitiveIndex === (numPrimitives - 1)); + } else if ((result = regexp.face_vertex_normal.exec(line)) !== null) { - const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; - const isInstancedPrimitive = (primitiveInstanceCount > 1); + // f vertex//normal vertex//normal vertex//normal + // 0 1 2 3 4 5 6 7 8 + // ['f 1//1 2//2 3//3', '1', '1', '2', '2', '3', '3', undefined, undefined] - const color = decompressColor$5(eachPrimitiveColor.subarray((primitiveIndex * 4), (primitiveIndex * 4) + 3)); - const opacity = eachPrimitiveColor[(primitiveIndex * 4) + 3] / 255.0; + addFace(state, + result[1], result[3], result[5], result[7], + undefined, undefined, undefined, undefined, + result[2], result[4], result[6], result[8] + ); - const primitivePositions = positions.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? positions.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); - const primitiveNormals = normals.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? normals.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); - const primitiveIndices = indices.subarray(eachPrimitiveIndicesPortion [primitiveIndex], atLastPrimitive ? indices.length : eachPrimitiveIndicesPortion [primitiveIndex + 1]); - const primitiveEdgeIndices = edgeIndices.subarray(eachPrimitiveEdgeIndicesPortion [primitiveIndex], atLastPrimitive ? edgeIndices.length : eachPrimitiveEdgeIndicesPortion [primitiveIndex + 1]); + } else if ((result = regexp.face_vertex.exec(line)) !== null) { - if (isInstancedPrimitive) { + // f vertex vertex vertex + // 0 1 2 3 4 + // ['f 1 2 3', '1', '2', '3', undefined] - // Primitive instanced by more than one entity, and has positions in Model-space + addFace(state, result[1], result[2], result[3], result[4]); + } else { + modelNode.error('Unexpected face line: \'' + line + '\''); + return; + } - var geometryId = "geometry" + primitiveIndex; // These IDs are local to the VBOSceneModel + } else if (lineFirstChar === 'l') { - sceneModel.createGeometry({ - id: geometryId, - primitive: "triangles", - positionsCompressed: primitivePositions, - normalsCompressed: primitiveNormals, - indices: primitiveIndices, - edgeIndices: primitiveEdgeIndices - }); + var lineParts = line.substring(1).trim().split(' '); + var lineVertices = [], lineUVs = []; - } else { + if (line.indexOf('/') === -1) { - // Primitive is used only by one entity, and has positions pre-transformed into World-space + lineVertices = lineParts; - const meshId = primitiveIndex; // These IDs are local to the VBOSceneModel + } else { + for (var li = 0, llen = lineParts.length; li < llen; li++) { + var parts = lineParts[li].split('/'); + if (parts[0] !== '') { + lineVertices.push(parts[0]); + } + if (parts[1] !== '') { + lineUVs.push(parts[1]); + } + } + } + addLineGeometry(state, lineVertices, lineUVs); - const entityIndex = batchedPrimitiveEntityIndexes[primitiveIndex]; - eachEntityId[entityIndex]; + } else if ((result = regexp.object_pattern.exec(line)) !== null) { - const meshDefaults = {}; // TODO: get from lookup from entity IDs + // o object_name + // or + // g group_name - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - primitive: "triangles", - positionsCompressed: primitivePositions, - normalsCompressed: primitiveNormals, - indices: primitiveIndices, - edgeIndices: primitiveEdgeIndices, - color: color, - opacity: opacity - })); - } - } + var id = result[0].substr(1).trim(); + startObject(state, id, true); - let countInstances = 0; + } else if (regexp.material_use_pattern.test(line)) { - for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + // material - const lastEntityIndex = (numEntities - 1); - const atLastEntity = (entityIndex === lastEntityIndex); - const entityId = eachEntityId[entityIndex]; - const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; - const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + var id = line.substring(7).trim(); + state.object.material.id = id; - const meshIds = []; + } else if (regexp.material_library_pattern.test(line)) { - for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + // mtl file - const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; - const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; - const isInstancedPrimitive = (primitiveInstanceCount > 1); + state.materialLibraries[line.substring(7).trim()] = true; - if (isInstancedPrimitive) { + } else if ((result = regexp.smoothing_pattern.exec(line)) !== null) { - const meshDefaults = {}; // TODO: get from lookup from entity IDs + // smooth shading - const meshId = "instance." + countInstances++; - const geometryId = "geometry" + primitiveIndex; - const matricesIndex = (eachEntityMatricesPortion [entityIndex]) * 16; - const matrix = matrices.subarray(matricesIndex, matricesIndex + 16); + var value = result[1].trim().toLowerCase(); + state.object.material.smooth = (value === '1' || value === 'on'); - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - matrix: matrix - })); + } else { - meshIds.push(meshId); + // Handle null terminated files without exception + if (line === '\0') { + continue; + } - } else { - meshIds.push(primitiveIndex); + modelNode.error('Unexpected line: \'' + line + '\''); + return; } } - if (meshIds.length > 0) { + return state; + }; - const entityDefaults = {}; // TODO: get from lookup from entity IDs + function getBasePath(src) { + var n = src.lastIndexOf('/'); + return (n === -1) ? src : src.substring(0, n + 1); + } - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, ///////////////// TODO: If metaobject exists - meshIds: meshIds - })); + function startObject(state, id, fromDeclaration) { + if (state.object && state.object.fromDeclaration === false) { + state.object.id = id; + state.object.fromDeclaration = (fromDeclaration !== false); + return; } + state.object = { + id: id || '', + geometry: { + positions: [], + normals: [], + uv: [] + }, + material: { + id: '', + smooth: true + }, + fromDeclaration: (fromDeclaration !== false) + }; + state.objects.push(state.object); } -} -/** @private */ -const ParserV5 = { - version: 5, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$5(elements); - const inflatedData = inflate$5(deflatedData); - load$5(viewer, options, inflatedData, sceneModel); + function parseVertexIndex(value, len) { + var index = parseInt(value, 10); + return (index >= 0 ? index - 1 : index + len / 3) * 3; } -}; -/* - - Parser for .XKT Format V6 - - */ + function parseNormalIndex(value, len) { + var index = parseInt(value, 10); + return (index >= 0 ? index - 1 : index + len / 3) * 3; + } -let pako$4 = window.pako || p; -if (!pako$4.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$4 = pako$4.default; -} + function parseUVIndex(value, len) { + var index = parseInt(value, 10); + return (index >= 0 ? index - 1 : index + len / 2) * 2; + } -function extract$4(elements) { + function addVertex(state, a, b, c) { + var src = state.positions; + var dst = state.object.geometry.positions; + dst.push(src[a + 0]); + dst.push(src[a + 1]); + dst.push(src[a + 2]); + dst.push(src[b + 0]); + dst.push(src[b + 1]); + dst.push(src[b + 2]); + dst.push(src[c + 0]); + dst.push(src[c + 1]); + dst.push(src[c + 2]); + } - return { - positions: elements[0], - normals: elements[1], - indices: elements[2], - edgeIndices: elements[3], - matrices: elements[4], - reusedPrimitivesDecodeMatrix: elements[5], - eachPrimitivePositionsAndNormalsPortion: elements[6], - eachPrimitiveIndicesPortion: elements[7], - eachPrimitiveEdgeIndicesPortion: elements[8], - eachPrimitiveColorAndOpacity: elements[9], - primitiveInstances: elements[10], - eachEntityId: elements[11], - eachEntityPrimitiveInstancesPortion: elements[12], - eachEntityMatricesPortion: elements[13], - eachTileAABB: elements[14], - eachTileEntitiesPortion: elements[15] - }; -} + function addVertexLine(state, a) { + var src = state.positions; + var dst = state.object.geometry.positions; + dst.push(src[a + 0]); + dst.push(src[a + 1]); + dst.push(src[a + 2]); + } -function inflate$4(deflatedData) { + function addNormal(state, a, b, c) { + var src = state.normals; + var dst = state.object.geometry.normals; + dst.push(src[a + 0]); + dst.push(src[a + 1]); + dst.push(src[a + 2]); + dst.push(src[b + 0]); + dst.push(src[b + 1]); + dst.push(src[b + 2]); + dst.push(src[c + 0]); + dst.push(src[c + 1]); + dst.push(src[c + 2]); + } - function inflate(array, options) { - return (array.length === 0) ? [] : pako$4.inflate(array, options).buffer; + function addUV(state, a, b, c) { + var src = state.uv; + var dst = state.object.geometry.uv; + dst.push(src[a + 0]); + dst.push(src[a + 1]); + dst.push(src[b + 0]); + dst.push(src[b + 1]); + dst.push(src[c + 0]); + dst.push(src[c + 1]); } - return { - positions: new Uint16Array(inflate(deflatedData.positions)), - normals: new Int8Array(inflate(deflatedData.normals)), - indices: new Uint32Array(inflate(deflatedData.indices)), - edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), - matrices: new Float32Array(inflate(deflatedData.matrices)), - reusedPrimitivesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedPrimitivesDecodeMatrix)), - eachPrimitivePositionsAndNormalsPortion: new Uint32Array(inflate(deflatedData.eachPrimitivePositionsAndNormalsPortion)), - eachPrimitiveIndicesPortion: new Uint32Array(inflate(deflatedData.eachPrimitiveIndicesPortion)), - eachPrimitiveEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachPrimitiveEdgeIndicesPortion)), - eachPrimitiveColorAndOpacity: new Uint8Array(inflate(deflatedData.eachPrimitiveColorAndOpacity)), - primitiveInstances: new Uint32Array(inflate(deflatedData.primitiveInstances)), - eachEntityId: pako$4.inflate(deflatedData.eachEntityId, {to: 'string'}), - eachEntityPrimitiveInstancesPortion: new Uint32Array(inflate(deflatedData.eachEntityPrimitiveInstancesPortion)), - eachEntityMatricesPortion: new Uint32Array(inflate(deflatedData.eachEntityMatricesPortion)), - eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), - eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)) - }; -} + function addUVLine(state, a) { + var src = state.uv; + var dst = state.object.geometry.uv; + dst.push(src[a + 0]); + dst.push(src[a + 1]); + } -const decompressColor$4 = (function () { - const floatColor = new Float32Array(3); - return function (intColor) { - floatColor[0] = intColor[0] / 255.0; - floatColor[1] = intColor[1] / 255.0; - floatColor[2] = intColor[2] / 255.0; - return floatColor; - }; -})(); + function addFace(state, a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd) { + var vLen = state.positions.length; + var ia = parseVertexIndex(a, vLen); + var ib = parseVertexIndex(b, vLen); + var ic = parseVertexIndex(c, vLen); + var id; + if (d === undefined) { + addVertex(state, ia, ib, ic); -function load$4(viewer, options, inflatedData, sceneModel) { + } else { + id = parseVertexIndex(d, vLen); + addVertex(state, ia, ib, id); + addVertex(state, ib, ic, id); + } - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; + if (ua !== undefined) { - const matrices = inflatedData.matrices; + var uvLen = state.uv.length; - const reusedPrimitivesDecodeMatrix = inflatedData.reusedPrimitivesDecodeMatrix; + ia = parseUVIndex(ua, uvLen); + ib = parseUVIndex(ub, uvLen); + ic = parseUVIndex(uc, uvLen); - const eachPrimitivePositionsAndNormalsPortion = inflatedData.eachPrimitivePositionsAndNormalsPortion; - const eachPrimitiveIndicesPortion = inflatedData.eachPrimitiveIndicesPortion; - const eachPrimitiveEdgeIndicesPortion = inflatedData.eachPrimitiveEdgeIndicesPortion; - const eachPrimitiveColorAndOpacity = inflatedData.eachPrimitiveColorAndOpacity; + if (d === undefined) { + addUV(state, ia, ib, ic); - const primitiveInstances = inflatedData.primitiveInstances; + } else { + id = parseUVIndex(ud, uvLen); + addUV(state, ia, ib, id); + addUV(state, ib, ic, id); + } + } - const eachEntityId = JSON.parse(inflatedData.eachEntityId); - const eachEntityPrimitiveInstancesPortion = inflatedData.eachEntityPrimitiveInstancesPortion; - const eachEntityMatricesPortion = inflatedData.eachEntityMatricesPortion; + if (na !== undefined) { - const eachTileAABB = inflatedData.eachTileAABB; - const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + // Normals are many times the same. If so, skip function call and parseInt. - const numPrimitives = eachPrimitivePositionsAndNormalsPortion.length; - const numPrimitiveInstances = primitiveInstances.length; - const numEntities = eachEntityId.length; - const numTiles = eachTileEntitiesPortion.length; + var nLen = state.normals.length; - let nextMeshId = 0; + ia = parseNormalIndex(na, nLen); + ib = na === nb ? ia : parseNormalIndex(nb, nLen); + ic = na === nc ? ia : parseNormalIndex(nc, nLen); - // Count instances of each primitive + if (d === undefined) { + addNormal(state, ia, ib, ic); - const primitiveReuseCounts = new Uint32Array(numPrimitives); + } else { - for (let primitiveInstanceIndex = 0; primitiveInstanceIndex < numPrimitiveInstances; primitiveInstanceIndex++) { - const primitiveIndex = primitiveInstances[primitiveInstanceIndex]; - if (primitiveReuseCounts[primitiveIndex] !== undefined) { - primitiveReuseCounts[primitiveIndex]++; - } else { - primitiveReuseCounts[primitiveIndex] = 1; + id = parseNormalIndex(nd, nLen); + addNormal(state, ia, ib, id); + addNormal(state, ib, ic, id); + } } } - // Iterate over tiles + function addLineGeometry(state, positions, uv) { - const tileCenter = math.vec3(); - const rtcAABB = math.AABB3(); + state.object.geometry.type = 'Line'; - for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + var vLen = state.positions.length; + var uvLen = state.uv.length; - const lastTileIndex = (numTiles - 1); + for (var vi = 0, l = positions.length; vi < l; vi++) { + addVertexLine(state, parseVertexIndex(positions[vi], vLen)); + } - const atLastTile = (tileIndex === lastTileIndex); + for (var uvi = 0, uvl = uv.length; uvi < uvl; uvi++) { + addUVLine(state, parseUVIndex(uv[uvi], uvLen)); + } + } +})(); - const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; - const lastTileEntityIndex = atLastTile ? numEntities : eachTileEntitiesPortion[tileIndex + 1]; +//-------------------------------------------------------------------------------------------- +// Loads MTL files listed in parsed state +//-------------------------------------------------------------------------------------------- - const tileAABBIndex = tileIndex * 6; - const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); +function loadMTLs(modelNode, state, ok) { + var basePath = state.basePath; + var srcList = Object.keys(state.materialLibraries); + var numToLoad = srcList.length; + for (var i = 0, len = numToLoad; i < len; i++) { + loadMTL(modelNode, basePath, basePath + srcList[i], function () { + if (--numToLoad === 0) { + ok(); + } + }); + } +} - math.getAABB3Center(tileAABB, tileCenter); +//-------------------------------------------------------------------------------------------- +// Loads an MTL file +//-------------------------------------------------------------------------------------------- - rtcAABB[0] = tileAABB[0] - tileCenter[0]; - rtcAABB[1] = tileAABB[1] - tileCenter[1]; - rtcAABB[2] = tileAABB[2] - tileCenter[2]; - rtcAABB[3] = tileAABB[3] - tileCenter[0]; - rtcAABB[4] = tileAABB[4] - tileCenter[1]; - rtcAABB[5] = tileAABB[5] - tileCenter[2]; +var loadMTL = function (modelNode, basePath, src, ok) { + loadFile(src, function (text) { + parseMTL(modelNode, text, basePath); + ok(); + }, + function (error) { + modelNode.error(error); + ok(); + }); +}; - const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); +var parseMTL = (function () { - const geometryCreated = {}; + var delimiter_pattern = /\s+/; - // Iterate over each tile's entities + return function (modelNode, mtlText, basePath) { - for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex < lastTileEntityIndex; tileEntityIndex++) { + var lines = mtlText.split('\n'); + var materialCfg = { + id: "Default" + }; + var needCreate = false; + var line; + var pos; + var key; + var value; + var alpha; - const xktEntityId = eachEntityId[tileEntityIndex]; - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + basePath = basePath || ""; - const entityMatrixIndex = eachEntityMatricesPortion[tileEntityIndex]; - const entityMatrix = matrices.slice(entityMatrixIndex, entityMatrixIndex + 16); + for (var i = 0; i < lines.length; i++) { - const lastTileEntityIndex = (numEntities - 1); - const atLastTileEntity = (tileEntityIndex === lastTileEntityIndex); - const firstPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [tileEntityIndex]; - const lastPrimitiveInstanceIndex = atLastTileEntity ? primitiveInstances.length : eachEntityPrimitiveInstancesPortion[tileEntityIndex + 1]; + line = lines[i].trim(); - const meshIds = []; + if (line.length === 0 || line.charAt(0) === '#') { // Blank line or comment ignore + continue; + } - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; + pos = line.indexOf(' '); - if (metaObject) { + key = (pos >= 0) ? line.substring(0, pos) : line; + key = key.toLowerCase(); - // Mask loading of object types + value = (pos >= 0) ? line.substring(pos + 1) : ''; + value = value.trim(); - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } + switch (key.toLowerCase()) { - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } + case "newmtl": // New material + //if (needCreate) { + createMaterial(modelNode, materialCfg); + //} + materialCfg = { + id: value + }; + needCreate = true; + break; - // Get initial property values for object types + case 'ka': + materialCfg.ambient = parseRGB(value); + break; - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + case 'kd': + materialCfg.diffuse = parseRGB(value); + break; - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; + case 'ks': + materialCfg.specular = parseRGB(value); + break; + + case 'map_kd': + if (!materialCfg.diffuseMap) { + materialCfg.diffuseMap = createTexture(modelNode, basePath, value, "sRGB"); } - if (props.pickable === false) { - entityDefaults.pickable = false; + break; + + case 'map_ks': + if (!materialCfg.specularMap) { + materialCfg.specularMap = createTexture(modelNode, basePath, value, "linear"); } - if (props.colorize) { - meshDefaults.color = props.colorize; + break; + + case 'map_bump': + case 'bump': + if (!materialCfg.normalMap) { + materialCfg.normalMap = createTexture(modelNode, basePath, value); } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; + break; + + case 'ns': + materialCfg.shininess = parseFloat(value); + break; + + case 'd': + alpha = parseFloat(value); + if (alpha < 1) { + materialCfg.alpha = alpha; + materialCfg.alphaMode = "blend"; } - } + break; - } else { - if (options.excludeUnclassifiedObjects) { - continue; - } + case 'tr': + alpha = parseFloat(value); + if (alpha > 0) { + materialCfg.alpha = 1 - alpha; + materialCfg.alphaMode = "blend"; + } + break; + // modelNode.error("Unrecognized token: " + key); } + } - // Iterate each entity's primitive instances - - for (let primitiveInstancesIndex = firstPrimitiveInstanceIndex; primitiveInstancesIndex < lastPrimitiveInstanceIndex; primitiveInstancesIndex++) { + if (needCreate) { + createMaterial(modelNode, materialCfg); + } + }; - const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; - const primitiveReuseCount = primitiveReuseCounts[primitiveIndex]; - const isReusedPrimitive = (primitiveReuseCount > 1); + function createTexture(modelNode, basePath, value, encoding) { + var textureCfg = {}; + var items = value.split(/\s+/); + var pos = items.indexOf('-bm'); + if (pos >= 0) { + //matParams.bumpScale = parseFloat(items[pos + 1]); + items.splice(pos, 2); + } + pos = items.indexOf('-s'); + if (pos >= 0) { + textureCfg.scale = [parseFloat(items[pos + 1]), parseFloat(items[pos + 2])]; + items.splice(pos, 4); // we expect 3 parameters here! + } + pos = items.indexOf('-o'); + if (pos >= 0) { + textureCfg.translate = [parseFloat(items[pos + 1]), parseFloat(items[pos + 2])]; + items.splice(pos, 4); // we expect 3 parameters here! + } + textureCfg.src = basePath + items.join(' ').trim(); + textureCfg.flipY = true; + textureCfg.encoding = encoding || "linear"; + //textureCfg.wrapS = self.wrap; + //textureCfg.wrapT = self.wrap; + var texture = new Texture(modelNode, textureCfg); + return texture.id; + } - const atLastPrimitive = (primitiveIndex === (numPrimitives - 1)); + function createMaterial(modelNode, materialCfg) { + new PhongMaterial(modelNode, materialCfg); + } - const primitivePositions = positions.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? positions.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); - const primitiveNormals = normals.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? normals.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); - const primitiveIndices = indices.subarray(eachPrimitiveIndicesPortion [primitiveIndex], atLastPrimitive ? indices.length : eachPrimitiveIndicesPortion [primitiveIndex + 1]); - const primitiveEdgeIndices = edgeIndices.subarray(eachPrimitiveEdgeIndicesPortion [primitiveIndex], atLastPrimitive ? edgeIndices.length : eachPrimitiveEdgeIndicesPortion [primitiveIndex + 1]); + function parseRGB(value) { + var ss = value.split(delimiter_pattern, 3); + return [parseFloat(ss[0]), parseFloat(ss[1]), parseFloat(ss[2])]; + } - const color = decompressColor$4(eachPrimitiveColorAndOpacity.subarray((primitiveIndex * 4), (primitiveIndex * 4) + 3)); - const opacity = eachPrimitiveColorAndOpacity[(primitiveIndex * 4) + 3] / 255.0; +})(); +//-------------------------------------------------------------------------------------------- +// Creates meshes from parsed state +//-------------------------------------------------------------------------------------------- - const meshId = nextMeshId++; - if (isReusedPrimitive) { +function createMeshes(modelNode, state) { - // Create mesh for multi-use primitive - create (or reuse) geometry, create mesh using that geometry + for (var j = 0, k = state.objects.length; j < k; j++) { - const geometryId = "geometry." + tileIndex + "." + primitiveIndex; // These IDs are local to the VBOSceneModel + var object = state.objects[j]; + var geometry = object.geometry; + (geometry.type === 'Line'); - if (!geometryCreated[geometryId]) { + if (geometry.positions.length === 0) { + // Skip o/g line declarations that did not follow with any faces + continue; + } - sceneModel.createGeometry({ - id: geometryId, - primitive: "triangles", - positionsCompressed: primitivePositions, - normalsCompressed: primitiveNormals, - indices: primitiveIndices, - edgeIndices: primitiveEdgeIndices, - positionsDecodeMatrix: reusedPrimitivesDecodeMatrix - }); + var geometryCfg = { + primitive: "triangles", + compressGeometry: false + }; - geometryCreated[geometryId] = true; - } + geometryCfg.positions = geometry.positions; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - origin: tileCenter, - matrix: entityMatrix, - color: color, - opacity: opacity - })); + if (geometry.normals.length > 0) { + geometryCfg.normals = geometry.normals; + } - meshIds.push(meshId); + if (geometry.uv.length > 0) { + geometryCfg.uv = geometry.uv; + } - } else { + var indices = new Array(geometryCfg.positions.length / 3); // Triangle soup + for (var idx = 0; idx < indices.length; idx++) { + indices[idx] = idx; + } + geometryCfg.indices = indices; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - origin: tileCenter, - primitive: "triangles", - positionsCompressed: primitivePositions, - normalsCompressed: primitiveNormals, - indices: primitiveIndices, - edgeIndices: primitiveEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: color, - opacity: opacity - })); + const origin = tempVec3a$4; - meshIds.push(meshId); - } - } + worldToRTCPositions(geometry.positions, geometry.positions, origin); - if (meshIds.length > 0) { + var readableGeometry = new ReadableGeometry(modelNode, geometryCfg); - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, - meshIds: meshIds - })); + var materialId = object.material.id; + var material; + if (materialId && materialId !== "") { + material = modelNode.scene.components[materialId]; + if (!material) { + modelNode.error("Material not found: " + materialId); } - } - } -} - -/** @private */ -const ParserV6 = { - version: 6, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$4(elements); - const inflatedData = inflate$4(deflatedData); - load$4(viewer, options, inflatedData, sceneModel); - } -}; + } else { + material = new PhongMaterial(modelNode, { + //emissive: [0.6, 0.6, 0.0], + diffuse: [0.6, 0.6, 0.6], + backfaces: true + }); -/* + } - Parser for .XKT Format V7 + // material.emissive = [Math.random(), Math.random(), Math.random()]; - */ + var mesh = new Mesh(modelNode, { + id: modelNode.id + "#" + object.id, + origin: (origin[0] !== 0 || origin[1] !== 0 || origin[2] !== 0) ? origin : null, + isObject: true, + geometry: readableGeometry, + material: material, + pickable: true + }); -let pako$3 = window.pako || p; -if (!pako$3.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$3 = pako$3.default; + modelNode.addChild(mesh); + } } -function extract$3(elements) { - - return { - - // Vertex attributes - - positions: elements[0], - normals: elements[1], - colors: elements[2], +function loadFile(url, ok, err) { + var request = new XMLHttpRequest(); + request.open('GET', url, true); + request.addEventListener('load', function (event) { + var response = event.target.response; + if (this.status === 200) { + if (ok) { + ok(response); + } + } else if (this.status === 0) { + // Some browsers return HTTP Status 0 when using non-http protocol + // e.g. 'file://' or 'data://'. Handle as success. + console.warn('loadFile: HTTP Status 0 received.'); + if (ok) { + ok(response); + } + } else { + if (err) { + err(event); + } + } + }, false); - // Indices + request.addEventListener('error', function (event) { + if (err) { + err(event); + } + }, false); + request.send(null); +} - indices: elements[3], - edgeIndices: elements[4], +/** + * {@link Viewer} plugin that loads models from [OBJ](https://en.wikipedia.org/wiki/Wavefront_.obj_file) files. + * + * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. + * * Creates an {@link Entity} for each object within the model, which will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. + * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. + * + * ## Metadata + * + * OBJLoaderPlugin can also load an accompanying JSON metadata file with each model, which creates a {@link MetaModel} corresponding + * to the model {@link Entity} and a {@link MetaObject} corresponding to each object {@link Entity}. + * + * Each {@link MetaObject} has a {@link MetaObject#type}, which indicates the classification of its corresponding {@link Entity}. When loading + * metadata, we can also provide GLTFModelLoaderPlugin with a custom lookup table of initial values to set on the properties of each type of {@link Entity}. By default, OBJLoaderPlugin + * uses its own map of standard default colors, visibilities and opacities for IFC element types. - // Transform matrices + * + * ## Usage + * + * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#loading_OBJ_SportsCar)] + * + * ````javascript + * import {Viewer, OBJLoaderPlugin} from "xeokit-sdk.es.js"; + * + * // Create a xeokit Viewer and arrange the camera + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.orbitPitch(20); + * + * // Add an OBJLoaderPlugin to the Viewer + * const objLoader = new OBJLoaderPlugin(viewer); + * + * // Load an OBJ model + * var model = objLoader.load({ // Model is an Entity + * id: "myModel", + * src: "./models/obj/sportsCar/sportsCar.obj", + * edges: true + * }); + * + * // When the model has loaded, fit it to view + * model.on("loaded", () => { + * viewer.cameraFlight.flyTo(model); + * }) + * + * // Find the model Entity by ID + * model = viewer.scene.models["myModel"]; + * + * // Update properties of the model Entity + * model.highlight = [1,0,0]; + * + * // Destroy the model + * model.destroy(); + * ```` + * @class OBJLoaderPlugin + */ +class OBJLoaderPlugin extends Plugin { - matrices: elements[5], + /** + * @constructor + * + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="OBJLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + */ + constructor(viewer, cfg) { - reusedGeometriesDecodeMatrix: elements[6], + super("OBJLoader", viewer, cfg); - // Geometries + /** + * @private + */ + this._sceneGraphLoader = new OBJSceneGraphLoader(); + } - eachGeometryPrimitiveType: elements[7], - eachGeometryPositionsPortion: elements[8], - eachGeometryNormalsPortion: elements[9], - eachGeometryColorsPortion: elements[10], - eachGeometryIndicesPortion: elements[11], - eachGeometryEdgeIndicesPortion: elements[12], + /** + * Loads an OBJ model from a file into this OBJLoader's {@link Viewer}. + * + * @param {*} params Loading parameters. + * @param {String} params.id ID to assign to the model's root {@link Entity}, unique among all components in the Viewer's {@link Scene}. + * @param {String} params.src Path to an OBJ file. + * @param {String} [params.metaModelSrc] Path to an optional metadata file. + * @param {Number[]} [params.position=[0,0,0]] The model World-space 3D position. + * @param {Number[]} [params.scale=[1,1,1]] The model's World-space scale. + * @param {Number[]} [params.rotation=[0,0,0]] The model's World-space rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. + * @param {Number} [params.edgeThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. + * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} + */ + load(params = {}) { - // Meshes are grouped in runs that are shared by the same entities + if (params.id && this.viewer.scene.components[params.id]) { + this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); + delete params.id; + } - eachMeshGeometriesPortion: elements[13], - eachMeshMatricesPortion: elements[14], - eachMeshMaterial: elements[15], + var modelNode = new Node$1(this.viewer.scene, utils.apply(params, { + isModel: true + })); - // Entity elements in the following arrays are grouped in runs that are shared by the same tiles + const modelId = modelNode.id; // In case ID was auto-generated + const src = params.src; - eachEntityId: elements[16], - eachEntityMeshesPortion: elements[17], + if (!src) { + this.error("load() param expected: src"); + return modelNode; + } - eachTileAABB: elements[18], - eachTileEntitiesPortion: elements[19] - }; -} + if (params.metaModelSrc) { + const metaModelSrc = params.metaModelSrc; + utils.loadJSON(metaModelSrc, + (modelMetadata) => { + this.viewer.metaScene.createMetaModel(modelId, modelMetadata); + this._sceneGraphLoader.load(modelNode, src, params); + }, + (errMsg) => { + this.error(`load(): Failed to load model modelMetadata for model '${modelId} from '${metaModelSrc}' - ${errMsg}`); + }); + } else { + this._sceneGraphLoader.load(modelNode, src, params); + } -function inflate$3(deflatedData) { + modelNode.once("destroyed", () => { + this.viewer.metaScene.destroyMetaModel(modelId); + }); - function inflate(array, options) { - return (array.length === 0) ? [] : pako$3.inflate(array, options).buffer; + return modelNode; } - return { - positions: new Uint16Array(inflate(deflatedData.positions)), - normals: new Int8Array(inflate(deflatedData.normals)), - colors: new Uint8Array(inflate(deflatedData.colors)), + /** + * Destroys this OBJLoaderPlugin. + */ + destroy() { + super.destroy(); + } +} - indices: new Uint32Array(inflate(deflatedData.indices)), - edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), +const zeroVec = new Float64Array([0, 0, 1]); +const quat = new Float64Array(4); - matrices: new Float32Array(inflate(deflatedData.matrices)), +/** + * Controls a {@link SectionPlane} with mouse and touch input. + * + * @private + */ +class Control { - reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + /** @private */ + constructor(plugin) { - eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), - eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), - eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), - eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), - eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), - eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + /** + * ID of this Control. + * + * SectionPlaneControls are mapped by this ID in {@link SectionPlanesPlugin#sectionPlaneControls}. + * + * @property id + * @type {String|Number} + */ + this.id = null; - eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), - eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), - eachMeshMaterial: new Uint8Array(inflate(deflatedData.eachMeshMaterial)), + this._viewer = plugin.viewer; - eachEntityId: pako$3.inflate(deflatedData.eachEntityId, {to: 'string'}), - eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + this._visible = false; + this._pos = math.vec3(); // Full-precision position of the center of the Control + this._origin = math.vec3(); + this._rtcPos = math.vec3(); - eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), - eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), - }; -} + this._baseDir = math.vec3(); // Saves direction of clip plane when we start dragging an arrow or ring. + this._rootNode = null; // Root of Node graph that represents this control in the 3D scene + this._displayMeshes = null; // Meshes that are always visible + this._affordanceMeshes = null; // Meshes displayed momentarily for affordance -const decompressColor$3 = (function () { - const floatColor = new Float32Array(3); - return function (intColor) { - floatColor[0] = intColor[0] / 255.0; - floatColor[1] = intColor[1] / 255.0; - floatColor[2] = intColor[2] / 255.0; - return floatColor; - }; -})(); + this._ignoreNextSectionPlaneDirUpdate = false; -function convertColorsRGBToRGBA$1(colorsRGB) { - const colorsRGBA = []; - for (let i = 0, len = colorsRGB.length; i < len; i+=3) { - colorsRGBA.push(colorsRGB[i]); - colorsRGBA.push(colorsRGB[i+1]); - colorsRGBA.push(colorsRGB[i+2]); - colorsRGBA.push(1.0); + this._createNodes(); + this._bindEvents(); } - return colorsRGBA; -} -function load$3(viewer, options, inflatedData, sceneModel) { - - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const colors = inflatedData.colors; - - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - - const matrices = inflatedData.matrices; + /** + * Called by SectionPlanesPlugin to assign this Control to a SectionPlane. + * SectionPlanesPlugin keeps SectionPlaneControls in a reuse pool. + * Call with a null or undefined value to disconnect the Control ffrom whatever SectionPlane it was assigned to. + * @private + */ + _setSectionPlane(sectionPlane) { + if (this._sectionPlane) { + this._sectionPlane.off(this._onSectionPlanePos); + this._sectionPlane.off(this._onSectionPlaneDir); + this._onSectionPlanePos = null; + this._onSectionPlaneDir = null; + this._sectionPlane = null; + } + if (sectionPlane) { + this.id = sectionPlane.id; + this._setPos(sectionPlane.pos); + this._setDir(sectionPlane.dir); + this._sectionPlane = sectionPlane; + this._onSectionPlanePos = sectionPlane.on("pos", () => { + this._setPos(this._sectionPlane.pos); + }); + this._onSectionPlaneDir = sectionPlane.on("dir", () => { + if (!this._ignoreNextSectionPlaneDirUpdate) { + this._setDir(this._sectionPlane.dir); + } else { + this._ignoreNextSectionPlaneDirUpdate = false; + } + }); + } + } - const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + /** + * Gets the {@link SectionPlane} controlled by this Control. + * @returns {SectionPlane} The SectionPlane. + */ + get sectionPlane() { + return this._sectionPlane; + } - const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; - const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; - const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; - const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; - const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; - const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + /** @private */ + _setPos(xyz) { - const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; - const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; - const eachMeshMaterial = inflatedData.eachMeshMaterial; + this._pos.set(xyz); - const eachEntityId = JSON.parse(inflatedData.eachEntityId); - const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + worldToRTCPos(this._pos, this._origin, this._rtcPos); - const eachTileAABB = inflatedData.eachTileAABB; - const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + this._rootNode.origin = this._origin; + this._rootNode.position = this._rtcPos; + } - const numGeometries = eachGeometryPositionsPortion.length; - const numMeshes = eachMeshGeometriesPortion.length; - const numEntities = eachEntityId.length; - const numTiles = eachTileEntitiesPortion.length; + /** @private */ + _setDir(xyz) { + this._baseDir.set(xyz); + this._rootNode.quaternion = math.vec3PairToQuaternion(zeroVec, xyz, quat); + } - let nextMeshId = 0; + _setSectionPlaneDir(dir) { + if (this._sectionPlane) { + this._ignoreNextSectionPlaneDirUpdate = true; + this._sectionPlane.dir = dir; + } + } - // Count instances of each geometry + /** + * Sets if this Control is visible. + * + * @type {Boolean} + */ + setVisible(visible = true) { + if (this._visible === visible) { + return; + } + this._visible = visible; + var id; + for (id in this._displayMeshes) { + if (this._displayMeshes.hasOwnProperty(id)) { + this._displayMeshes[id].visible = visible; + } + } + if (!visible) { + for (id in this._affordanceMeshes) { + if (this._affordanceMeshes.hasOwnProperty(id)) { + this._affordanceMeshes[id].visible = visible; + } + } + } + } - const geometryReuseCounts = new Uint32Array(numGeometries); + /** + * Gets if this Control is visible. + * + * @type {Boolean} + */ + getVisible() { + return this._visible; + } - for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - if (geometryReuseCounts[geometryIndex] !== undefined) { - geometryReuseCounts[geometryIndex]++; - } else { - geometryReuseCounts[geometryIndex] = 1; + /** + * Sets if this Control is culled. This is called by SectionPlanesPlugin to + * temporarily hide the Control while a snapshot is being taken by Viewer#getSnapshot(). + * @param culled + */ + setCulled(culled) { + var id; + for (id in this._displayMeshes) { + if (this._displayMeshes.hasOwnProperty(id)) { + this._displayMeshes[id].culled = culled; + } + } + if (!culled) { + for (id in this._affordanceMeshes) { + if (this._affordanceMeshes.hasOwnProperty(id)) { + this._affordanceMeshes[id].culled = culled; + } + } } } - // Iterate over tiles + /** + * Builds the Entities that represent this Control. + * @private + */ + _createNodes() { - const tileCenter = math.vec3(); - const rtcAABB = math.AABB3(); + const NO_STATE_INHERIT = false; + const scene = this._viewer.scene; + const radius = 1.0; + const handleTubeRadius = 0.06; + const hoopRadius = radius - 0.2; + const tubeRadius = 0.01; + const arrowRadius = 0.07; - for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + this._rootNode = new Node$1(scene, { + position: [0, 0, 0], + scale: [5, 5, 5] + }); - const lastTileIndex = (numTiles - 1); + const rootNode = this._rootNode; - const atLastTile = (tileIndex === lastTileIndex); + const shapes = {// Reusable geometries - const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; - const lastTileEntityIndex = atLastTile ? numEntities : eachTileEntitiesPortion[tileIndex + 1]; + arrowHead: new ReadableGeometry(rootNode, buildCylinderGeometry({ + radiusTop: 0.001, + radiusBottom: arrowRadius, + radialSegments: 32, + heightSegments: 1, + height: 0.2, + openEnded: false + })), - const tileAABBIndex = tileIndex * 6; - const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + arrowHeadBig: new ReadableGeometry(rootNode, buildCylinderGeometry({ + radiusTop: 0.001, + radiusBottom: 0.09, + radialSegments: 32, + heightSegments: 1, + height: 0.25, + openEnded: false + })), - math.getAABB3Center(tileAABB, tileCenter); + arrowHeadHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({ + radiusTop: 0.09, + radiusBottom: 0.09, + radialSegments: 8, + heightSegments: 1, + height: 0.37, + openEnded: false + })), - rtcAABB[0] = tileAABB[0] - tileCenter[0]; - rtcAABB[1] = tileAABB[1] - tileCenter[1]; - rtcAABB[2] = tileAABB[2] - tileCenter[2]; - rtcAABB[3] = tileAABB[3] - tileCenter[0]; - rtcAABB[4] = tileAABB[4] - tileCenter[1]; - rtcAABB[5] = tileAABB[5] - tileCenter[2]; + curve: new ReadableGeometry(rootNode, buildTorusGeometry({ + radius: hoopRadius, + tube: tubeRadius, + radialSegments: 64, + tubeSegments: 14, + arc: (Math.PI * 2.0) / 4.0 + })), - const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + curveHandle: new ReadableGeometry(rootNode, buildTorusGeometry({ + radius: hoopRadius, + tube: handleTubeRadius, + radialSegments: 64, + tubeSegments: 14, + arc: (Math.PI * 2.0) / 4.0 + })), - const geometryCreated = {}; + hoop: new ReadableGeometry(rootNode, buildTorusGeometry({ + radius: hoopRadius, + tube: tubeRadius, + radialSegments: 64, + tubeSegments: 8, + arc: (Math.PI * 2.0) + })), - // Iterate over each tile's entities + axis: new ReadableGeometry(rootNode, buildCylinderGeometry({ + radiusTop: tubeRadius, + radiusBottom: tubeRadius, + radialSegments: 20, + heightSegments: 1, + height: radius, + openEnded: false + })), - for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex < lastTileEntityIndex; tileEntityIndex++) { + axisHandle: new ReadableGeometry(rootNode, buildCylinderGeometry({ + radiusTop: 0.08, + radiusBottom: 0.08, + radialSegments: 20, + heightSegments: 1, + height: radius, + openEnded: false + })) + }; - const xktEntityId = eachEntityId[tileEntityIndex]; - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + const materials = { // Reusable materials - const lastTileEntityIndex = (numEntities - 1); - const atLastTileEntity = (tileEntityIndex === lastTileEntityIndex); - const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; - const lastMeshIndex = atLastTileEntity ? eachMeshGeometriesPortion.length : eachEntityMeshesPortion[tileEntityIndex + 1]; + pickable: new PhongMaterial(rootNode, { // Invisible material for pickable handles, which define a pickable 3D area + diffuse: [1, 1, 0], + alpha: 0, // Invisible + alphaMode: "blend" + }), - const meshIds = []; + red: new PhongMaterial(rootNode, { + diffuse: [1, 0.0, 0.0], + emissive: [1, 0.0, 0.0], + ambient: [0.0, 0.0, 0.0], + specular: [.6, .6, .3], + shininess: 80, + lineWidth: 2 + }), - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; + highlightRed: new EmphasisMaterial(rootNode, { // Emphasis for red rotation affordance hoop + edges: false, + fill: true, + fillColor: [1, 0, 0], + fillAlpha: 0.6 + }), - if (metaObject) { + green: new PhongMaterial(rootNode, { + diffuse: [0.0, 1, 0.0], + emissive: [0.0, 1, 0.0], + ambient: [0.0, 0.0, 0.0], + specular: [.6, .6, .3], + shininess: 80, + lineWidth: 2 + }), - // Mask loading of object types + highlightGreen: new EmphasisMaterial(rootNode, { // Emphasis for green rotation affordance hoop + edges: false, + fill: true, + fillColor: [0, 1, 0], + fillAlpha: 0.6 + }), - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } + blue: new PhongMaterial(rootNode, { + diffuse: [0.0, 0.0, 1], + emissive: [0.0, 0.0, 1], + ambient: [0.0, 0.0, 0.0], + specular: [.6, .6, .3], + shininess: 80, + lineWidth: 2 + }), - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } + highlightBlue: new EmphasisMaterial(rootNode, { // Emphasis for blue rotation affordance hoop + edges: false, + fill: true, + fillColor: [0, 0, 1], + fillAlpha: 0.2 + }), - // Get initial property values for object types + center: new PhongMaterial(rootNode, { + diffuse: [0.0, 0.0, 0.0], + emissive: [0, 0, 0], + ambient: [0.0, 0.0, 0.0], + specular: [.6, .6, .3], + shininess: 80 + }), - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + highlightBall: new EmphasisMaterial(rootNode, { + edges: false, + fill: true, + fillColor: [0.5, 0.5, 0.5], + fillAlpha: 0.5, + vertices: false + }), - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; - } - if (props.metallic !== undefined && props.metallic !== null) { - meshDefaults.metallic = props.metallic; - } - if (props.roughness !== undefined && props.roughness !== null) { - meshDefaults.roughness = props.roughness; - } - } + highlightPlane: new EmphasisMaterial(rootNode, { + edges: true, + edgeWidth: 3, + fill: false, + fillColor: [0.5, 0.5, .5], + fillAlpha: 0.5, + vertices: false + }) + }; - } else { - if (options.excludeUnclassifiedObjects) { - continue; - } - } + this._displayMeshes = { - // Iterate each entity's meshes + plane: rootNode.addChild(new Mesh(rootNode, { + geometry: new ReadableGeometry(rootNode, { + primitive: "triangles", + positions: [ + 0.5, 0.5, 0.0, 0.5, -0.5, 0.0, // 0 + -0.5, -0.5, 0.0, -0.5, 0.5, 0.0, // 1 + 0.5, 0.5, -0.0, 0.5, -0.5, -0.0, // 2 + -0.5, -0.5, -0.0, -0.5, 0.5, -0.0 // 3 + ], + indices: [0, 1, 2, 2, 3, 0] + }), + material: new PhongMaterial(rootNode, { + emissive: [0, 0.0, 0], + diffuse: [0, 0, 0], + backfaces: true + }), + opacity: 0.6, + ghosted: true, + ghostMaterial: new EmphasisMaterial(rootNode, { + edges: false, + filled: true, + fillColor: [1, 1, 0], + edgeColor: [0, 0, 0], + fillAlpha: 0.1, + backfaces: true + }), + pickable: false, + collidable: true, + clippable: false, + visible: false, + scale: [2.4, 2.4, 1] + }), NO_STATE_INHERIT), - for (let meshIndex = firstMeshIndex; meshIndex < lastMeshIndex; meshIndex++) { + planeFrame: rootNode.addChild(new Mesh(rootNode, { // Visible frame + geometry: new ReadableGeometry(rootNode, buildTorusGeometry({ + center: [0, 0, 0], + radius: 1.7, + tube: tubeRadius * 2, + radialSegments: 4, + tubeSegments: 4, + arc: Math.PI * 2.0 + })), + material: new PhongMaterial(rootNode, { + emissive: [0, 0, 0], + diffuse: [0, 0, 0], + specular: [0, 0, 0], + shininess: 0 + }), + //highlighted: true, + highlightMaterial: new EmphasisMaterial(rootNode, { + edges: false, + edgeColor: [0.0, 0.0, 0.0], + filled: true, + fillColor: [0.8, 0.8, 0.8], + fillAlpha: 1.0 + }), + pickable: false, + collidable: false, + clippable: false, + visible: false, + scale: [1, 1, .1], + rotation: [0, 0, 45] + }), NO_STATE_INHERIT), - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - const geometryReuseCount = geometryReuseCounts[geometryIndex]; - const isReusedGeometry = (geometryReuseCount > 1); + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- - const atLastGeometry = (geometryIndex === (numGeometries - 1)); + xCurve: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis + geometry: shapes.curve, + material: materials.red, + matrix: (function () { + const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4()); + const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate1, rotate2, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + backfaces: true, + visible: false + }), NO_STATE_INHERIT), - const meshColor = decompressColor$3(eachMeshMaterial.subarray((meshIndex * 6), (meshIndex * 6) + 3)); - const meshOpacity = eachMeshMaterial[(meshIndex * 6) + 3] / 255.0; - const meshMetallic = eachMeshMaterial[(meshIndex * 6) + 4] / 255.0; - const meshRoughness = eachMeshMaterial[(meshIndex * 6) + 5] / 255.0; + xCurveHandle: rootNode.addChild(new Mesh(rootNode, { // Red hoop about Y-axis + geometry: shapes.curveHandle, + material: materials.pickable, + matrix: (function () { + const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4()); + const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate1, rotate2, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + backfaces: true, + visible: false + }), NO_STATE_INHERIT), - const meshId = nextMeshId++; + xCurveArrow1: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.red, + matrix: (function () { + const translate = math.translateMat4c(0., -0.07, -0.8, math.identityMat4()); + const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); + const rotate = math.rotationMat4v(0 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - if (isReusedGeometry) { + xCurveArrow2: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.red, + matrix: (function () { + const translate = math.translateMat4c(0.0, -0.8, -0.07, math.identityMat4()); + const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); + const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- - const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; - const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); + yCurve: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.curve, + material: materials.green, + rotation: [-90, 0, 0], + pickable: false, + collidable: true, + clippable: false, + backfaces: true, + visible: false + }), NO_STATE_INHERIT), - const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel + yCurveHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.curveHandle, + material: materials.pickable, + rotation: [-90, 0, 0], + pickable: true, + collidable: true, + clippable: false, + backfaces: true, + visible: false + }), NO_STATE_INHERIT), - if (!geometryCreated[geometryId]) { + yCurveArrow1: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.green, + matrix: (function () { + const translate = math.translateMat4c(0.07, 0, -0.8, math.identityMat4()); + const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); + const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + yCurveArrow2: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.green, + matrix: (function () { + const translate = math.translateMat4c(0.8, 0.0, -0.07, math.identityMat4()); + const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); + const rotate = math.rotationMat4v(90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - let primitiveName; - let geometryPositions; - let geometryNormals; - let geometryColors; - let geometryIndices; - let geometryEdgeIndices; + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- - switch (primitiveType) { - case 0: - primitiveName = "solid"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - break; - case 1: - primitiveName = "surface"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - break; - case 2: - primitiveName = "points"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryColors = convertColorsRGBToRGBA$1(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); - break; - case 3: - primitiveName = "lines"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - break; - default: - continue; - } + zCurve: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis + geometry: shapes.curve, + material: materials.blue, + matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - sceneModel.createGeometry({ - id: geometryId, - primitive: primitiveName, - positionsCompressed: geometryPositions, - normalsCompressed: geometryNormals, - colors: geometryColors, - indices: geometryIndices, - edgeIndices: geometryEdgeIndices, - positionsDecodeMatrix: reusedGeometriesDecodeMatrix - }); + zCurveHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.curveHandle, + material: materials.pickable, + matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - geometryCreated[geometryId] = true; - } + zCurveCurveArrow1: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.blue, + matrix: (function () { + const translate = math.translateMat4c(.8, -0.07, 0, math.identityMat4()); + const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); + return math.mulMat4(translate, scale, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - origin: tileCenter, - matrix: meshMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); + zCurveArrow2: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.blue, + matrix: (function () { + const translate = math.translateMat4c(.05, -0.8, 0, math.identityMat4()); + const scale = math.scaleMat4v([0.6, 0.6, 0.6], math.identityMat4()); + const rotate = math.rotationMat4v(90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(math.mulMat4(translate, scale, math.identityMat4()), rotate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - meshIds.push(meshId); + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- - } else { + center: rootNode.addChild(new Mesh(rootNode, { + geometry: new ReadableGeometry(rootNode, buildSphereGeometry({ + radius: 0.05 + })), + material: materials.center, + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- - let primitiveName; - let geometryPositions; - let geometryNormals; - let geometryColors; - let geometryIndices; - let geometryEdgeIndices; + xAxisArrow: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.red, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - switch (primitiveType) { - case 0: - primitiveName = "solid"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - break; - case 1: - primitiveName = "surface"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - break; - case 2: - primitiveName = "points"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryColors = convertColorsRGBToRGBA$1(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); - break; - case 3: - primitiveName = "lines"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - break; - default: - continue; - } - - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - origin: tileCenter, - primitive: primitiveName, - positionsCompressed: geometryPositions, - normalsCompressed: geometryNormals, - colors: geometryColors, - indices: geometryIndices, - edgeIndices: geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); - - meshIds.push(meshId); - } - } - - if (meshIds.length > 0) { - - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, - meshIds: meshIds - })); - } - } - } -} - -/** @private */ -const ParserV7 = { - version: 7, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$3(elements); - const inflatedData = inflate$3(deflatedData); - load$3(viewer, options, inflatedData, sceneModel); - } -}; + xAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHeadHandle, + material: materials.pickable, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), -/* + xAxis: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.axis, + material: materials.red, + matrix: (function () { + const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - Parser for .XKT Format V8 + xAxisHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.axisHandle, + material: materials.pickable, + matrix: (function () { + const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - */ + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- -let pako$2 = window.pako || p; -if (!pako$2.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$2 = pako$2.default; -} + yAxisArrow: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.green, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), -const tempVec4a$4 = math.vec4(); -const tempVec4b$4 = math.vec4(); + yAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHeadHandle, + material: materials.pickable, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false, + opacity: 0.2 + }), NO_STATE_INHERIT), -function extract$2(elements) { + yShaft: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.axis, + material: materials.green, + position: [0, -radius / 2, 0], + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - return { + yShaftHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.axisHandle, + material: materials.pickable, + position: [0, -radius / 2, 0], + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - // Vertex attributes + //---------------------------------------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------------------------------------- - types: elements[0], - eachMetaObjectId: elements[1], - eachMetaObjectType: elements[2], - eachMetaObjectName: elements[3], - eachMetaObjectParent: elements[4], + zAxisArrow: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHead, + material: materials.blue, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - positions: elements[5], - normals: elements[6], - colors: elements[7], - indices: elements[8], - edgeIndices: elements[9], + zAxisArrowHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHeadHandle, + material: materials.pickable, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: true, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - // Transform matrices - matrices: elements[10], - reusedGeometriesDecodeMatrix: elements[11], + zShaft: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.axis, + material: materials.blue, + matrix: (function () { + const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + clippable: false, + pickable: false, + collidable: true, + visible: false + }), NO_STATE_INHERIT), - // Geometries + zAxisHandle: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.axisHandle, + material: materials.pickable, + matrix: (function () { + const translate = math.translateMat4c(0, radius / 2, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + clippable: false, + pickable: true, + collidable: true, + visible: false + }), NO_STATE_INHERIT) + }; - eachGeometryPrimitiveType: elements[12], - eachGeometryPositionsPortion: elements[13], - eachGeometryNormalsPortion: elements[14], - eachGeometryColorsPortion: elements[15], - eachGeometryIndicesPortion: elements[16], - eachGeometryEdgeIndicesPortion: elements[17], + this._affordanceMeshes = { - // Meshes are grouped in runs that are shared by the same entities + planeFrame: rootNode.addChild(new Mesh(rootNode, { + geometry: new ReadableGeometry(rootNode, buildTorusGeometry({ + center: [0, 0, 0], + radius: 2, + tube: tubeRadius, + radialSegments: 4, + tubeSegments: 4, + arc: Math.PI * 2.0 + })), + material: new PhongMaterial(rootNode, { + ambient: [1, 1, 1], + diffuse: [0, 0, 0], + emissive: [1, 1, 0] + }), + highlighted: true, + highlightMaterial: new EmphasisMaterial(rootNode, { + edges: false, + filled: true, + fillColor: [1, 1, 0], + fillAlpha: 1.0 + }), + pickable: false, + collidable: false, + clippable: false, + visible: false, + scale: [1, 1, 1], + rotation: [0, 0, 45] + }), NO_STATE_INHERIT), - eachMeshGeometriesPortion: elements[18], - eachMeshMatricesPortion: elements[19], - eachMeshMaterial: elements[20], + xHoop: rootNode.addChild(new Mesh(rootNode, { // Full + geometry: shapes.hoop, + material: materials.red, + highlighted: true, + highlightMaterial: materials.highlightRed, + matrix: (function () { + const rotate2 = math.rotationMat4v(90 * math.DEGTORAD, [0, 1, 0], math.identityMat4()); + const rotate1 = math.rotationMat4v(270 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate1, rotate2, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - // Entity elements in the following arrays are grouped in runs that are shared by the same tiles + yHoop: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.hoop, + material: materials.green, + highlighted: true, + highlightMaterial: materials.highlightGreen, + rotation: [-90, 0, 0], + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - eachEntityMetaObject: elements[21], - eachEntityMeshesPortion: elements[22], + zHoop: rootNode.addChild(new Mesh(rootNode, { // Blue hoop about Z-axis + geometry: shapes.hoop, + material: materials.blue, + highlighted: true, + highlightMaterial: materials.highlightBlue, + matrix: math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()), + pickable: false, + collidable: true, + clippable: false, + backfaces: true, + visible: false + }), NO_STATE_INHERIT), - eachTileAABB: elements[23], - eachTileEntitiesPortion: elements[24] - }; -} + xAxisArrow: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHeadBig, + material: materials.red, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0, 0, 1], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), -function inflate$2(deflatedData) { + yAxisArrow: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHeadBig, + material: materials.green, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(180 * math.DEGTORAD, [1, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT), - function inflate(array, options) { - return (array.length === 0) ? [] : pako$2.inflate(array, options).buffer; + zAxisArrow: rootNode.addChild(new Mesh(rootNode, { + geometry: shapes.arrowHeadBig, + material: materials.blue, + matrix: (function () { + const translate = math.translateMat4c(0, radius + .1, 0, math.identityMat4()); + const rotate = math.rotationMat4v(-90 * math.DEGTORAD, [0.8, 0, 0], math.identityMat4()); + return math.mulMat4(rotate, translate, math.identityMat4()); + })(), + pickable: false, + collidable: true, + clippable: false, + visible: false + }), NO_STATE_INHERIT) + }; } - return { + _bindEvents() { - types: pako$2.inflate(deflatedData.types, {to: 'string'}), - eachMetaObjectId: pako$2.inflate(deflatedData.eachMetaObjectId, {to: 'string'}), - eachMetaObjectType: new Uint32Array(inflate(deflatedData.eachMetaObjectType)), - eachMetaObjectName: pako$2.inflate(deflatedData.eachMetaObjectName, {to: 'string'}), - eachMetaObjectParent: new Uint32Array(inflate(deflatedData.eachMetaObjectParent)), + const self = this; - positions: new Uint16Array(inflate(deflatedData.positions)), - normals: new Int8Array(inflate(deflatedData.normals)), - colors: new Uint8Array(inflate(deflatedData.colors)), - indices: new Uint32Array(inflate(deflatedData.indices)), - edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + var grabbed = false; - matrices: new Float32Array(inflate(deflatedData.matrices)), - reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + const DRAG_ACTIONS = { + none: -1, + xTranslate: 0, + yTranslate: 1, + zTranslate: 2, + xRotate: 3, + yRotate: 4, + zRotate: 5 + }; - eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), - eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), - eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), - eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), - eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), - eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + const rootNode = this._rootNode; - eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), - eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), - eachMeshMaterial: new Uint8Array(inflate(deflatedData.eachMeshMaterial)), + var nextDragAction = null; // As we hover grabbed an arrow or hoop, self is the action we would do if we then dragged it. + var dragAction = null; // Action we're doing while we drag an arrow or hoop. + const lastCanvasPos = math.vec2(); - eachEntityMetaObject: new Uint32Array(inflate(deflatedData.eachEntityMetaObject)), - eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + const xBaseAxis = math.vec3([1, 0, 0]); + const yBaseAxis = math.vec3([0, 1, 0]); + const zBaseAxis = math.vec3([0, 0, 1]); - eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), - eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), - }; -} + const canvas = this._viewer.scene.canvas.canvas; + const camera = this._viewer.camera; + const scene = this._viewer.scene; -const decompressColor$2 = (function () { - const floatColor = new Float32Array(3); - return function (intColor) { - floatColor[0] = intColor[0] / 255.0; - floatColor[1] = intColor[1] / 255.0; - floatColor[2] = intColor[2] / 255.0; - return floatColor; - }; -})(); + { // Keep gizmo screen size constant -function convertColorsRGBToRGBA(colorsRGB) { - const colorsRGBA = []; - for (let i = 0, len = colorsRGB.length; i < len; i += 3) { - colorsRGBA.push(colorsRGB[i]); - colorsRGBA.push(colorsRGB[i + 1]); - colorsRGBA.push(colorsRGB[i + 2]); - colorsRGBA.push(1.0); - } - return colorsRGBA; -} + const tempVec3a = math.vec3([0, 0, 0]); + let lastDist = -1; -function load$2(viewer, options, inflatedData, sceneModel) { + this._onCameraViewMatrix = scene.camera.on("viewMatrix", () => { + }); - const types = JSON.parse(inflatedData.types); - const eachMetaObjectId = JSON.parse(inflatedData.eachMetaObjectId); - const eachMetaObjectType = inflatedData.eachMetaObjectType; - const eachMetaObjectName = JSON.parse(inflatedData.eachMetaObjectName); - const eachMetaObjectParent = inflatedData.eachMetaObjectParent; + this._onCameraProjMatrix = scene.camera.on("projMatrix", () => { + }); - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const colors = inflatedData.colors; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; + this._onSceneTick = scene.on("tick", () => { - const matrices = inflatedData.matrices; - const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + const dist = Math.abs(math.lenVec3(math.subVec3(scene.camera.eye, this._pos, tempVec3a))); - const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; - const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; - const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; - const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; - const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; - const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + if (dist !== lastDist) { + if (camera.projection === "perspective") { + const worldSize = (Math.tan(camera.perspective.fov * math.DEGTORAD)) * dist; + const size = 0.07 * worldSize; + rootNode.scale = [size, size, size]; + lastDist = dist; + } + } - const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; - const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; - const eachMeshMaterial = inflatedData.eachMeshMaterial; + if (camera.projection === "ortho") { + const worldSize = camera.ortho.scale / 10; + const size = worldSize; + rootNode.scale = [size, size, size]; + lastDist = dist; + } + }); + } - const eachEntityMetaObject = inflatedData.eachEntityMetaObject; - const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + const getClickCoordsWithinElement = (function () { + const canvasPos = new Float64Array(2); + return function (event) { + if (!event) { + event = window.event; + canvasPos[0] = event.x; + canvasPos[1] = event.y; + } else { + var element = event.target; + var totalOffsetLeft = 0; + var totalOffsetTop = 0; - const eachTileAABB = inflatedData.eachTileAABB; - const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + while (element.offsetParent) { + totalOffsetLeft += element.offsetLeft; + totalOffsetTop += element.offsetTop; + element = element.offsetParent; + } + canvasPos[0] = event.pageX - totalOffsetLeft; + canvasPos[1] = event.pageY - totalOffsetTop; + } + return canvasPos; + }; + })(); - const numMetaObjects = eachMetaObjectId.length; - const numGeometries = eachGeometryPositionsPortion.length; - const numMeshes = eachMeshGeometriesPortion.length; - const numEntities = eachEntityMetaObject.length; - const numTiles = eachTileEntitiesPortion.length; + const localToWorldVec = (function () { + const mat = math.mat4(); + return function (localVec, worldVec) { + math.quaternionToMat4(self._rootNode.quaternion, mat); + math.transformVec3(mat, localVec, worldVec); + math.normalizeVec3(worldVec); + return worldVec; + }; + })(); - let nextMeshId = 0; + var getTranslationPlane = (function () { + const planeNormal = math.vec3(); + return function (worldAxis) { + const absX = Math.abs(worldAxis[0]); + if (absX > Math.abs(worldAxis[1]) && absX > Math.abs(worldAxis[2])) { + math.cross3Vec3(worldAxis, [0, 1, 0], planeNormal); + } else { + math.cross3Vec3(worldAxis, [1, 0, 0], planeNormal); + } + math.cross3Vec3(planeNormal, worldAxis, planeNormal); + math.normalizeVec3(planeNormal); + return planeNormal; + } + })(); - // Create metamodel, unless already loaded from JSON by XKTLoaderPlugin + const dragTranslateSectionPlane = (function () { + const p1 = math.vec3(); + const p2 = math.vec3(); + const worldAxis = math.vec4(); + return function (baseAxis, fromMouse, toMouse) { + localToWorldVec(baseAxis, worldAxis); + const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse); + getPointerPlaneIntersect(fromMouse, planeNormal, p1); + getPointerPlaneIntersect(toMouse, planeNormal, p2); + math.subVec3(p2, p1); + const dot = math.dotVec3(p2, worldAxis); + self._pos[0] += worldAxis[0] * dot; + self._pos[1] += worldAxis[1] * dot; + self._pos[2] += worldAxis[2] * dot; + self._rootNode.position = self._pos; + if (self._sectionPlane) { + self._sectionPlane.pos = self._pos; + } + } + })(); - const metaModelId = sceneModel.id; + var dragRotateSectionPlane = (function () { + const p1 = math.vec4(); + const p2 = math.vec4(); + const c = math.vec4(); + const worldAxis = math.vec4(); + return function (baseAxis, fromMouse, toMouse) { + localToWorldVec(baseAxis, worldAxis); + const hasData = getPointerPlaneIntersect(fromMouse, worldAxis, p1) && getPointerPlaneIntersect(toMouse, worldAxis, p2); + if (!hasData) { // Find intersections with view plane and project down to origin + const planeNormal = getTranslationPlane(worldAxis, fromMouse, toMouse); + getPointerPlaneIntersect(fromMouse, planeNormal, p1, 1); // Ensure plane moves closer to camera so angles become workable + getPointerPlaneIntersect(toMouse, planeNormal, p2, 1); + var dot = math.dotVec3(p1, worldAxis); + p1[0] -= dot * worldAxis[0]; + p1[1] -= dot * worldAxis[1]; + p1[2] -= dot * worldAxis[2]; + dot = math.dotVec3(p2, worldAxis); + p2[0] -= dot * worldAxis[0]; + p2[1] -= dot * worldAxis[1]; + p2[2] -= dot * worldAxis[2]; + } + math.normalizeVec3(p1); + math.normalizeVec3(p2); + dot = math.dotVec3(p1, p2); + dot = math.clamp(dot, -1.0, 1.0); // Rounding errors cause dot to exceed allowed range + var incDegrees = Math.acos(dot) * math.RADTODEG; + math.cross3Vec3(p1, p2, c); + if (math.dotVec3(c, worldAxis) < 0.0) { + incDegrees = -incDegrees; + } + self._rootNode.rotate(baseAxis, incDegrees); + rotateSectionPlane(); + } + })(); - if (!viewer.metaScene.metaModels[metaModelId]) { + var getPointerPlaneIntersect = (function () { + const dir = math.vec4([0, 0, 0, 1]); + const matrix = math.mat4(); + return function (mouse, axis, dest, offset) { + offset = offset || 0; + dir[0] = mouse[0] / canvas.width * 2.0 - 1.0; + dir[1] = -(mouse[1] / canvas.height * 2.0 - 1.0); + dir[2] = 0.0; + dir[3] = 1.0; + math.mulMat4(camera.projMatrix, camera.viewMatrix, matrix); // Unproject norm device coords to view coords + math.inverseMat4(matrix); + math.transformVec4(matrix, dir, dir); + math.mulVec4Scalar(dir, 1.0 / dir[3]); // This is now point A on the ray in world space + var rayO = camera.eye; // The direction + math.subVec4(dir, rayO, dir); + const origin = self._sectionPlane.pos; // Plane origin: + var d = -math.dotVec3(origin, axis) - offset; + var dot = math.dotVec3(axis, dir); + if (Math.abs(dot) > 0.005) { + var t = -(math.dotVec3(axis, rayO) + d) / dot; + math.mulVec3Scalar(dir, t, dest); + math.addVec3(dest, rayO); + math.subVec3(dest, origin, dest); + return true; + } + return false; + } + })(); - const metaModelData = { - metaObjects: [] - }; + const rotateSectionPlane = (function () { + const dir = math.vec3(); + const mat = math.mat4(); + return function () { + if (self.sectionPlane) { + math.quaternionToMat4(rootNode.quaternion, mat); // << --- + math.transformVec3(mat, [0, 0, 1], dir); + self._setSectionPlaneDir(dir); + } + }; + })(); - for (let metaObjectIndex = 0; metaObjectIndex < numMetaObjects; metaObjectIndex++) { + { + var down = false; + var lastAffordanceMesh; - const metaObjectId = eachMetaObjectId[metaObjectIndex]; - const typeIndex = eachMetaObjectType[metaObjectIndex]; - const metaObjectType = types[typeIndex] || "default"; - const metaObjectName = eachMetaObjectName[metaObjectIndex]; - const metaObjectParentIndex = eachMetaObjectParent[metaObjectIndex]; - const metaObjectParentId = (metaObjectParentIndex !== metaObjectIndex) ? eachMetaObjectId[metaObjectParentIndex] : null; + this._onCameraControlHover = this._viewer.cameraControl.on("hoverEnter", (hit) => { + if (!this._visible) { + return; + } + if (down) { + return; + } + grabbed = false; + if (lastAffordanceMesh) { + lastAffordanceMesh.visible = false; + } + var affordanceMesh; + const meshId = hit.entity.id; + switch (meshId) { - metaModelData.metaObjects.push({ - id: metaObjectId, - type: metaObjectType, - name: metaObjectName, - parent: metaObjectParentId - }); - } + case this._displayMeshes.xAxisArrowHandle.id: + affordanceMesh = this._affordanceMeshes.xAxisArrow; + nextDragAction = DRAG_ACTIONS.xTranslate; + break; - viewer.metaScene.createMetaModel(metaModelId, metaModelData, { - includeTypes: options.includeTypes, - excludeTypes: options.excludeTypes, - globalizeObjectIds: options.globalizeObjectIds - }); + case this._displayMeshes.xAxisHandle.id: + affordanceMesh = this._affordanceMeshes.xAxisArrow; + nextDragAction = DRAG_ACTIONS.xTranslate; + break; - sceneModel.once("destroyed", () => { - viewer.metaScene.destroyMetaModel(metaModelId); - }); - } + case this._displayMeshes.yAxisArrowHandle.id: + affordanceMesh = this._affordanceMeshes.yAxisArrow; + nextDragAction = DRAG_ACTIONS.yTranslate; + break; - // Count instances of each geometry + case this._displayMeshes.yShaftHandle.id: + affordanceMesh = this._affordanceMeshes.yAxisArrow; + nextDragAction = DRAG_ACTIONS.yTranslate; + break; - const geometryReuseCounts = new Uint32Array(numGeometries); + case this._displayMeshes.zAxisArrowHandle.id: + affordanceMesh = this._affordanceMeshes.zAxisArrow; + nextDragAction = DRAG_ACTIONS.zTranslate; + break; - for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - if (geometryReuseCounts[geometryIndex] !== undefined) { - geometryReuseCounts[geometryIndex]++; - } else { - geometryReuseCounts[geometryIndex] = 1; - } - } + case this._displayMeshes.zAxisHandle.id: + affordanceMesh = this._affordanceMeshes.zAxisArrow; + nextDragAction = DRAG_ACTIONS.zTranslate; + break; - // Iterate over tiles + case this._displayMeshes.xCurveHandle.id: + affordanceMesh = this._affordanceMeshes.xHoop; + nextDragAction = DRAG_ACTIONS.xRotate; + break; - const tileCenter = math.vec3(); - const rtcAABB = math.AABB3(); + case this._displayMeshes.yCurveHandle.id: + affordanceMesh = this._affordanceMeshes.yHoop; + nextDragAction = DRAG_ACTIONS.yRotate; + break; - const geometryArraysCache = {}; + case this._displayMeshes.zCurveHandle.id: + affordanceMesh = this._affordanceMeshes.zHoop; + nextDragAction = DRAG_ACTIONS.zRotate; + break; - for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + default: + nextDragAction = DRAG_ACTIONS.none; + return; // Not clicked an arrow or hoop + } + if (affordanceMesh) { + affordanceMesh.visible = true; + } + lastAffordanceMesh = affordanceMesh; + grabbed = true; + }); - const lastTileIndex = (numTiles - 1); + this._onCameraControlHoverLeave = this._viewer.cameraControl.on("hoverOut", (hit) => { + if (!this._visible) { + return; + } + if (lastAffordanceMesh) { + lastAffordanceMesh.visible = false; + } + lastAffordanceMesh = null; + nextDragAction = DRAG_ACTIONS.none; + }); - const atLastTile = (tileIndex === lastTileIndex); + canvas.addEventListener("mousedown", this._canvasMouseDownListener = (e) => { + e.preventDefault(); + if (!this._visible) { + return; + } + if (!grabbed) { + return; + } + this._viewer.cameraControl.pointerEnabled = false; + switch (e.which) { + case 1: // Left button + down = true; + var canvasPos = getClickCoordsWithinElement(e); + dragAction = nextDragAction; + lastCanvasPos[0] = canvasPos[0]; + lastCanvasPos[1] = canvasPos[1]; + break; + } + }); - const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; - const lastTileEntityIndex = atLastTile ? numEntities : eachTileEntitiesPortion[tileIndex + 1]; + canvas.addEventListener("mousemove", this._canvasMouseMoveListener = (e) => { + if (!this._visible) { + return; + } + if (!down) { + return; + } + var canvasPos = getClickCoordsWithinElement(e); + const x = canvasPos[0]; + const y = canvasPos[1]; - const tileAABBIndex = tileIndex * 6; - const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + switch (dragAction) { + case DRAG_ACTIONS.xTranslate: + dragTranslateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos); + break; + case DRAG_ACTIONS.yTranslate: + dragTranslateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos); + break; + case DRAG_ACTIONS.zTranslate: + dragTranslateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos); + break; + case DRAG_ACTIONS.xRotate: + dragRotateSectionPlane(xBaseAxis, lastCanvasPos, canvasPos); + break; + case DRAG_ACTIONS.yRotate: + dragRotateSectionPlane(yBaseAxis, lastCanvasPos, canvasPos); + break; + case DRAG_ACTIONS.zRotate: + dragRotateSectionPlane(zBaseAxis, lastCanvasPos, canvasPos); + break; + } - math.getAABB3Center(tileAABB, tileCenter); + lastCanvasPos[0] = x; + lastCanvasPos[1] = y; + }); - rtcAABB[0] = tileAABB[0] - tileCenter[0]; - rtcAABB[1] = tileAABB[1] - tileCenter[1]; - rtcAABB[2] = tileAABB[2] - tileCenter[2]; - rtcAABB[3] = tileAABB[3] - tileCenter[0]; - rtcAABB[4] = tileAABB[4] - tileCenter[1]; - rtcAABB[5] = tileAABB[5] - tileCenter[2]; + canvas.addEventListener("mouseup", this._canvasMouseUpListener = (e) => { + if (!this._visible) { + return; + } + this._viewer.cameraControl.pointerEnabled = true; + if (!down) { + return; + } + switch (e.which) { + } + down = false; + grabbed = false; + }); - const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + canvas.addEventListener("wheel", this._canvasWheelListener = (e) => { + if (!this._visible) { + return; + } + var delta = Math.max(-1, Math.min(1, -e.deltaY * 40)); + if (delta === 0) { + return; + } + }); + } + } - const geometryCreatedInTile = {}; + _destroy() { + this._unbindEvents(); + this._destroyNodes(); + } - // Iterate over each tile's entities + _unbindEvents() { - for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex < lastTileEntityIndex; tileEntityIndex++) { + const viewer = this._viewer; + const scene = viewer.scene; + const canvas = scene.canvas.canvas; + const camera = viewer.camera; + const cameraControl = viewer.cameraControl; - const xktMetaObjectIndex = eachEntityMetaObject[tileEntityIndex]; - const xktMetaObjectId = eachMetaObjectId[xktMetaObjectIndex]; - const xktEntityId = xktMetaObjectId; + scene.off(this._onSceneTick); - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + canvas.removeEventListener("mousedown", this._canvasMouseDownListener); + canvas.removeEventListener("mousemove", this._canvasMouseMoveListener); + canvas.removeEventListener("mouseup", this._canvasMouseUpListener); + canvas.removeEventListener("wheel", this._canvasWheelListener); - const lastTileEntityIndex = (numEntities - 1); - const atLastTileEntity = (tileEntityIndex === lastTileEntityIndex); - const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; - const lastMeshIndex = atLastTileEntity ? eachMeshGeometriesPortion.length : eachEntityMeshesPortion[tileEntityIndex + 1]; + camera.off(this._onCameraViewMatrix); + camera.off(this._onCameraProjMatrix); - const meshIds = []; + cameraControl.off(this._onCameraControlHover); + cameraControl.off(this._onCameraControlHoverLeave); + } - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; + _destroyNodes() { + this._setSectionPlane(null); + this._rootNode.destroy(); + this._displayMeshes = {}; + this._affordanceMeshes = {}; + } +} - if (metaObject) { +/** + * Renders a 3D plane within an {@link Overview} to indicate its {@link SectionPlane}'s current position and orientation. + * + * @private + */ +class Plane { - // Mask loading of object types + /** @private */ + constructor(overview, overviewScene, sectionPlane) { - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } + /** + * The ID of this SectionPlanesOverviewPlane. + * + * @type {String} + */ + this.id = sectionPlane.id; - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } + /** + * The {@link SectionPlane} represented by this SectionPlanesOverviewPlane. + * + * @type {SectionPlane} + */ + this._sectionPlane = sectionPlane; - // Get initial property values for object types + this._mesh = new Mesh(overviewScene, { + id: sectionPlane.id, + geometry: new ReadableGeometry(overviewScene, buildBoxGeometry({ + xSize: .5, + ySize: .5, + zSize: .001 + })), + material: new PhongMaterial(overviewScene, { + emissive: [1, 1, 1], + diffuse: [0, 0, 0], + backfaces: false + }), + edgeMaterial: new EdgeMaterial(overviewScene, { + edgeColor: [0.0, 0.0, 0.0], + edgeAlpha: 1.0, + edgeWidth: 1 + }), + highlightMaterial: new EmphasisMaterial(overviewScene, { + fill: true, + fillColor: [0.5, 1, 0.5], + fillAlpha: 0.7, + edges: true, + edgeColor: [0.0, 0.0, 0.0], + edgeAlpha: 1.0, + edgeWidth: 1 + }), + selectedMaterial: new EmphasisMaterial(overviewScene, { + fill: true, + fillColor: [0, 0, 1], + fillAlpha: 0.7, + edges: true, + edgeColor: [1.0, 0.0, 0.0], + edgeAlpha: 1.0, + edgeWidth: 1 + }), + highlighted: true, + scale: [3, 3, 3], + position: [0, 0, 0], + rotation: [0, 0, 0], + opacity: 0.3, + edges: true + }); - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; - } - if (props.metallic !== undefined && props.metallic !== null) { - meshDefaults.metallic = props.metallic; - } - if (props.roughness !== undefined && props.roughness !== null) { - meshDefaults.roughness = props.roughness; - } - } + { + const vec = math.vec3([0, 0, 0]); + const pos2 = math.vec3(); + const zeroVec = math.vec3([0, 0, 1]); + const quat = math.vec4(4); + const pos3 = math.vec3(); - } else { - if (options.excludeUnclassifiedObjects) { - continue; - } - } + const update = () => { - // Iterate each entity's meshes + const origin = this._sectionPlane.scene.center; - for (let meshIndex = firstMeshIndex; meshIndex < lastMeshIndex; meshIndex++) { + const negDir = [-this._sectionPlane.dir[0], -this._sectionPlane.dir[1], -this._sectionPlane.dir[2]]; + math.subVec3(origin, this._sectionPlane.pos, vec); + const dist = -math.dotVec3(negDir, vec); - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - const geometryReuseCount = geometryReuseCounts[geometryIndex]; - const isReusedGeometry = (geometryReuseCount > 1); + math.normalizeVec3(negDir); + math.mulVec3Scalar(negDir, dist, pos2); + const quaternion = math.vec3PairToQuaternion(zeroVec, this._sectionPlane.dir, quat); - const atLastGeometry = (geometryIndex === (numGeometries - 1)); + pos3[0] = pos2[0] * 0.1; + pos3[1] = pos2[1] * 0.1; + pos3[2] = pos2[2] * 0.1; - const meshColor = decompressColor$2(eachMeshMaterial.subarray((meshIndex * 6), (meshIndex * 6) + 3)); - const meshOpacity = eachMeshMaterial[(meshIndex * 6) + 3] / 255.0; - const meshMetallic = eachMeshMaterial[(meshIndex * 6) + 4] / 255.0; - const meshRoughness = eachMeshMaterial[(meshIndex * 6) + 5] / 255.0; + this._mesh.quaternion = quaternion; + this._mesh.position = pos3; + }; - const meshId = nextMeshId++; + this._onSectionPlanePos = this._sectionPlane.on("pos", update); + this._onSectionPlaneDir = this._sectionPlane.on("dir", update); - if (isReusedGeometry) { + // update(); + } - // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry + this._highlighted = false; + this._selected = false; + } - const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; - const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); + /** + * Sets if this SectionPlanesOverviewPlane is highlighted. + * + * @type {Boolean} + * @private + */ + setHighlighted(highlighted) { + this._highlighted = !!highlighted; + this._mesh.highlighted = this._highlighted; + this._mesh.highlightMaterial.fillColor = highlighted ? [0, 0.7, 0] : [0, 0, 0]; + // this._selectedMesh.highlighted = true; + } - const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel + /** + * Gets if this SectionPlanesOverviewPlane is highlighted. + * + * @type {Boolean} + * @private + */ + getHighlighted() { + return this._highlighted; + } - let geometryArrays = geometryArraysCache[geometryId]; + /** + * Sets if this SectionPlanesOverviewPlane is selected. + * + * @type {Boolean} + * @private + */ + setSelected(selected) { + this._selected = !!selected; + this._mesh.edgeMaterial.edgeWidth = selected ? 3 : 1; + this._mesh.highlightMaterial.edgeWidth = selected ? 3 : 1; - if (!geometryArrays) { + } - geometryArrays = { - batchThisMesh: (!options.reuseGeometries) - }; + /** + * Gets if this SectionPlanesOverviewPlane is selected. + * + * @type {Boolean} + * @private + */ + getSelected() { + return this._selected; + } - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + /** @private */ + destroy() { + this._sectionPlane.off(this._onSectionPlanePos); + this._sectionPlane.off(this._onSectionPlaneDir); + this._mesh.destroy(); + } +} - let geometryValid = false; +/** + * @desc An interactive 3D overview for navigating the {@link SectionPlane}s created by its {@link SectionPlanesPlugin}. + * + * * Located at {@link SectionPlanesPlugin#overview}. + * * Renders the overview on a separate canvas at a corner of the {@link Viewer}'s {@link Scene} {@link Canvas}. + * * The overview shows a 3D plane object for each {@link SectionPlane} in the {@link Scene}. + * * Click a plane object in the overview to toggle the visibility of a 3D gizmo to edit the position and orientation of its {@link SectionPlane}. + * + * @private + */ +class Overview { - switch (primitiveType) { - case 0: - geometryArrays.primitiveName = "solid"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - case 1: - geometryArrays.primitiveName = "surface"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - case 2: - geometryArrays.primitiveName = "points"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryColors = convertColorsRGBToRGBA(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); - geometryValid = (geometryArrays.geometryPositions.length > 0); - break; - case 3: - geometryArrays.primitiveName = "lines"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - default: - continue; - } + /** + * @private + */ + constructor(plugin, cfg) { - if (!geometryValid) { - geometryArrays = null; - } + if (!cfg.onHoverEnterPlane || !cfg.onHoverLeavePlane || !cfg.onClickedNothing || !cfg.onClickedPlane) { + throw "Missing config(s): onHoverEnterPlane, onHoverLeavePlane, onClickedNothing || onClickedPlane"; + } - if (geometryArrays) { - if (geometryArrays.geometryPositions.length > 1000) ; - if (geometryArrays.batchThisMesh) { - geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length); - const geometryPositions = geometryArrays.geometryPositions; - const decompressedPositions = geometryArrays.decompressedPositions; - for (let i = 0, len = geometryPositions.length; i < len; i += 3) { - decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12]; - decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13]; - decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14]; - } - geometryArrays.geometryPositions = null; - geometryArraysCache[geometryId] = geometryArrays; - } - } - } + /** + * The {@link SectionPlanesPlugin} that owns this SectionPlanesOverview. + * + * @type {SectionPlanesPlugin} + */ + this.plugin = plugin; - if (geometryArrays) { + this._viewer = plugin.viewer; - if (geometryArrays.batchThisMesh) { + this._onHoverEnterPlane = cfg.onHoverEnterPlane; + this._onHoverLeavePlane = cfg.onHoverLeavePlane; + this._onClickedNothing = cfg.onClickedNothing; + this._onClickedPlane = cfg.onClickedPlane; + this._visible = true; - const decompressedPositions = geometryArrays.decompressedPositions; - const positions = new Uint16Array(decompressedPositions.length); - for (let i = 0, len = decompressedPositions.length; i < len; i += 3) { - tempVec4a$4[0] = decompressedPositions[i + 0]; - tempVec4a$4[1] = decompressedPositions[i + 1]; - tempVec4a$4[2] = decompressedPositions[i + 2]; - tempVec4a$4[3] = 1; - math.transformVec4(meshMatrix, tempVec4a$4, tempVec4b$4); - geometryCompressionUtils.compressPosition(tempVec4b$4, rtcAABB, tempVec4a$4); - positions[i + 0] = tempVec4a$4[0]; - positions[i + 1] = tempVec4a$4[1]; - positions[i + 2] = tempVec4a$4[2]; - } + this._planes = {}; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - origin: tileCenter, - primitive: geometryArrays.primitiveName, - positionsCompressed: positions, - normalsCompressed: geometryArrays.geometryNormals, - colorsCompressed: geometryArrays.geometryColors, - indices: geometryArrays.geometryIndices, - edgeIndices: geometryArrays.geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); + //-------------------------------------------------------------------------------------------------------------- + // Init canvas + //-------------------------------------------------------------------------------------------------------------- - meshIds.push(meshId); + this._canvas = cfg.overviewCanvas; - } else { + //-------------------------------------------------------------------------------------------------------------- + // Init scene + //-------------------------------------------------------------------------------------------------------------- - if (!geometryCreatedInTile[geometryId]) { + this._scene = new Scene(this._viewer, { + canvasId: this._canvas.id, + transparent: true + }); + this._scene.clearLights(); + new DirLight(this._scene, { + dir: [0.4, -0.4, 0.8], + color: [0.8, 1.0, 1.0], + intensity: 1.0, + space: "view" + }); + new DirLight(this._scene, { + dir: [-0.8, -0.3, -0.4], + color: [0.8, 0.8, 0.8], + intensity: 1.0, + space: "view" + }); + new DirLight(this._scene, { + dir: [0.8, -0.6, -0.8], + color: [1.0, 1.0, 1.0], + intensity: 1.0, + space: "view" + }); - sceneModel.createGeometry({ - id: geometryId, - primitive: geometryArrays.primitiveName, - positionsCompressed: geometryArrays.geometryPositions, - normalsCompressed: geometryArrays.geometryNormals, - colorsCompressed: geometryArrays.geometryColors, - indices: geometryArrays.geometryIndices, - edgeIndices: geometryArrays.geometryEdgeIndices, - positionsDecodeMatrix: reusedGeometriesDecodeMatrix - }); + this._scene.camera; + this._scene.camera.perspective.fov = 70; - geometryCreatedInTile[geometryId] = true; - } + this._zUp = false; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - origin: tileCenter, - matrix: meshMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); + //-------------------------------------------------------------------------------------------------------------- + // Synchronize overview scene camera with viewer camera + //-------------------------------------------------------------------------------------------------------------- - meshIds.push(meshId); - } - } + { + const camera = this._scene.camera; + const matrix = math.rotationMat4c(-90 * math.DEGTORAD, 1, 0, 0); + const eyeLookVec = math.vec3(); + const eyeLookVecOverview = math.vec3(); + const upOverview = math.vec3(); - } else { + this._synchCamera = () => { + const eye = this._viewer.camera.eye; + const look = this._viewer.camera.look; + const up = this._viewer.camera.up; + math.mulVec3Scalar(math.normalizeVec3(math.subVec3(eye, look, eyeLookVec)), 7); + if (this._zUp) { // +Z up + math.transformVec3(matrix, eyeLookVec, eyeLookVecOverview); + math.transformVec3(matrix, up, upOverview); + camera.look = [0, 0, 0]; + camera.eye = math.transformVec3(matrix, eyeLookVec, eyeLookVecOverview); + camera.up = math.transformPoint3(matrix, up, upOverview); + } else { // +Y up + camera.look = [0, 0, 0]; + camera.eye = eyeLookVec; + camera.up = up; + } + }; + } - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + this._onViewerCameraMatrix = this._viewer.camera.on("matrix", this._synchCamera); - let primitiveName; - let geometryPositions; - let geometryNormals; - let geometryColors; - let geometryIndices; - let geometryEdgeIndices; - let geometryValid = false; + this._onViewerCameraWorldAxis = this._viewer.camera.on("worldAxis", this._synchCamera); - switch (primitiveType) { - case 0: - primitiveName = "solid"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - case 1: - primitiveName = "surface"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - case 2: - primitiveName = "points"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryColors = convertColorsRGBToRGBA(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); - geometryValid = (geometryPositions.length > 0); - break; - case 3: - primitiveName = "lines"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - default: - continue; - } + this._onViewerCameraFOV = this._viewer.camera.perspective.on("fov", (fov) => { + this._scene.camera.perspective.fov = fov; + }); - if (geometryValid) { + //-------------------------------------------------------------------------------------------------------------- + // Bind overview canvas events + //-------------------------------------------------------------------------------------------------------------- - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - origin: tileCenter, - primitive: primitiveName, - positionsCompressed: geometryPositions, - normalsCompressed: geometryNormals, - colorsCompressed: geometryColors, - indices: geometryIndices, - edgeIndices: geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); + { + var hoveredEntity = null; - meshIds.push(meshId); + this._onInputMouseMove = this._scene.input.on("mousemove", (coords) => { + const hit = this._scene.pick({ + canvasPos: coords + }); + if (hit) { + if (!hoveredEntity || hit.entity.id !== hoveredEntity.id) { + if (hoveredEntity) { + const plane = this._planes[hoveredEntity.id]; + if (plane) { + this._onHoverLeavePlane(hoveredEntity.id); + } + } + hoveredEntity = hit.entity; + const plane = this._planes[hoveredEntity.id]; + if (plane) { + this._onHoverEnterPlane(hoveredEntity.id); + } + } + } else { + if (hoveredEntity) { + this._onHoverLeavePlane(hoveredEntity.id); + hoveredEntity = null; } } - } + }); - if (meshIds.length > 0) { + this._scene.canvas.canvas.addEventListener("mouseup", this._onCanvasMouseUp = () => { + if (hoveredEntity) { + const plane = this._planes[hoveredEntity.id]; + if (plane) { + this._onClickedPlane(hoveredEntity.id); + } + } else { + this._onClickedNothing(); + } + }); - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, - meshIds: meshIds - })); - } + this._scene.canvas.canvas.addEventListener("mouseout", this._onCanvasMouseOut = () => { + if (hoveredEntity) { + this._onHoverLeavePlane(hoveredEntity.id); + hoveredEntity = null; + } + }); } - } -} - -/** @private */ -const ParserV8 = { - version: 8, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$2(elements); - const inflatedData = inflate$2(deflatedData); - load$2(viewer, options, inflatedData, sceneModel); - } -}; - -/* - - Parser for .XKT Format V9 - - */ - -let pako$1 = window.pako || p; -if (!pako$1.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako$1 = pako$1.default; -} - -const tempVec4a$3 = math.vec4(); -const tempVec4b$3 = math.vec4(); - -function extract$1(elements) { - - return { - - // Metadata - metadata: elements[0], - - positions: elements[1], - normals: elements[2], - colors: elements[3], - indices: elements[4], - edgeIndices: elements[5], + //-------------------------------------------------------------------------------------------------------------- + // Configure overview + //-------------------------------------------------------------------------------------------------------------- - // Transform matrices + this.setVisible(cfg.overviewVisible); + } - matrices: elements[6], - reusedGeometriesDecodeMatrix: elements[7], + /** Called by SectionPlanesPlugin#createSectionPlane() + * @private + */ + addSectionPlane(sectionPlane) { + this._planes[sectionPlane.id] = new Plane(this, this._scene, sectionPlane); + } - // Geometries + /** @private + */ + setPlaneHighlighted(id, highlighted) { + const plane = this._planes[id]; + if (plane) { + plane.setHighlighted(highlighted); + } + } - eachGeometryPrimitiveType: elements[8], - eachGeometryPositionsPortion: elements[9], - eachGeometryNormalsPortion: elements[10], - eachGeometryColorsPortion: elements[11], - eachGeometryIndicesPortion: elements[12], - eachGeometryEdgeIndicesPortion: elements[13], + /** @private + */ + setPlaneSelected(id, selected) { + const plane = this._planes[id]; + if (plane) { + plane.setSelected(selected); + } + } - // Meshes are grouped in runs that are shared by the same entities + /** @private + */ + removeSectionPlane(sectionPlane) { + const plane = this._planes[sectionPlane.id]; + if (plane) { + plane.destroy(); + delete this._planes[sectionPlane.id]; + } + } - eachMeshGeometriesPortion: elements[14], - eachMeshMatricesPortion: elements[15], - eachMeshMaterial: elements[16], + /** + * Sets if this SectionPlanesOverview is visible. + * + * @param {Boolean} visible Whether or not this SectionPlanesOverview is visible. + */ + setVisible(visible = true) { + this._visible = visible; + this._canvas.style.visibility = visible ? "visible" : "hidden"; + } - // Entity elements in the following arrays are grouped in runs that are shared by the same tiles + /** + * Gets if this SectionPlanesOverview is visible. + * + * @return {Boolean} True when this SectionPlanesOverview is visible. + */ + getVisible() { + return this._visible; + } - eachEntityId: elements[17], - eachEntityMeshesPortion: elements[18], + /** @private + */ + destroy() { + this._viewer.camera.off(this._onViewerCameraMatrix); + this._viewer.camera.off(this._onViewerCameraWorldAxis); + this._viewer.camera.perspective.off(this._onViewerCameraFOV); - eachTileAABB: elements[19], - eachTileEntitiesPortion: elements[20] - }; + this._scene.input.off(this._onInputMouseMove); + this._scene.canvas.canvas.removeEventListener("mouseup", this._onCanvasMouseUp); + this._scene.canvas.canvas.removeEventListener("mouseout", this._onCanvasMouseOut); + this._scene.destroy(); + } } -function inflate$1(deflatedData) { - - function inflate(array, options) { - return (array.length === 0) ? [] : pako$1.inflate(array, options).buffer; - } +const tempAABB = math.AABB3(); +const tempVec3 = math.vec3(); - return { +/** + * SectionPlanesPlugin is a {@link Viewer} plugin that manages {@link SectionPlane}s. + * + * [](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_SectionPlanesPlugin) + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#gizmos_SectionPlanesPlugin)] + * + * ## Overview + * + * * Use the SectionPlanesPlugin to + * create and edit {@link SectionPlane}s to slice portions off your models and reveal internal structures. + * * As shown in the screen capture above, SectionPlanesPlugin shows an overview of all your SectionPlanes (on the right, in + * this example). + * * Click a plane in the overview to activate a 3D control with which you can interactively + * reposition its SectionPlane in the main canvas. + * * Use {@lin BCFViewpointsPlugin} to save and load SectionPlanes in BCF viewpoints. + * + * ## Usage + * + * In the example below, we'll use a {@link GLTFLoaderPlugin} to load a model, and a SectionPlanesPlugin + * to slice it open with two {@link SectionPlane}s. We'll show the overview in the bottom right of the Viewer + * canvas. Finally, we'll programmatically activate the 3D editing control, so that we can use it to interactively + * reposition our second SectionPlane. + * + * ````JavaScript + * import {Viewer, GLTFLoaderPlugin, SectionPlanesPlugin} from "xeokit-sdk.es.js"; + * + * // Create a Viewer and arrange its Camera + * + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * viewer.camera.eye = [-5.02, 2.22, 15.09]; + * viewer.camera.look = [4.97, 2.79, 9.89]; + * viewer.camera.up = [-0.05, 0.99, 0.02]; + * + * + * // Add a GLTFLoaderPlugin + * + * const gltfLoader = new GLTFLoaderPlugin(viewer); + * + * // Add a SectionPlanesPlugin, with overview visible + * + * const sectionPlanes = new SectionPlanesPlugin(viewer, { + * overviewCanvasID: "myOverviewCanvas", + * overviewVisible: true + * }); + * + * // Load a model + * + * const model = gltfLoader.load({ + * id: "myModel", + * src: "./models/gltf/schependomlaan/scene.gltf" + * }); + * + * // Create a couple of section planes + * // These will be shown in the overview + * + * sectionPlanes.createSectionPlane({ + * id: "mySectionPlane", + * pos: [1.04, 1.95, 9.74], + * dir: [1.0, 0.0, 0.0] + * }); + * + * sectionPlanes.createSectionPlane({ + * id: "mySectionPlane2", + * pos: [2.30, 4.46, 14.93], + * dir: [0.0, -0.09, -0.79] + * }); + * + * // Show the SectionPlanePlugin's 3D editing gizmo, + * // to interactively reposition one of our SectionPlanes + * + * sectionPlanes.showControl("mySectionPlane2"); + * + * const mySectionPlane2 = sectionPlanes.sectionPlanes["mySectionPlane2"]; + * + * // Programmatically reposition one of our SectionPlanes + * // This also updates its position as shown in the overview gizmo + * + * mySectionPlane2.pos = [11.0, 6.0, -12]; + * mySectionPlane2.dir = [0.4, 0.0, 0.5]; + * ```` + */ +class SectionPlanesPlugin extends Plugin { - metadata: JSON.parse(pako$1.inflate(deflatedData.metadata, {to: 'string'})), + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="SectionPlanes"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {String} [cfg.overviewCanvasId] ID of a canvas element to display the overview. + * @param {String} [cfg.overviewVisible=true] Initial visibility of the overview canvas. + */ + constructor(viewer, cfg = {}) { - positions: new Uint16Array(inflate(deflatedData.positions)), - normals: new Int8Array(inflate(deflatedData.normals)), - colors: new Uint8Array(inflate(deflatedData.colors)), - indices: new Uint32Array(inflate(deflatedData.indices)), - edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + super("SectionPlanes", viewer); - matrices: new Float32Array(inflate(deflatedData.matrices)), - reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + this._freeControls = []; + this._sectionPlanes = viewer.scene.sectionPlanes; + this._controls = {}; + this._shownControlId = null; - eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), - eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), - eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), - eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), - eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), - eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + if (cfg.overviewCanvasId !== null && cfg.overviewCanvasId !== undefined) { - eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), - eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), - eachMeshMaterial: new Uint8Array(inflate(deflatedData.eachMeshMaterial)), + const overviewCanvas = document.getElementById(cfg.overviewCanvasId); - eachEntityId: JSON.parse(pako$1.inflate(deflatedData.eachEntityId, {to: 'string'})), - eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + if (!overviewCanvas) { + this.warn("Can't find overview canvas: '" + cfg.overviewCanvasId + "' - will create plugin without overview"); - eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), - eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), - }; -} + } else { -const decompressColor$1 = (function () { - const floatColor = new Float32Array(3); - return function (intColor) { - floatColor[0] = intColor[0] / 255.0; - floatColor[1] = intColor[1] / 255.0; - floatColor[2] = intColor[2] / 255.0; - return floatColor; - }; -})(); + this._overview = new Overview(this, { + overviewCanvas: overviewCanvas, + visible: cfg.overviewVisible, -function load$1(viewer, options, inflatedData, sceneModel) { + onHoverEnterPlane: ((id) => { + this._overview.setPlaneHighlighted(id, true); + }), - const metadata = inflatedData.metadata; + onHoverLeavePlane: ((id) => { + this._overview.setPlaneHighlighted(id, false); + }), - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const colors = inflatedData.colors; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; + onClickedPlane: ((id) => { + if (this.getShownControl() === id) { + this.hideControl(); + return; + } + this.showControl(id); + const sectionPlane = this.sectionPlanes[id]; + const sectionPlanePos = sectionPlane.pos; + tempAABB.set(this.viewer.scene.aabb); + math.getAABB3Center(tempAABB, tempVec3); + tempAABB[0] += sectionPlanePos[0] - tempVec3[0]; + tempAABB[1] += sectionPlanePos[1] - tempVec3[1]; + tempAABB[2] += sectionPlanePos[2] - tempVec3[2]; + tempAABB[3] += sectionPlanePos[0] - tempVec3[0]; + tempAABB[4] += sectionPlanePos[1] - tempVec3[1]; + tempAABB[5] += sectionPlanePos[2] - tempVec3[2]; + this.viewer.cameraFlight.flyTo({ + aabb: tempAABB, + fitFOV: 65 + }); + }), - const matrices = inflatedData.matrices; - const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + onClickedNothing: (() => { + this.hideControl(); + }) + }); + } + } - const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; - const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; - const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; - const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; - const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; - const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + this._onSceneSectionPlaneCreated = viewer.scene.on("sectionPlaneCreated", (sectionPlane) => { - const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; - const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; - const eachMeshMaterial = inflatedData.eachMeshMaterial; + // SectionPlane created, either via SectionPlanesPlugin#createSectionPlane(), or by directly + // instantiating a SectionPlane independently of SectionPlanesPlugin, which can be done + // by BCFViewpointsPlugin#loadViewpoint(). - const eachEntityId = inflatedData.eachEntityId; - const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + this._sectionPlaneCreated(sectionPlane); + }); + } - const eachTileAABB = inflatedData.eachTileAABB; - const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + /** + * Sets if the overview canvas is visible. + * + * @param {Boolean} visible Whether or not the overview canvas is visible. + */ + setOverviewVisible(visible) { + if (this._overview) { + this._overview.setVisible(visible); + } + } - const numGeometries = eachGeometryPositionsPortion.length; - const numMeshes = eachMeshGeometriesPortion.length; - const numEntities = eachEntityMeshesPortion.length; - const numTiles = eachTileEntitiesPortion.length; + /** + * Gets if the overview canvas is visible. + * + * @return {Boolean} True when the overview canvas is visible. + */ + getOverviewVisible() { + if (this._overview) { + return this._overview.getVisible(); + } + } - let nextMeshId = 0; + /** + * Returns a map of the {@link SectionPlane}s created by this SectionPlanesPlugin. + * + * @returns {{String:SectionPlane}} A map containing the {@link SectionPlane}s, each mapped to its {@link SectionPlane#id}. + */ + get sectionPlanes() { + return this._sectionPlanes; + } - // Create metamodel, unless already loaded from external JSON file by XKTLoaderPlugin + /** + * Creates a {@link SectionPlane}. + * + * The {@link SectionPlane} will be registered by {@link SectionPlane#id} in {@link SectionPlanesPlugin#sectionPlanes}. + * + * @param {Object} params {@link SectionPlane} configuration. + * @param {String} [params.id] Unique ID to assign to the {@link SectionPlane}. Must be unique among all components in the {@link Viewer}'s {@link Scene}. Auto-generated when omitted. + * @param {Number[]} [params.pos=[0,0,0]] World-space position of the {@link SectionPlane}. + * @param {Number[]} [params.dir=[0,0,-1]] World-space vector indicating the orientation of the {@link SectionPlane}. + * @param {Boolean} [params.active=true] Whether the {@link SectionPlane} is initially active. Only clips while this is true. + * @returns {SectionPlane} The new {@link SectionPlane}. + */ + createSectionPlane(params = {}) { - const metaModelId = sceneModel.id; + if (params.id !== undefined && params.id !== null && this.viewer.scene.components[params.id]) { + this.error("Viewer component with this ID already exists: " + params.id); + delete params.id; + } - if (!viewer.metaScene.metaModels[metaModelId]) { + // Note that SectionPlane constructor fires "sectionPlaneCreated" on the Scene, + // which SectionPlanesPlugin handles and calls #_sectionPlaneCreated to create gizmo and add to overview canvas. - viewer.metaScene.createMetaModel(metaModelId, metadata, { - includeTypes: options.includeTypes, - excludeTypes: options.excludeTypes, - globalizeObjectIds: options.globalizeObjectIds + const sectionPlane = new SectionPlane(this.viewer.scene, { + id: params.id, + pos: params.pos, + dir: params.dir, + active: true }); + return sectionPlane; + } - sceneModel.once("destroyed", () => { - viewer.metaScene.destroyMetaModel(metaModelId); + _sectionPlaneCreated(sectionPlane) { + const control = (this._freeControls.length > 0) ? this._freeControls.pop() : new Control(this); + control._setSectionPlane(sectionPlane); + control.setVisible(false); + this._controls[sectionPlane.id] = control; + if (this._overview) { + this._overview.addSectionPlane(sectionPlane); + } + sectionPlane.once("destroyed", () => { + this._sectionPlaneDestroyed(sectionPlane); }); } - // Count instances of each geometry - - const geometryReuseCounts = new Uint32Array(numGeometries); - - for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - if (geometryReuseCounts[geometryIndex] !== undefined) { - geometryReuseCounts[geometryIndex]++; - } else { - geometryReuseCounts[geometryIndex] = 1; + /** + * Inverts the direction of {@link SectionPlane#dir} on every existing SectionPlane. + * + * Inverts all SectionPlanes, including those that were not created with SectionPlanesPlugin. + */ + flipSectionPlanes() { + const sectionPlanes = this.viewer.scene.sectionPlanes; + for (let id in sectionPlanes) { + const sectionPlane = sectionPlanes[id]; + sectionPlane.flipDir(); } } - // Iterate over tiles + /** + * Shows the 3D editing gizmo for a {@link SectionPlane}. + * + * @param {String} id ID of the {@link SectionPlane}. + */ + showControl(id) { + const control = this._controls[id]; + if (!control) { + this.error("Control not found: " + id); + return; + } + this.hideControl(); + control.setVisible(true); + if (this._overview) { + this._overview.setPlaneSelected(id, true); + } + this._shownControlId = id; + } - const tileCenter = math.vec3(); - const rtcAABB = math.AABB3(); + /** + * Gets the ID of the {@link SectionPlane} that the 3D editing gizmo is shown for. + * + * Returns ````null```` when the editing gizmo is not shown. + * + * @returns {String} ID of the the {@link SectionPlane} that the 3D editing gizmo is shown for, if shown, else ````null````. + */ + getShownControl() { + return this._shownControlId; + } - const geometryArraysCache = {}; + /** + * Hides the 3D {@link SectionPlane} editing gizmo if shown. + */ + hideControl() { + for (var id in this._controls) { + if (this._controls.hasOwnProperty(id)) { + this._controls[id].setVisible(false); + if (this._overview) { + this._overview.setPlaneSelected(id, false); + } + } + } + this._shownControlId = null; + } - for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + /** + * Destroys a {@link SectionPlane} created by this SectionPlanesPlugin. + * + * @param {String} id ID of the {@link SectionPlane}. + */ + destroySectionPlane(id) { + var sectionPlane = this.viewer.scene.sectionPlanes[id]; + if (!sectionPlane) { + this.error("SectionPlane not found: " + id); + return; + } + this._sectionPlaneDestroyed(sectionPlane); + sectionPlane.destroy(); - const lastTileIndex = (numTiles - 1); + if (id === this._shownControlId) { + this._shownControlId = null; + } + } - const atLastTile = (tileIndex === lastTileIndex); + _sectionPlaneDestroyed(sectionPlane) { + if (this._overview) { + this._overview.removeSectionPlane(sectionPlane); + } + const control = this._controls[sectionPlane.id]; + if (!control) { + return; + } + control.setVisible(false); + control._setSectionPlane(null); + delete this._controls[sectionPlane.id]; + this._freeControls.push(control); + } - const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; - const lastTileEntityIndex = atLastTile ? (numEntities - 1) : (eachTileEntitiesPortion[tileIndex + 1] - 1); + /** + * Destroys all {@link SectionPlane}s created by this SectionPlanesPlugin. + */ + clear() { + const ids = Object.keys(this._sectionPlanes); + for (var i = 0, len = ids.length; i < len; i++) { + this.destroySectionPlane(ids[i]); + } + } - const tileAABBIndex = tileIndex * 6; - const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + /** + * @private + */ + send(name, value) { + switch (name) { - math.getAABB3Center(tileAABB, tileCenter); + case "snapshotStarting": // Viewer#getSnapshot() about to take snapshot - hide controls + for (let id in this._controls) { + if (this._controls.hasOwnProperty(id)) { + this._controls[id].setCulled(true); + } + } + break; - rtcAABB[0] = tileAABB[0] - tileCenter[0]; - rtcAABB[1] = tileAABB[1] - tileCenter[1]; - rtcAABB[2] = tileAABB[2] - tileCenter[2]; - rtcAABB[3] = tileAABB[3] - tileCenter[0]; - rtcAABB[4] = tileAABB[4] - tileCenter[1]; - rtcAABB[5] = tileAABB[5] - tileCenter[2]; + case "snapshotFinished": // Viewer#getSnapshot() finished taking snapshot - show controls again + for (let id in this._controls) { + if (this._controls.hasOwnProperty(id)) { + this._controls[id].setCulled(false); + } + } + break; - const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + case "clearSectionPlanes": + this.clear(); + break; + } + } - const geometryCreatedInTile = {}; + /** + * Destroys this SectionPlanesPlugin. + * + * Also destroys each {@link SectionPlane} created by this SectionPlanesPlugin. + * + * Does not destroy the canvas the SectionPlanesPlugin was configured with. + */ + destroy() { + this.clear(); + if (this._overview) { + this._overview.destroy(); + } + this._destroyFreeControls(); + super.destroy(); + } - // Iterate over each tile's entities + _destroyFreeControls() { + var control = this._freeControls.pop(); + while (control) { + control._destroy(); + control = this._freeControls.pop(); + } + this.viewer.scene.off(this._onSceneSectionPlaneCreated); + } +} - for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex <= lastTileEntityIndex; tileEntityIndex++) { +/** + * {@link Viewer} plugin that manages skyboxes + * + * @example + * + * // Create a Viewer + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * // Add a GLTFModelsPlugin + * var gltfLoaderPlugin = new GLTFModelsPlugin(viewer, { + * id: "GLTFModels" // Default value + * }); + * + * // Add a SkyboxesPlugin + * var skyboxesPlugin = new SkyboxesPlugin(viewer, { + * id: "Skyboxes" // Default value + * }); + * + * // Load a glTF model + * const model = gltfLoaderPlugin.load({ + * id: "myModel", + * src: "./models/gltf/mygltfmodel.gltf" + * }); + * + * // Create three directional World-space lights. "World" means that they will appear as if part + * // of the world, instead of "View", where they move with the user's head. + * + * skyboxesPlugin.createLight({ + * id: "keyLight", + * dir: [0.8, -0.6, -0.8], + * color: [1.0, 0.3, 0.3], + * intensity: 1.0, + * space: "world" + * }); + * + * skyboxesPlugin.createLight({ + * id: "fillLight", + * dir: [-0.8, -0.4, -0.4], + * color: [0.3, 1.0, 0.3], + * intensity: 1.0, + * space: "world" + * }); + * + * skyboxesPlugin.createDirLight({ + * id: "rimLight", + * dir: [0.2, -0.8, 0.8], + * color: [0.6, 0.6, 0.6], + * intensity: 1.0, + * space: "world" + * }); + * + * @class SkyboxesPlugin + */ +class SkyboxesPlugin extends Plugin { - const xktEntityId = eachEntityId[tileEntityIndex]; + constructor(viewer) { + super("skyboxes", viewer); + this.skyboxes = {}; + } - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + /** + * @private + */ + send(name, value) { + switch (name) { + case "clear": + this.clear(); + break; + } + } - const finalTileEntityIndex = (numEntities - 1); - const atLastTileEntity = (tileEntityIndex === finalTileEntityIndex); - const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; - const lastMeshIndex = atLastTileEntity ? (eachMeshGeometriesPortion.length - 1) : (eachEntityMeshesPortion[tileEntityIndex + 1] - 1); + /** + Creates a skybox. - const meshIds = []; + @param {String} id Unique ID to assign to the skybox. + @param {Object} params Skybox configuration. + @param {Boolean} [params.active=true] Whether the skybox plane is initially active. Only skyboxes while this is true. + @returns {Skybox} The new skybox. + */ + createSkybox(id, params) { + if (this.viewer.scene.components[id]) { + this.error("Component with this ID already exists: " + id); + return this; + } + var skybox = new Skybox(this.viewer.scene, { + id: id, + pos: params.pos, + dir: params.dir, + active: true + }); + this.skyboxes[id] = skybox; + return skybox; + } - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; + /** + Destroys a skybox. + @param id + */ + destroySkybox(id) { + var skybox = this.skyboxes[id]; + if (!skybox) { + this.error("Skybox not found: " + id); + return; + } + skybox.destroy(); + } - if (metaObject) { + /** + Destroys all skyboxes. + */ + clear() { + var ids = Object.keys(this.viewer.scene.skyboxes); + for (var i = 0, len = ids.length; i < len; i++) { + this.destroySkybox(ids[i]); + } + } - // Mask loading of object types - - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } - - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } - - // Get initial property values for object types - - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + /** + * Destroys this plugin. + * + * Clears skyboxes from the Viewer first. + */ + destroy() { + this.clear(); + super.clear(); + } +} - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; - } - if (props.metallic !== undefined && props.metallic !== null) { - meshDefaults.metallic = props.metallic; - } - if (props.roughness !== undefined && props.roughness !== null) { - meshDefaults.roughness = props.roughness; - } - } +/** + * Default data access strategy for {@link STLLoaderPlugin}. + * + * This implementation simply loads STL files using XMLHttpRequest. + */ +class STLDefaultDataSource { - } else { - if (options.excludeUnclassifiedObjects) { - continue; + /** + * Gets STL data. + * + * @param {String|Number} src Identifies the STL file. + * @param {Function} ok Fired on successful loading of the STL file. + * @param {Function} error Fired on error while loading the STL file. + */ + getSTL(src, ok, error) { + const request = new XMLHttpRequest(); + request.overrideMimeType("application/json"); + request.open('GET', src, true); + request.responseType = 'arraybuffer'; + request.onreadystatechange = function () { + if (request.readyState === 4) { + if (request.status === 200) { + ok(request.response); + } else { + error(request.statusText); } } + }; + request.send(null); + } +} - // Iterate each entity's meshes - - for (let meshIndex = firstMeshIndex; meshIndex <= lastMeshIndex; meshIndex++) { - - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - const geometryReuseCount = geometryReuseCounts[geometryIndex]; - const isReusedGeometry = (geometryReuseCount > 1); - - const atLastGeometry = (geometryIndex === (numGeometries - 1)); - - const meshColor = decompressColor$1(eachMeshMaterial.subarray((meshIndex * 6), (meshIndex * 6) + 3)); - const meshOpacity = eachMeshMaterial[(meshIndex * 6) + 3] / 255.0; - const meshMetallic = eachMeshMaterial[(meshIndex * 6) + 4] / 255.0; - const meshRoughness = eachMeshMaterial[(meshIndex * 6) + 5] / 255.0; - - const meshId = nextMeshId++; - - if (isReusedGeometry) { - - // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry - - const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; - const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); - - const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel - - let geometryArrays = geometryArraysCache[geometryId]; - - if (!geometryArrays) { - geometryArrays = { - batchThisMesh: (!options.reuseGeometries) - }; - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; - let geometryValid = false; - switch (primitiveType) { - case 0: - geometryArrays.primitiveName = "solid"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - case 1: - geometryArrays.primitiveName = "surface"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - case 2: - geometryArrays.primitiveName = "points"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0); - break; - case 3: - geometryArrays.primitiveName = "lines"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - default: - continue; - } - - if (!geometryValid) { - geometryArrays = null; - } - - if (geometryArrays) { - if (geometryArrays.geometryPositions.length > 1000) ; - if (geometryArrays.batchThisMesh) { - geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length); - geometryArrays.transformedAndRecompressedPositions = new Uint16Array(geometryArrays.geometryPositions.length); - const geometryPositions = geometryArrays.geometryPositions; - const decompressedPositions = geometryArrays.decompressedPositions; - for (let i = 0, len = geometryPositions.length; i < len; i += 3) { - decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12]; - decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13]; - decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14]; - } - geometryArrays.geometryPositions = null; - geometryArraysCache[geometryId] = geometryArrays; - } - } - } - - if (geometryArrays) { - - if (geometryArrays.batchThisMesh) { - - const decompressedPositions = geometryArrays.decompressedPositions; - const transformedAndRecompressedPositions = geometryArrays.transformedAndRecompressedPositions; - - for (let i = 0, len = decompressedPositions.length; i < len; i += 3) { - tempVec4a$3[0] = decompressedPositions[i + 0]; - tempVec4a$3[1] = decompressedPositions[i + 1]; - tempVec4a$3[2] = decompressedPositions[i + 2]; - tempVec4a$3[3] = 1; - math.transformVec4(meshMatrix, tempVec4a$3, tempVec4b$3); - geometryCompressionUtils.compressPosition(tempVec4b$3, rtcAABB, tempVec4a$3); - transformedAndRecompressedPositions[i + 0] = tempVec4a$3[0]; - transformedAndRecompressedPositions[i + 1] = tempVec4a$3[1]; - transformedAndRecompressedPositions[i + 2] = tempVec4a$3[2]; - } - - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - origin: tileCenter, - primitive: geometryArrays.primitiveName, - positionsCompressed: transformedAndRecompressedPositions, - normalsCompressed: geometryArrays.geometryNormals, - colorsCompressed: geometryArrays.geometryColors, - indices: geometryArrays.geometryIndices, - edgeIndices: geometryArrays.geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); - - meshIds.push(meshId); - - } else { +const tempVec3a$3 = math.vec3(); - if (!geometryCreatedInTile[geometryId]) { +/** + * @private + */ +class STLSceneGraphLoader { - sceneModel.createGeometry({ - id: geometryId, - primitive: geometryArrays.primitiveName, - positionsCompressed: geometryArrays.geometryPositions, - normalsCompressed: geometryArrays.geometryNormals, - colorsCompressed: geometryArrays.geometryColors, - indices: geometryArrays.geometryIndices, - edgeIndices: geometryArrays.geometryEdgeIndices, - positionsDecodeMatrix: reusedGeometriesDecodeMatrix - }); + load(plugin, modelNode, src, options, ok, error) { - geometryCreatedInTile[geometryId] = true; - } + options = options || {}; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - origin: tileCenter, - matrix: meshMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); + const spinner = plugin.viewer.scene.canvas.spinner; + spinner.processes++; - meshIds.push(meshId); - } + plugin.dataSource.getSTL(src, function (data) { // OK + parse(plugin, modelNode, data, options); + try { + const binData = ensureBinary(data); + if (isBinary(binData)) { + parseBinary(plugin, binData, modelNode, options); + } else { + parseASCII(plugin, ensureString(data), modelNode, options); } - - } else { - - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; - - let primitiveName; - let geometryPositions; - let geometryNormals; - let geometryColors; - let geometryIndices; - let geometryEdgeIndices; - let geometryValid = false; - - switch (primitiveType) { - case 0: - primitiveName = "solid"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - case 1: - primitiveName = "surface"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - case 2: - primitiveName = "points"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0); - break; - case 3: - primitiveName = "lines"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - default: - continue; + spinner.processes--; + core.scheduleTask(function () { + modelNode.fire("loaded", true, false); + }); + if (ok) { + ok(); } - - if (geometryValid) { - - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - origin: tileCenter, - primitive: primitiveName, - positionsCompressed: geometryPositions, - normalsCompressed: geometryNormals, - colorsCompressed: geometryColors, - indices: geometryIndices, - edgeIndices: geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); - - meshIds.push(meshId); + } catch (e) { + spinner.processes--; + plugin.error(e); + if (error) { + error(e); } + modelNode.fire("error", e); } - } - - if (meshIds.length > 0) { + }, + function (msg) { + spinner.processes--; + plugin.error(msg); + if (error) { + error(msg); + } + modelNode.fire("error", msg); + }); + } - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, - meshIds: meshIds - })); + parse(plugin, modelNode, data, options) { + const spinner = plugin.viewer.scene.canvas.spinner; + spinner.processes++; + try { + const binData = ensureBinary(data); + if (isBinary(binData)) { + parseBinary(plugin, binData, modelNode, options); + } else { + parseASCII(plugin, ensureString(data), modelNode, options); } + spinner.processes--; + core.scheduleTask(function () { + modelNode.fire("loaded", true, false); + }); + } catch (e) { + spinner.processes--; + modelNode.fire("error", e); } } } -/** @private */ -const ParserV9 = { - version: 9, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract$1(elements); - const inflatedData = inflate$1(deflatedData); - load$1(viewer, options, inflatedData, sceneModel); +function parse(plugin, modelNode, data, options) { + try { + const binData = ensureBinary(data); + if (isBinary(binData)) { + parseBinary(plugin, binData, modelNode, options); + } else { + parseASCII(plugin, ensureString(data), modelNode, options); + } + } catch (e) { + modelNode.fire("error", e); } -}; - -/* - Parser for .XKT Format V10 -*/ - -let pako = window.pako || p; -if (!pako.inflate) { // See https://github.com/nodeca/pako/issues/97 - pako = pako.default; } -const tempVec4a$2 = math.vec4(); -const tempVec4b$2 = math.vec4(); - -function extract(elements) { - - return { - metadata: elements[0], - textureData: elements[1], - eachTextureDataPortion: elements[2], - eachTextureDimensions: elements[3], - positions: elements[4], - normals: elements[5], - colors: elements[6], - uvs: elements[7], - indices: elements[8], - edgeIndices: elements[9], - eachTextureSetTextures: elements[10], - matrices: elements[11], - reusedGeometriesDecodeMatrix: elements[12], - eachGeometryPrimitiveType: elements[13], - eachGeometryPositionsPortion: elements[14], - eachGeometryNormalsPortion: elements[15], - eachGeometryColorsPortion: elements[16], - eachGeometryUVsPortion: elements[17], - eachGeometryIndicesPortion: elements[18], - eachGeometryEdgeIndicesPortion: elements[19], - eachMeshGeometriesPortion: elements[20], - eachMeshMatricesPortion: elements[21], - eachMeshTextureSet: elements[22], - eachMeshMaterialAttributes: elements[23], - eachEntityId: elements[24], - eachEntityMeshesPortion: elements[25], - eachTileAABB: elements[26], - eachTileEntitiesPortion: elements[27] - }; +function isBinary(data) { + const reader = new DataView(data); + const numFaces = reader.getUint32(80, true); + const faceSize = (32 / 8 * 3) + ((32 / 8 * 3) * 3) + (16 / 8); + const numExpectedBytes = 80 + (32 / 8) + (numFaces * faceSize); + if (numExpectedBytes === reader.byteLength) { + return true; + } + const solid = [115, 111, 108, 105, 100]; + for (var i = 0; i < 5; i++) { + if (solid[i] !== reader.getUint8(i, false)) { + return true; + } + } + return false; } -function inflate(deflatedData) { - - function inflate(array, options) { - return (array.length === 0) ? [] : pako.inflate(array, options).buffer; +function parseBinary(plugin, data, modelNode, options) { + const reader = new DataView(data); + const faces = reader.getUint32(80, true); + let r; + let g; + let b; + let hasColors = false; + let colors; + let defaultR; + let defaultG; + let defaultB; + let lastR = null; + let lastG = null; + let lastB = null; + let newMesh = false; + for (let index = 0; index < 80 - 10; index++) { + if ((reader.getUint32(index, false) === 0x434F4C4F /*COLO*/) && + (reader.getUint8(index + 4) === 0x52 /*'R'*/) && + (reader.getUint8(index + 5) === 0x3D /*'='*/)) { + hasColors = true; + colors = []; + defaultR = reader.getUint8(index + 6) / 255; + defaultG = reader.getUint8(index + 7) / 255; + defaultB = reader.getUint8(index + 8) / 255; + reader.getUint8(index + 9) / 255; + } + } + const material = new MetallicMaterial(modelNode, { // Share material with all meshes + roughness: 0.5 + }); + // var material = new PhongMaterial(modelNode, { // Share material with all meshes + // diffuse: [0.4, 0.4, 0.4], + // reflectivity: 1, + // specular: [0.5, 0.5, 1.0] + // }); + let dataOffset = 84; + let faceLength = 12 * 4 + 2; + let positions = []; + let normals = []; + let splitMeshes = options.splitMeshes; + for (let face = 0; face < faces; face++) { + let start = dataOffset + face * faceLength; + let normalX = reader.getFloat32(start, true); + let normalY = reader.getFloat32(start + 4, true); + let normalZ = reader.getFloat32(start + 8, true); + if (hasColors) { + let packedColor = reader.getUint16(start + 48, true); + if ((packedColor & 0x8000) === 0) { + r = (packedColor & 0x1F) / 31; + g = ((packedColor >> 5) & 0x1F) / 31; + b = ((packedColor >> 10) & 0x1F) / 31; + } else { + r = defaultR; + g = defaultG; + b = defaultB; + } + if (splitMeshes && r !== lastR || g !== lastG || b !== lastB) { + if (lastR !== null) { + newMesh = true; + } + lastR = r; + lastG = g; + lastB = b; + } + } + for (let i = 1; i <= 3; i++) { + let vertexstart = start + i * 12; + positions.push(reader.getFloat32(vertexstart, true)); + positions.push(reader.getFloat32(vertexstart + 4, true)); + positions.push(reader.getFloat32(vertexstart + 8, true)); + normals.push(normalX, normalY, normalZ); + if (hasColors) { + colors.push(r, g, b, 1); // TODO: handle alpha + } + } + if (splitMeshes && newMesh) { + addMesh(modelNode, positions, normals, colors, material, options); + positions = []; + normals = []; + colors = colors ? [] : null; + newMesh = false; + } + } + if (positions.length > 0) { + addMesh(modelNode, positions, normals, colors, material, options); } - - return { - metadata: JSON.parse(pako.inflate(deflatedData.metadata, {to: 'string'})), - textureData: new Uint8Array(inflate(deflatedData.textureData)), - eachTextureDataPortion: new Uint32Array(inflate(deflatedData.eachTextureDataPortion)), - eachTextureDimensions: new Uint16Array(inflate(deflatedData.eachTextureDimensions)), - positions: new Uint16Array(inflate(deflatedData.positions)), - normals: new Int8Array(inflate(deflatedData.normals)), - colors: new Uint8Array(inflate(deflatedData.colors)), - uvs: new Float32Array(inflate(deflatedData.uvs)), - indices: new Uint32Array(inflate(deflatedData.indices)), - edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), - eachTextureSetTextures: new Int32Array(inflate(deflatedData.eachTextureSetTextures)), - matrices: new Float32Array(inflate(deflatedData.matrices)), - reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), - eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), - eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), - eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), - eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), - eachGeometryUVsPortion: new Uint32Array(inflate(deflatedData.eachGeometryUVsPortion)), - eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), - eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), - eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), - eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), - eachMeshTextureSet: new Int32Array(inflate(deflatedData.eachMeshTextureSet)), // Can be -1 - eachMeshMaterialAttributes: new Uint8Array(inflate(deflatedData.eachMeshMaterialAttributes)), - eachEntityId: JSON.parse(pako.inflate(deflatedData.eachEntityId, {to: 'string'})), - eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), - eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), - eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), - }; } -const decompressColor = (function () { - const floatColor = new Float32Array(3); - return function (intColor) { - floatColor[0] = intColor[0] / 255.0; - floatColor[1] = intColor[1] / 255.0; - floatColor[2] = intColor[2] / 255.0; - return floatColor; - }; -})(); +function parseASCII(plugin, data, modelNode, options) { + const faceRegex = /facet([\s\S]*?)endfacet/g; + let faceCounter = 0; + const floatRegex = /[\s]+([+-]?(?:\d+.\d+|\d+.|\d+|.\d+)(?:[eE][+-]?\d+)?)/.source; + const vertexRegex = new RegExp('vertex' + floatRegex + floatRegex + floatRegex, 'g'); + const normalRegex = new RegExp('normal' + floatRegex + floatRegex + floatRegex, 'g'); + const positions = []; + const normals = []; + const colors = null; + let normalx; + let normaly; + let normalz; + let result; + let verticesPerFace; + let normalsPerFace; + let text; + while ((result = faceRegex.exec(data)) !== null) { + verticesPerFace = 0; + normalsPerFace = 0; + text = result[0]; + while ((result = normalRegex.exec(text)) !== null) { + normalx = parseFloat(result[1]); + normaly = parseFloat(result[2]); + normalz = parseFloat(result[3]); + normalsPerFace++; + } + while ((result = vertexRegex.exec(text)) !== null) { + positions.push(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])); + normals.push(normalx, normaly, normalz); + verticesPerFace++; + } + if (normalsPerFace !== 1) { + plugin.error("Error in normal of face " + faceCounter); + } + if (verticesPerFace !== 3) { + plugin.error("Error in positions of face " + faceCounter); + } + faceCounter++; + } + const material = new MetallicMaterial(modelNode, { + roughness: 0.5 + }); + // var material = new PhongMaterial(modelNode, { + // diffuse: [0.4, 0.4, 0.4], + // reflectivity: 1, + // specular: [0.5, 0.5, 1.0] + // }); + addMesh(modelNode, positions, normals, colors, material, options); +} -((function () { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - return function (imagedata) { - canvas.width = imagedata.width; - canvas.height = imagedata.height; - context.putImageData(imagedata, 0, 0); - return canvas.toDataURL(); - }; -}))(); +function addMesh(modelNode, positions, normals, colors, material, options) { -function load(viewer, options, inflatedData, sceneModel) { + const indices = new Int32Array(positions.length / 3); + for (let ni = 0, len = indices.length; ni < len; ni++) { + indices[ni] = ni; + } - const metadata = inflatedData.metadata; - const textureData = inflatedData.textureData; - const eachTextureDataPortion = inflatedData.eachTextureDataPortion; - inflatedData.eachTextureDimensions; - const positions = inflatedData.positions; - const normals = inflatedData.normals; - const colors = inflatedData.colors; - const uvs = inflatedData.uvs; - const indices = inflatedData.indices; - const edgeIndices = inflatedData.edgeIndices; - const eachTextureSetTextures = inflatedData.eachTextureSetTextures; - const matrices = inflatedData.matrices; - const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; - const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; - const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; - const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; - const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; - const eachGeometryUVsPortion = inflatedData.eachGeometryUVsPortion; - const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; - const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; - const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; - const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; - const eachMeshTextureSet = inflatedData.eachMeshTextureSet; - const eachMeshMaterialAttributes = inflatedData.eachMeshMaterialAttributes; - const eachEntityId = inflatedData.eachEntityId; - const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; - const eachTileAABB = inflatedData.eachTileAABB; - const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + normals = normals && normals.length > 0 ? normals : null; + colors = colors && colors.length > 0 ? colors : null; - const numTextures = eachTextureDataPortion.length; - const numTextureSets = eachTextureSetTextures.length / 5; - const numGeometries = eachGeometryPositionsPortion.length; - const numMeshes = eachMeshGeometriesPortion.length; - const numEntities = eachEntityMeshesPortion.length; - const numTiles = eachTileEntitiesPortion.length; + if (options.smoothNormals) { + math.faceToVertexNormals(positions, normals, options); + } - let nextMeshId = 0; + const origin = tempVec3a$3; - // Create metamodel, unless already loaded from external JSON file by XKTLoaderPlugin + worldToRTCPositions(positions, positions, origin); - const metaModelId = sceneModel.id; + const geometry = new ReadableGeometry(modelNode, { + primitive: "triangles", + positions: positions, + normals: normals, + colors: colors, + indices: indices + }); - if (!viewer.metaScene.metaModels[metaModelId]) { + const mesh = new Mesh(modelNode, { + origin: (origin[0] !== 0 || origin[1] !== 0 || origin[2] !== 0) ? origin : null, + geometry: geometry, + material: material, + edges: options.edges + }); - viewer.metaScene.createMetaModel(metaModelId, metadata, { - includeTypes: options.includeTypes, - excludeTypes: options.excludeTypes, - globalizeObjectIds: options.globalizeObjectIds - }); + modelNode.addChild(mesh); +} - sceneModel.once("destroyed", () => { - viewer.metaScene.destroyMetaModel(metaModelId); - }); +function ensureString(buffer) { + if (typeof buffer !== 'string') { + return decodeText(new Uint8Array(buffer)); } + return buffer; +} - // Create textures - - for (let textureIndex = 0; textureIndex < numTextures; textureIndex++) { - const atLastTexture = (textureIndex === (numTextures - 1)); - const textureDataPortionStart = eachTextureDataPortion[textureIndex]; - const textureDataPortionEnd = atLastTexture ? textureData.length : (eachTextureDataPortion[textureIndex + 1]); - const textureDataPortionSize = textureDataPortionEnd - textureDataPortionStart; - const textureDataPortionExists = (textureDataPortionSize > 0); - if (textureDataPortionExists) { - - const imageDataSubarray = new Uint8Array(textureData.subarray(textureDataPortionStart, textureDataPortionEnd)); - const arrayBuffer = imageDataSubarray.buffer; - - sceneModel.createTexture({ - id: `texture-${textureIndex}`, - buffers: [arrayBuffer] - }); +function ensureBinary(buffer) { + if (typeof buffer === 'string') { + const arrayBuffer = new Uint8Array(buffer.length); + for (let i = 0; i < buffer.length; i++) { + arrayBuffer[i] = buffer.charCodeAt(i) & 0xff; // implicitly assumes little-endian } + return arrayBuffer.buffer || arrayBuffer; + } else { + return buffer; } +} - // Create texture sets - - for (let textureSetIndex = 0; textureSetIndex < numTextureSets; textureSetIndex++) { - const eachTextureSetTexturesIndex = textureSetIndex * 5; - const textureSetId = `textureSet-${textureSetIndex}`; - const colorTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 0]; - const metallicRoughnessTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 1]; - const normalsTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 2]; - const emissiveTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 3]; - const occlusionTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 4]; - sceneModel.createTextureSet({ - id: textureSetId, - colorTextureId: colorTextureIndex >= 0 ? `texture-${colorTextureIndex}` : null, - normalsTextureId: normalsTextureIndex >= 0 ? `texture-${normalsTextureIndex}` : null, - metallicRoughnessTextureId: metallicRoughnessTextureIndex >= 0 ? `texture-${metallicRoughnessTextureIndex}` : null, - emissiveTextureId: emissiveTextureIndex >= 0 ? `texture-${emissiveTextureIndex}` : null, - occlusionTextureId: occlusionTextureIndex >= 0 ? `texture-${occlusionTextureIndex}` : null - }); +function decodeText(array) { + if (typeof TextDecoder !== 'undefined') { + return new TextDecoder().decode(array); } - - // Count instances of each geometry - - const geometryReuseCounts = new Uint32Array(numGeometries); - - for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - if (geometryReuseCounts[geometryIndex] !== undefined) { - geometryReuseCounts[geometryIndex]++; - } else { - geometryReuseCounts[geometryIndex] = 1; - } + let s = ''; + for (let i = 0, il = array.length; i < il; i++) { + s += String.fromCharCode(array[i]); // Implicitly assumes little-endian. } + return decodeURIComponent(escape(s)); +} - // Iterate over tiles - - const tileCenter = math.vec3(); - const rtcAABB = math.AABB3(); - - const geometryArraysCache = {}; - - for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { +/** + * {@link Viewer} plugin that loads models from STL files. + * + * ## Overview + * + * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. + * * Creates an {@link Entity} for each object within the model, which will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. + * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. + * * Supports both binary and ASCII formats. + * * Supports double-precision vertex positions. + * * Supports custom data source configuration. + * + * ## Smoothing STL Normals + * + * STL models are normally flat-shaded, however providing a ````smoothNormals```` parameter when loading gives a smooth + * appearance. Triangles in STL are disjoint, where each triangle has its own separate vertex positions, normals and + * (optionally) colors. This means that you can have gaps between triangles in an STL model. Normals for each triangle + * are perpendicular to the triangle's surface, which gives the model a faceted appearance by default. + * + * The ```smoothNormals``` parameter causes the plugin to recalculate the STL normals, so that each normal's direction is + * the average of the orientations of the triangles adjacent to its vertex. When smoothing, each vertex normal is set to + * the average of the orientations of all other triangles that have a vertex at the same position, excluding those triangles + * whose direction deviates from the direction of the vertice's triangle by a threshold given in + * the ````smoothNormalsAngleThreshold```` loading parameter. This makes smoothing robust for hard edges. + * + * ## Creating Entities for Objects + * + * An STL model is normally a single mesh, however providing a ````splitMeshes```` parameter when loading + * will create a separate object {@link Entity} for each group of faces that share the same vertex colors. This option + * only works with binary STL files. + * + * See the {@link STLLoaderPlugin#load} method for more info on loading options. + * + * ## Usage + * + * In the example below, we'll use an STLLoaderPlugin to load an STL model of a spur gear. When the model has loaded, + * we'll use the {@link CameraFlightAnimation} to fly the {@link Camera} to look at boundary of the model. We'll + * then get the model's {@link Entity} from the {@link Scene} and highlight the whole model. + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_STL_SpurGear)] + * + * ````javascript + * // Create a xeokit Viewer + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * // Add an STLLoaderPlugin to the Viewer + * var plugin = new STLLoaderPlugin(viewer); + * + * // Load the STL model + * var model = plugin.load({ // Model is an Entity + * id: "myModel", + * src: "./models/stl/binary/spurGear.stl", + * scale: [0.1, 0.1, 0.1], + * rotate: [90, 0, 0], + * translate: [100,0,0], + * edges: true, + * smoothNormals: true, // Default + * smoothNormalsAngleThreshold: 20, // Default + * splitMeshes: true // Default + * }); + * + * // When the model has loaded, fit it to view + * model.on("loaded", function() { // Model is an Entity + * viewer.cameraFlight.flyTo(model); + * }); + * + * // Find the model Entity by ID + * model = viewer.scene.models["myModel"]; + * + * // Update properties of the model Entity + * model.highlight = [1,0,0]; + * + * // Destroy the model Entity + * model.destroy(); + * ```` + * + * ## Loading from a Pre-Loaded STL File + * + * If we already have our STL file in memory (perhaps pre-loaded, or even generated in-client), then we can just pass that + * file data straight into the {@link STLLoaderPlugin#load} method. In the example below, to show how it's done, we'll pre-load + * our STL file data, then pass it straight into that method. + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_STL_dataAsParam)] + * + * ````javascript + * loadSTL("./models/stl/binary/spurGear.stl", (stlData) =>{ + * + * const model = stlLoader.load({ + * id: "myModel", + * stl: stlData, + * smoothNormals: true + * }); + * + * model.on("loaded", () => { + * viewer.cameraFlight.jumpTo(model); + * viewer.scene.on("tick", () => { + * viewer.camera.orbitYaw(0.4); + * }) + * }); + * }) + * + * function loadSTL(src, ok, error) { + * const request = new XMLHttpRequest(); + * request.overrideMimeType("application/json"); + * request.open('GET', src, true); + * request.responseType = 'arraybuffer'; + * request.onreadystatechange = function () { + * if (request.readyState === 4) { + * if (request.status === 200) { + * ok(request.response); + * } else if (error) { + * error(request.statusText); + * } + * } + * }; + * request.send(null); + * } + *```` + * + * ## Configuring a Custom Data Source + * + * In the example below, we'll create the STLLoaderPlugin again, this time configuring it with a + * custom data source object, through which it can load STL files. For this example, our data source just loads + * them via HTTP, for simplicity. Once we've created the STLLoaderPlugin, we'll load our STL file as before. + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_STL_dataSource)] + * + * ````javascript + * // Our custom STL data access strategy - implementation happens to be the same as STLDefaultDataSource + * + * class MyDataSource { + * getSTL(src, ok, error) { + * const request = new XMLHttpRequest(); + * request.overrideMimeType("application/json"); + * request.open('GET', src, true); + * request.responseType = 'arraybuffer'; + * request.onreadystatechange = function () { + * if (request.readyState === 4) { + * if (request.status === 200) { + * ok(request.response); + * } else { + * error(request.statusText); + * } + * } + * }; + * request.send(null); + * } + * } + * + * const stlLoader = new STLLoaderPlugin(viewer, { + * dataSource: new MyDataSource() + * }); + * + * // Load the STL model as before + * var model = plugin.load({ + * id: "myModel", + * src: "./models/stl/binary/spurGear.stl", + * scale: [0.1, 0.1, 0.1], + * rotate: [90, 0, 0], + * translate: [100,0,0], + * edges: true, + * smoothNormals: true, // Default + * smoothNormalsAngleThreshold: 20, // Default + * splitMeshes: true // Default + * }); + * + * //... + *```` + * + * @class STLLoaderPlugin + */ +class STLLoaderPlugin extends Plugin { - const lastTileIndex = (numTiles - 1); + /** + * @constructor + * + * @param {Viewer} viewer The Viewer. + * @param {Object} [cfg] Plugin configuration. + * @param {String} [cfg.id="STLLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Object} [cfg.dataSource] A custom data source through which the STLLoaderPlugin can load STL files. Defaults to an instance of {@link STLDefaultDataSource}, which loads over HTTP. + */ + constructor(viewer, cfg = {}) { - const atLastTile = (tileIndex === lastTileIndex); + super("STLLoader", viewer, cfg); - const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; - const lastTileEntityIndex = atLastTile ? (numEntities - 1) : (eachTileEntitiesPortion[tileIndex + 1] - 1); + /** + * @private + */ + this._sceneGraphLoader = new STLSceneGraphLoader(); - const tileAABBIndex = tileIndex * 6; - const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + this.dataSource = cfg.dataSource; + } - math.getAABB3Center(tileAABB, tileCenter); + /** + * Sets a custom data source through which the STLLoaderPlugin can load STL files. + * + * Default value is {@link STLDefaultDataSource}, which loads via an XMLHttpRequest. + * + * @type {Object} + */ + set dataSource(value) { + this._dataSource = value || new STLDefaultDataSource(); + } - rtcAABB[0] = tileAABB[0] - tileCenter[0]; - rtcAABB[1] = tileAABB[1] - tileCenter[1]; - rtcAABB[2] = tileAABB[2] - tileCenter[2]; - rtcAABB[3] = tileAABB[3] - tileCenter[0]; - rtcAABB[4] = tileAABB[4] - tileCenter[1]; - rtcAABB[5] = tileAABB[5] - tileCenter[2]; + /** + * Gets the custom data source through which the STLLoaderPlugin can load STL files. + * + * Default value is {@link STLDefaultDataSource}, which loads via an XMLHttpRequest. + * + * @type {Object} + */ + get dataSource() { + return this._dataSource; + } - const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + /** + * Loads an STL model from a file into this STLLoaderPlugin's {@link Viewer}. + * + * @param {*} params Loading parameters. + * @param {String} params.id ID to assign to the model's root {@link Entity}, unique among all components in the Viewer's {@link Scene}. + * @param {String} [params.src] Path to an STL file. Overrides the ````stl```` parameter. + * @param {String} [params.stl] Contents of an STL file, either binary of ASCII. Overridden by the ````src```` parameter. + * @param {Boolean} [params.edges=false] Whether or not to renders the model with edges emphasized. + * @param {Number[]} [params.origin=[0,0,0]] The model's World-space double-precision 3D origin. Use this to position the model within xeokit's World coordinate system, using double-precision coordinates. + * @param {Number[]} [params.position=[0,0,0]] The model single-precision 3D position, relative to the ````origin```` parameter. + * @param {Number[]} [params.scale=[1,1,1]] The model's scale. + * @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, given as Euler angles in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. Relative to ````origin````. + * @param {Boolean} [params.backfaces=false] When true, allows visible backfaces, wherever specified in the STL. When false, ignores backfaces. + * @param {Boolean} [params.smoothNormals=true] When true, automatically converts face-oriented normals to vertex normals for a smooth appearance. + * @param {Number} [params.smoothNormalsAngleThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. + * @param {Number} [params.edgeThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. + * @param {Boolean} [params.splitMeshes=true] When true, creates a separate {@link Mesh} for each group of faces that share the same vertex colors. Only works with binary STL. + * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} + */ + load(params) { - const geometryCreatedInTile = {}; + if (params.id && this.viewer.scene.components[params.id]) { + this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); + delete params.id; + } - // Iterate over each tile's entities + const modelNode = new Node$1(this.viewer.scene, utils.apply(params, { + isModel: true + })); - for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex <= lastTileEntityIndex; tileEntityIndex++) { + const src = params.src; + const stl = params.stl; - const xktEntityId = eachEntityId[tileEntityIndex]; + if (!src && !stl) { + this.error("load() param expected: either 'src' or 'stl'"); + return modelNode; + } - const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + if (src) { + this._sceneGraphLoader.load(this, modelNode, src, params); + } else { + this._sceneGraphLoader.parse(this, modelNode, stl, params); + } - const finalTileEntityIndex = (numEntities - 1); - const atLastTileEntity = (tileEntityIndex === finalTileEntityIndex); - const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; - const lastMeshIndex = atLastTileEntity ? (eachMeshGeometriesPortion.length - 1) : (eachEntityMeshesPortion[tileEntityIndex + 1] - 1); + return modelNode; + } +} - const meshIds = []; +/** + * @desc Information about an ````IfcBuildingStorey````. + * + * These are provided by a {@link StoreyViewsPlugin}. + */ +class Storey { - const metaObject = viewer.metaScene.metaObjects[entityId]; - const entityDefaults = {}; - const meshDefaults = {}; + /** + * @private + */ + constructor(plugin, aabb, modelId, storeyId, numObjects) { - if (metaObject) { + /** + * The {@link StoreyViewsPlugin} this Storey belongs to. + * + * @property plugin + * @type {StoreyViewsPlugin} + */ + this.plugin = plugin; - // Mask loading of object types - - if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { - continue; - } - - if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { - continue; - } - - // Get initial property values for object types - - const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; - - if (props) { - if (props.visible === false) { - entityDefaults.visible = false; - } - if (props.pickable === false) { - entityDefaults.pickable = false; - } - if (props.colorize) { - meshDefaults.color = props.colorize; - } - if (props.opacity !== undefined && props.opacity !== null) { - meshDefaults.opacity = props.opacity; - } - if (props.metallic !== undefined && props.metallic !== null) { - meshDefaults.metallic = props.metallic; - } - if (props.roughness !== undefined && props.roughness !== null) { - meshDefaults.roughness = props.roughness; - } - } - - } else { - if (options.excludeUnclassifiedObjects) { - continue; - } - } - - // Iterate each entity's meshes - - for (let meshIndex = firstMeshIndex; meshIndex <= lastMeshIndex; meshIndex++) { - - const geometryIndex = eachMeshGeometriesPortion[meshIndex]; - const geometryReuseCount = geometryReuseCounts[geometryIndex]; - const isReusedGeometry = (geometryReuseCount > 1); - - const atLastGeometry = (geometryIndex === (numGeometries - 1)); - - const textureSetIndex = eachMeshTextureSet[meshIndex]; - - const textureSetId = (textureSetIndex >= 0) ? `textureSet-${textureSetIndex}` : null; - - const meshColor = decompressColor(eachMeshMaterialAttributes.subarray((meshIndex * 6), (meshIndex * 6) + 3)); - const meshOpacity = eachMeshMaterialAttributes[(meshIndex * 6) + 3] / 255.0; - const meshMetallic = eachMeshMaterialAttributes[(meshIndex * 6) + 4] / 255.0; - const meshRoughness = eachMeshMaterialAttributes[(meshIndex * 6) + 5] / 255.0; - - const meshId = nextMeshId++; - - if (isReusedGeometry) { - - // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry - - const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; - const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); - - const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel - - let geometryArrays = geometryArraysCache[geometryId]; - - if (!geometryArrays) { - geometryArrays = { - batchThisMesh: (!options.reuseGeometries) - }; - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; - let geometryValid = false; - switch (primitiveType) { - case 0: - geometryArrays.primitiveName = "solid"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - case 1: - geometryArrays.primitiveName = "surface"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - case 2: - geometryArrays.primitiveName = "points"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0); - break; - case 3: - geometryArrays.primitiveName = "lines"; - geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); - break; - default: - continue; - } - - if (!geometryValid) { - geometryArrays = null; - } - - if (geometryArrays) { - if (geometryArrays.geometryPositions.length > 1000) ; - if (geometryArrays.batchThisMesh) { - geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length); - geometryArrays.transformedAndRecompressedPositions = new Uint16Array(geometryArrays.geometryPositions.length); - const geometryPositions = geometryArrays.geometryPositions; - const decompressedPositions = geometryArrays.decompressedPositions; - for (let i = 0, len = geometryPositions.length; i < len; i += 3) { - decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12]; - decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13]; - decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14]; - } - geometryArrays.geometryPositions = null; - geometryArraysCache[geometryId] = geometryArrays; - } - } - } - - if (geometryArrays) { - - if (geometryArrays.batchThisMesh) { - - const decompressedPositions = geometryArrays.decompressedPositions; - const transformedAndRecompressedPositions = geometryArrays.transformedAndRecompressedPositions; - - for (let i = 0, len = decompressedPositions.length; i < len; i += 3) { - tempVec4a$2[0] = decompressedPositions[i + 0]; - tempVec4a$2[1] = decompressedPositions[i + 1]; - tempVec4a$2[2] = decompressedPositions[i + 2]; - tempVec4a$2[3] = 1; - math.transformVec4(meshMatrix, tempVec4a$2, tempVec4b$2); - geometryCompressionUtils.compressPosition(tempVec4b$2, rtcAABB, tempVec4a$2); - transformedAndRecompressedPositions[i + 0] = tempVec4a$2[0]; - transformedAndRecompressedPositions[i + 1] = tempVec4a$2[1]; - transformedAndRecompressedPositions[i + 2] = tempVec4a$2[2]; - } - - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - textureSetId: textureSetId, - origin: tileCenter, - primitive: geometryArrays.primitiveName, - positionsCompressed: transformedAndRecompressedPositions, - normalsCompressed: geometryArrays.geometryNormals, - uv: geometryArrays.geometryUVs, - colorsCompressed: geometryArrays.geometryColors, - indices: geometryArrays.geometryIndices, - edgeIndices: geometryArrays.geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); - - meshIds.push(meshId); - - } else { - - if (!geometryCreatedInTile[geometryId]) { - - sceneModel.createGeometry({ - id: geometryId, - primitive: geometryArrays.primitiveName, - positionsCompressed: geometryArrays.geometryPositions, - normalsCompressed: geometryArrays.geometryNormals, - uv: geometryArrays.geometryUVs, - colorsCompressed: geometryArrays.geometryColors, - indices: geometryArrays.geometryIndices, - edgeIndices: geometryArrays.geometryEdgeIndices, - positionsDecodeMatrix: reusedGeometriesDecodeMatrix - }); - - geometryCreatedInTile[geometryId] = true; - } + /** + * ID of the IfcBuildingStorey. + * + * This matches IDs of the IfcBuildingStorey's {@link MetaObject} and {@link Entity}. + * + * @property storeyId + * @type {String} + */ + this.storeyId = storeyId; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - geometryId: geometryId, - textureSetId: textureSetId, - matrix: meshMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity, - origin: tileCenter - })); + /** + * ID of the model. + * + * This matches the ID of the {@link MetaModel} that contains the IfcBuildingStorey's {@link MetaObject}. + * + * @property modelId + * @type {String|Number} + */ + this.modelId = modelId; - meshIds.push(meshId); - } - } + /** + * Axis-aligned World-space boundary of the {@link Entity}s that represent the IfcBuildingStorey. + * + * The boundary is a six-element Float32Array containing the min/max extents of the + * axis-aligned boundary, ie. ````[xmin, ymin, zmin, xmax, ymax, zmax]```` + * + * @property aabb + * @type {Number[]} + */ + this.aabb = aabb.slice(); - } else { // Do not reuse geometry + /** Number of {@link Entity}s within the IfcBuildingStorey. + * + * @property numObjects + * @type {Number} + */ + this.numObjects = numObjects; + } +} - const primitiveType = eachGeometryPrimitiveType[geometryIndex]; +/** + * @desc Property states for {@link Entity}s in {@link Storey}s capture by a {@link StoreyViewsPlugin}. + * + * @type {{String:Object}} + */ +const IFCStoreyPlanObjectStates = { + IfcSlab: { + visible: true, + edges: false, + colorize: [1.0, 1.0, 1.0, 1.0] + }, + IfcWall: { + visible: true, + edges: false, + colorize: [0.1, 0.1, 0.1, 1.0] + }, + IfcWallStandardCase: { + visible: true, + edges: false, + colorize: [0.1, 0.1, 0.1, 1.0] + }, + IfcDoor: { + visible: true, + edges: false, + colorize: [0.5, 0.5, 0.5, 1.0] + }, + IfcWindow: { + visible: true, + edges: false, + colorize: [0.5, 0.5, 0.5, 1.0] + }, + IfcColumn: { + visible: true, + edges: false, + colorize: [0.5, 0.5, 0.5, 1.0] + }, + IfcCurtainWall: { + visible: true, + edges: false, + colorize: [0.5, 0.5, 0.5, 1.0] + }, + IfcStair: { + visible: true, + edges: false, + colorize: [0.7, 0.7, 0.7, 1.0] + }, + IfcStairFlight: { + visible: true, + edges: false, + colorize: [0.7, 0.7, 0.7, 1.0] + }, + IfcRamp: { + visible: true, + edges: false, + colorize: [0.7, 0.7, 0.7, 1.0] + }, + IfcFurniture: { + visible: true, + edges: false, + colorize: [0.7, 0.7, 0.7, 1.0] + }, + IfcFooting: { + visible: true, + edges: false, + colorize: [0.7, 0.7, 0.7, 1.0] + }, + IfcFloor: { + visible: true, + edges: false, + colorize: [1.0, 1.0, 1.0, 1.0] + }, + DEFAULT: { + visible: false + } +}; - let primitiveName; - let geometryPositions; - let geometryNormals; - let geometryUVs; - let geometryColors; - let geometryIndices; - let geometryEdgeIndices; - let geometryValid = false; +/** + * @desc A 2D plan view image of an ````IfcBuildingStorey````. + * + * These are created by a {@link StoreyViewsPlugin}. + */ +class StoreyMap { - switch (primitiveType) { - case 0: - primitiveName = "solid"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - case 1: - primitiveName = "surface"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); - geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - case 2: - primitiveName = "points"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0); - break; - case 3: - primitiveName = "lines"; - geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); - geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); - geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); - break; - default: - continue; - } + /** + * @private + */ + constructor(storeyId, imageData, format, width, height, padding) { - if (geometryValid) { + /** + * ID of the IfcBuildingStorey. + * + * This matches IDs of the IfcBuildingStorey's {@link MetaObject} and {@link Entity}. + * + * @property storeyId + * @type {String} + */ + this.storeyId = storeyId; - sceneModel.createMesh(utils.apply(meshDefaults, { - id: meshId, - textureSetId: textureSetId, - origin: tileCenter, - primitive: primitiveName, - positionsCompressed: geometryPositions, - normalsCompressed: geometryNormals, - uv: geometryUVs && geometryUVs.length > 0 ? geometryUVs : null, - colorsCompressed: geometryColors, - indices: geometryIndices, - edgeIndices: geometryEdgeIndices, - positionsDecodeMatrix: tileDecodeMatrix, - color: meshColor, - metallic: meshMetallic, - roughness: meshRoughness, - opacity: meshOpacity - })); + /** + * Base64-encoded plan view image. + * + * @property imageData + * @type {String} + */ + this.imageData = imageData; - meshIds.push(meshId); - } - } - } + /** + * The image format - "png" or "jpeg". + * + * @property format + * @type {String} + */ + this.format = format; - if (meshIds.length > 0) { + /** + * Width of the image, in pixels. + * + * @property width + * @type {Number} + */ + this.width = width; - sceneModel.createEntity(utils.apply(entityDefaults, { - id: entityId, - isObject: true, - meshIds: meshIds - })); - } - } + /** + * Height of the image, in pixels. + * + * @property height + * @type {Number} + */ + this.height = height; } } -/** @private */ -const ParserV10 = { - version: 10, - parse: function (viewer, options, elements, sceneModel) { - const deflatedData = extract(elements); - const inflatedData = inflate(deflatedData); - load(viewer, options, inflatedData, sceneModel); - } -}; +const tempVec3a$2 = math.vec3(); +const tempMat4 = math.mat4(); -const parsers = {}; +const EMPTY_IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="; -parsers[ParserV1.version] = ParserV1; -parsers[ParserV2.version] = ParserV2; -parsers[ParserV3.version] = ParserV3; -parsers[ParserV4.version] = ParserV4; -parsers[ParserV5.version] = ParserV5; -parsers[ParserV6.version] = ParserV6; -parsers[ParserV7.version] = ParserV7; -parsers[ParserV8.version] = ParserV8; -parsers[ParserV9.version] = ParserV9; -parsers[ParserV10.version] = ParserV10; /** - * {@link Viewer} plugin that loads models from xeokit's optimized *````.XKT````* format. + * @desc A {@link Viewer} plugin that provides methods for visualizing IfcBuildingStoreys. * - * + * * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_OTCConferenceCenter)] + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_recipe2)] * * ## Overview * - * * XKTLoaderPlugin is the most efficient way to load high-detail models into xeokit. - * * An *````.XKT````* file is a single BLOB containing a model, compressed using geometry quantization - * and [pako](https://nodeca.github.io/pako/). - * * Supports double-precision coordinates. - * * Supports compressed textures. - * * Set the position, scale and rotation of each model as you load it. - * * Filter which IFC types get loaded. - * * Configure initial default appearances for IFC types. - * * Set a custom data source for *````.XKT````* and IFC metadata files. - * * Option to load multiple copies of the same model, without object ID clashes. - * - * ## Creating *````.XKT````* Files and Metadata - * - * We have several sways to convert your files into XKT. See these tutorials for more info: - * - * * [Converting Models to XKT with convert2xkt](https://www.notion.so/xeokit/Converting-Models-to-XKT-with-convert2xkt-fa567843313f4db8a7d6535e76da9380) - how to convert various file formats (glTF, IFC, CityJSON, LAS/LAZ...) to XKT using our nodejs-based converter. - * * [Converting IFC Models to XKT using 3rd-Party Open Source Tools](https://www.notion.so/xeokit/Converting-IFC-Models-to-XKT-using-3rd-Party-Open-Source-Tools-c373e48bc4094ff5b6e5c5700ff580ee) - how to convert IFC files to XKT using 3rd-party open source CLI tools. - * - * ## Scene representation - * - * When loading a model, XKTLoaderPlugin creates an {@link Entity} that represents the model, which - * will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} - * in {@link Scene#models}. The XKTLoaderPlugin also creates an {@link Entity} for each object within the - * model. Those Entities will have {@link Entity#isObject} set ````true```` and will be registered - * by {@link Entity#id} in {@link Scene#objects}. + * StoreyViewsPlugin provides a flexible set of methods for visualizing building storeys in 3D and 2D. * - * ## Metadata + * Use the first two methods to set up 3D views of storeys: * - * Since XKT V8, model metadata is included in the XKT file. If the XKT file has metadata, then loading it creates - * model metadata components within the Viewer, namely a {@link MetaModel} corresponding to the model {@link Entity}, - * and a {@link MetaObject} for each object {@link Entity}. + * * [showStoreyObjects](#instance-method-showStoreyObjects) - shows the {@link Entity}s within a storey, and + * * [gotoStoreyCamera](#instance-method-gotoStoreyCamera) - positions the {@link Camera} for a plan view of the Entitys within a storey. + *

    * - * Each {@link MetaObject} has a {@link MetaObject#type}, which indicates the classification of its corresponding - * {@link Entity}. When loading metadata, we can also configure XKTLoaderPlugin with a custom lookup table of initial - * values to set on the properties of each type of {@link Entity}. By default, XKTLoaderPlugin uses its own map of - * default colors and visibilities for IFC element types. + * Use the second two methods to create 2D plan view mini-map images: * - * For XKT versions prior to V8, we provided the metadata to XKTLoaderPlugin as an accompanying JSON file to load. We can - * still do that for all XKT versions, and for XKT V8+ it will override any metadata provided within the XKT file. + * * [createStoreyMap](#instance-method-createStoreyMap) - creates a 2D plan view image of a storey, and + * * [pickStoreyMap](#instance-method-pickStoreyMap) - picks the {@link Entity} at the given 2D pixel coordinates within a plan view image. * * ## Usage * - * In the example below we'll load the Schependomlaan model from a [.XKT file](https://github.com/xeokit/xeokit-sdk/tree/master/examples/models/xkt/schependomlaan). - * - * This will create a bunch of {@link Entity}s that represents the model and its objects, along with a {@link MetaModel} and {@link MetaObject}s - * that hold their metadata. - * - * Since this model contains IFC types, the XKTLoaderPlugin will set the initial appearance of each object - * {@link Entity} according to its IFC type in {@link XKTLoaderPlugin#objectDefaults}. - * - * Read more about this example in the user guide on [Viewing BIM Models Offline](https://www.notion.so/xeokit/Viewing-an-IFC-Model-with-xeokit-c373e48bc4094ff5b6e5c5700ff580ee). + * Let's start by creating a {@link Viewer} with a StoreyViewsPlugin and an {@link XKTLoaderPlugin}. * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_metadata_Schependomlaan)] + * Then we'll load a BIM building model from an ```.xkt``` file. * * ````javascript - * import {Viewer, XKTLoaderPlugin} from "xeokit-sdk.es.js"; + * import {Viewer, XKTLoaderPlugin, StoreyViewsPlugin} from "xeokit-sdk.es.js"; * - * //------------------------------------------------------------------------------------------------------------------ - * // 1. Create a Viewer, - * // 2. Arrange the camera - * //------------------------------------------------------------------------------------------------------------------ + * // Create a Viewer, arrange the camera * - * // 1 * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); + * canvasId: "myCanvas", + * transparent: true + * }); * - * // 2 * viewer.camera.eye = [-2.56, 8.38, 8.27]; * viewer.camera.look = [13.44, 3.31, -14.83]; * viewer.camera.up = [0.10, 0.98, -0.14]; * - * //------------------------------------------------------------------------------------------------------------------ - * // 1. Create a XKTLoaderPlugin, - * // 2. Load a building model and JSON IFC metadata - * //------------------------------------------------------------------------------------------------------------------ + * // Add an XKTLoaderPlugin * - * // 1 * const xktLoader = new XKTLoaderPlugin(viewer); * - * // 2 - * const model = xktLoader.load({ // Returns an Entity that represents the model - * id: "myModel", - * src: "./models/xkt/Schependomlaan.xkt", - * edges: true - * }); - * - * model.on("loaded", () => { - * - * //-------------------------------------------------------------------------------------------------------------- - * // 1. Find metadata on the third storey - * // 2. Select all the objects in the building's third storey - * // 3. Fit the camera to all the objects on the third storey - * //-------------------------------------------------------------------------------------------------------------- - * - * // 1 - * const metaModel = viewer.metaScene.metaModels["myModel"]; // MetaModel with ID "myModel" - * const metaObject - * = viewer.metaScene.metaObjects["0u4wgLe6n0ABVaiXyikbkA"]; // MetaObject with ID "0u4wgLe6n0ABVaiXyikbkA" + * // Add a StoreyViewsPlugin * - * const name = metaObject.name; // "01 eerste verdieping" - * const type = metaObject.type; // "IfcBuildingStorey" - * const parent = metaObject.parent; // MetaObject with type "IfcBuilding" - * const children = metaObject.children; // Array of child MetaObjects - * const objectId = metaObject.id; // "0u4wgLe6n0ABVaiXyikbkA" - * const objectIds = viewer.metaScene.getObjectIDsInSubtree(objectId); // IDs of leaf sub-objects - * const aabb = viewer.scene.getAABB(objectIds); // Axis-aligned boundary of the leaf sub-objects + * const storeyViewsPlugin = new StoreyViewsPlugin(viewer); * - * // 2 - * viewer.scene.setObjectsSelected(objectIds, true); + * // Load a BIM model from .xkt format * - * // 3 - * viewer.cameraFlight.flyTo(aabb); + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true * }); - * - * // Find the model Entity by ID - * model = viewer.scene.models["myModel"]; - * - * // Destroy the model - * model.destroy(); * ```` * - * ## Loading XKT files containing textures - * - * XKTLoaderPlugin uses a {@link KTX2TextureTranscoder} to load textures in XKT files (XKT v10+). An XKTLoaderPlugin has its own - * default KTX2TextureTranscoder, configured to load the Basis Codec from the CDN. If we wish, we can override that with our own - * KTX2TextureTranscoder instance that's configured to load the Codec locally. - * - * In the example below, we'll create a {@link Viewer} and add an XKTLoaderPlugin - * configured with a KTX2TextureTranscoder that finds the Codec in our local file system. Then we'll use the - * XKTLoaderPlugin to load an XKT file that contains KTX2 textures, which the plugin will transcode using - * its KTX2TextureTranscoder. - * - * We'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. If we were happy with loading the - * Codec from our CDN (ie. our app will always have an Internet connection) then we could just leave out the - * KTX2TextureTranscoder altogether, and let the XKTLoaderPlugin use its internal default KTX2TextureTranscoder, which is configured to - * load the Codec from the CDN. We'll stick with loading our own Codec, in case we want to run our app without an Internet connection. - * - * + * ## Finding Storeys * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan)] + * Getting information on a storey in our model: * * ````javascript - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [-2.56, 8.38, 8.27]; - * viewer.camera.look = [13.44, 3.31, -14.83]; - * viewer.camera.up = [0.10, 0.98, -0.14]; - * - * const textureTranscoder = new KTX2TextureTranscoder({ - * viewer, - * transcoderPath: "./../dist/basis/" // <------ Path to Basis Universal transcoder - * }); - * - * const xktLoader = new XKTLoaderPlugin(viewer, { - * textureTranscoder // <<------------- Transcodes KTX2 textures in XKT files - * }); + * const storey = storeyViewsPlugin.storeys["2SWZMQPyD9pfT9q87pgXa1"]; // ID of the IfcBuildingStorey * - * const sceneModel = xktLoader.load({ - * id: "myModel", - * src: "./HousePlan.xkt" // <<------ XKT file with KTX2 textures - * }); + * const modelId = storey.modelId; // "myModel" + * const storeyId = storey.storeyId; // "2SWZMQPyD9pfT9q87pgXa1" + * const aabb = storey.aabb; // Axis-aligned 3D World-space boundary of the IfcBuildingStorey * ```` * - * ## Transforming - * - * We have the option to rotate, scale and translate each *````.XKT````* model as we load it. - * - * This lets us load multiple models, or even multiple copies of the same model, and position them apart from each other. - * - * In the example below, we'll scale our model to half its size, rotate it 90 degrees about its local X-axis, then - * translate it 100 units along its X axis. - * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Duplex_transform)] + * We can also get a "storeys" event every time the set of storeys changes, ie. every time a storey is created or destroyed: * * ````javascript - * xktLoader.load({ - * src: "./models/xkt/Duplex.ifc.xkt", - * rotation: [90,0,0], - * scale: [0.5, 0.5, 0.5], - * position: [100, 0, 0] + * storeyViewsPlugin.on("storeys", ()=> { + * const storey = storeyViewsPlugin.storeys["2SWZMQPyD9pfT9q87pgXa1"]; + * //... * }); * ```` * - * ## Including and excluding IFC types + * ## Showing Entitys within Storeys * - * We can also load only those objects that have the specified IFC types. + * Showing the {@link Entity}s within a storey: * - * In the example below, we'll load only the objects that represent walls. + * ````javascript + * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1"); + * ```` * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_includeTypes)] + * Showing **only** the Entitys in a storey, hiding all others: * * ````javascript - * const model2 = xktLoader.load({ - * id: "myModel2", - * src: "./models/xkt/OTCConferenceCenter.xkt", - * includeTypes: ["IfcWallStandardCase"] + * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { + * hideOthers: true * }); * ```` - * - * We can also load only those objects that **don't** have the specified IFC types. - * - * In the example below, we'll load only the objects that do not represent empty space. - * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_excludeTypes)] + * Showing only the storey Entitys, applying custom appearances configured on {@link StoreyViewsPlugin#objectStates}: * * ````javascript - * const model3 = xktLoader.load({ - * id: "myModel3", - * src: "./models/xkt/OTCConferenceCenter.xkt", - * excludeTypes: ["IfcSpace"] + * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { + * hideOthers: true, + * useObjectStates: true * }); * ```` * - * ## Configuring initial IFC object appearances - * - * We can specify the custom initial appearance of loaded objects according to their IFC types. + * * - * This is useful for things like: + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_showStoreyObjects)] * - * * setting the colors to our objects according to their IFC types, - * * automatically hiding ````IfcSpace```` objects, and - * * ensuring that ````IfcWindow```` objects are always transparent. - *
    - * In the example below, we'll load a model, while configuring ````IfcSpace```` elements to be always initially invisible, - * and ````IfcWindow```` types to be always translucent blue. + * When using this option, at some point later you'll probably want to restore all Entitys to their original visibilities and + * appearances. * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_objectDefaults)] + * To do that, save their visibility and appearance states in an {@link ObjectsMemento} beforehand, from + * which you can restore them later: * * ````javascript - * const myObjectDefaults = { + * const objectsMemento = new ObjectsMemento(); * - * IfcSpace: { - * visible: false - * }, - * IfcWindow: { - * colorize: [0.337255, 0.303922, 0.870588], // Blue - * opacity: 0.3 - * }, + * // Save all Entity visibility and appearance states * - * //... + * objectsMemento.saveObjects(viewer.scene); * - * DEFAULT: { - * colorize: [0.5, 0.5, 0.5] - * } - * }; + * // Show storey view Entitys, with custom appearances as configured for IFC types * - * const model4 = xktLoader.load({ - * id: "myModel4", - * src: "./models/xkt/Duplex.ifc.xkt", - * objectDefaults: myObjectDefaults // Use our custom initial default states for object Entities + * storeyViewsPlugin.showStoreyObjects("2SWZMQPyD9pfT9q87pgXa1", { + * useObjectStates: true // <<--------- Apply custom appearances * }); + * + * //... + * + * // Later, restore all Entitys to their saved visibility and appearance states + * objectsMemento.restoreObjects(viewer.scene); * ```` * - * When we don't customize the appearance of IFC types, as just above, then IfcSpace elements tend to obscure other - * elements, which can be confusing. + * ## Arranging the Camera for Storey Plan Views * - * It's often helpful to make IfcSpaces transparent and unpickable, like this: + * The {@link StoreyViewsPlugin#gotoStoreyCamera} method positions the {@link Camera} for a plan view of + * the {@link Entity}s within the given storey. * - * ````javascript - * const xktLoader = new XKTLoaderPlugin(viewer, { - * objectDefaults: { - * IfcSpace: { - * pickable: false, - * opacity: 0.2 - * } - * } - * }); - * ```` + * * - * Alternatively, we could just make IfcSpaces invisible, which also makes them unpickable: + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_gotoStoreyCamera)] + * + * Let's fly the {@link Camera} to a downward-looking orthographic view of the Entitys within our storey. * * ````javascript - * const xktLoader = new XKTLoaderPlugin(viewer, { - * objectDefaults: { - * IfcSpace: { - * visible: false - * } - * } + * storeyViewsPlugin.gotoStoreyCamera("2SWZMQPyD9pfT9q87pgXa1", { + * projection: "ortho", // Orthographic projection + * duration: 2.5, // 2.5 second transition + * done: () => { + * viewer.cameraControl.planView = true; // Disable rotation + * } * }); * ```` * - * ## Configuring a custom data source - * - * By default, XKTLoaderPlugin will load *````.XKT````* files and metadata JSON over HTTP. - * - * In the example below, we'll customize the way XKTLoaderPlugin loads the files by configuring it with our own data source - * object. For simplicity, our custom data source example also uses HTTP, using a couple of xeokit utility functions. + * Note that we also set {@link CameraControl#planView} ````true````, which prevents the CameraControl from rotating + * or orbiting. In orthographic mode, this effectively makes the {@link Viewer} behave as if it were a 2D viewer, with + * picking, panning and zooming still enabled. * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_dataSource)] + * If you need to be able to restore the Camera to its previous state, you can save it to a {@link CameraMemento} + * beforehand, from which you can restore it later: * * ````javascript - * import {utils} from "xeokit-sdk.es.js"; - * - * class MyDataSource { + * const cameraMemento = new CameraMemento(); * - * constructor() { - * } + * // Save camera state * - * // Gets metamodel JSON - * getMetaModel(metaModelSrc, ok, error) { - * console.log("MyDataSource#getMetaModel(" + metaModelSrc + ", ... )"); - * utils.loadJSON(metaModelSrc, - * (json) => { - * ok(json); - * }, - * function (errMsg) { - * error(errMsg); - * }); - * } + * cameraMemento.saveCamera(viewer.scene); * - * // Gets the contents of the given .XKT file in an arraybuffer - * getXKT(src, ok, error) { - * console.log("MyDataSource#getXKT(" + xKTSrc + ", ... )"); - * utils.loadArraybuffer(src, - * (arraybuffer) => { - * ok(arraybuffer); - * }, - * function (errMsg) { - * error(errMsg); - * }); - * } - * } + * // Position camera for a downward-looking orthographic view of our storey * - * const xktLoader2 = new XKTLoaderPlugin(viewer, { - * dataSource: new MyDataSource() + * storeyViewsPlugin.gotoStoreyCamera("2SWZMQPyD9pfT9q87pgXa1", { + * projection: "ortho", + * duration: 2.5, + * done: () => { + * viewer.cameraControl.planView = true; // Disable rotation + * } * }); * - * const model5 = xktLoader2.load({ - * id: "myModel5", - * src: "./models/xkt/Duplex.ifc.xkt" - * }); + * //... + * + * // Later, restore the Camera to its saved state + * cameraMemento.restoreCamera(viewer.scene); * ```` * - * ## Loading multiple copies of a model, without object ID clashes + * ## Creating StoreyMaps * - * Sometimes we need to load two or more instances of the same model, without having clashes - * between the IDs of the equivalent objects in the model instances. + * The {@link StoreyViewsPlugin#createStoreyMap} method creates a 2D orthographic plan image of the given storey. * - * As shown in the example below, we do this by setting {@link XKTLoaderPlugin#globalizeObjectIds} ````true```` before we load our models. + * * - * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#TreeViewPlugin_Containment_MultipleModels)] + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_createStoreyMap)] * - * ````javascript - * xktLoader.globalizeObjectIds = true; + * This method creates a {@link StoreyMap}, which provides the plan image as a Base64-encoded string. * - * const model = xktLoader.load({ - * id: "model1", - * src: "./models/xkt/Schependomlaan.xkt" - * }); + * Let's create a 2D plan image of our building storey: * - * const model2 = xktLoader.load({ - * id: "model2", - * src: "./models/xkt/Schependomlaan.xkt" + * ````javascript + * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { + * width: 300, + * format: "png" * }); + * + * const imageData = storeyMap.imageData; // Base64-encoded image data string + * const width = storeyMap.width; // 300 + * const height = storeyMap.height; // Automatically derived from width + * const format = storeyMap.format; // "png" * ```` * - * For each {@link Entity} loaded by these two calls, {@link Entity#id} and {@link MetaObject#id} will get prefixed by - * the ID of their model, in order to avoid ID clashes between the two models. + * As with ````showStoreyEntitys````, We also have the option to customize the appearance of the Entitys in our plan + * images according to their IFC types, using the lookup table configured on {@link StoreyViewsPlugin#objectStates}. * - * An Entity belonging to the first model will get an ID like this: + * For example, we usually want to show only element types like ````IfcWall````, ````IfcDoor```` and + * ````IfcFloor```` in our plan images. * - * ```` - * myModel1#0BTBFw6f90Nfh9rP1dlXrb - * ```` + * Let's create another StoreyMap, this time applying the custom appearances: * - * The equivalent Entity in the second model will get an ID like this: + * ````javascript + * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { + * width: 300, + * format: "png", + * useObjectStates: true // <<--------- Apply custom appearances + * }); + *```` * - * ```` - * myModel2#0BTBFw6f90Nfh9rP1dlXrb + * We can also specify a ````height```` for the plan image, as an alternative to ````width````: + * + * ````javascript + * const storeyMap = storeyViewsPlugin.createStoreyMap("2SWZMQPyD9pfT9q87pgXa1", { + * height: 200, + * format: "png", + * useObjectStates: true + * }); * ```` * - * Now, to update the visibility of both of those Entities collectively, using {@link Scene#setObjectsVisible}, we can - * supply just the IFC product ID part to that method: + * ## Picking Entities in StoreyMaps * - * ````javascript - * myViewer.scene.setObjectVisibilities("0BTBFw6f90Nfh9rP1dlXrb", true); - * ```` + * We can use {@link StoreyViewsPlugin#pickStoreyMap} to pick Entities in our building storey, using 2D coordinates from mouse or touch events on our {@link StoreyMap}'s 2D plan image. * - * The method, along with {@link Scene#setObjectsXRayed}, {@link Scene#setObjectsHighlighted} etc, will internally expand - * the given ID to refer to the instances of that Entity in both models. + * * - * We can also, of course, reference each Entity directly, using its globalized ID: + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#storeyViews_StoreyViewsPlugin_recipe2)] + * + * Let's programmatically pick the Entity at the given 2D pixel coordinates within our image: * * ````javascript - * myViewer.scene.setObjectVisibilities("myModel1#0BTBFw6f90Nfh9rP1dlXrb", true); - *```` + * const mouseCoords = [65, 120]; // Mouse coords within the image extents * - * @class XKTLoaderPlugin + * const pickResult = storeyViewsPlugin.pickStoreyMap(storeyMap, mouseCoords); + * + * if (pickResult && pickResult.entity) { + * pickResult.entity.highlighted = true; + * } + * ```` */ -class XKTLoaderPlugin extends Plugin { +class StoreyViewsPlugin extends Plugin { /** * @constructor * * @param {Viewer} viewer The Viewer. * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="XKTLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {Object} [cfg.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. - * @param {Object} [cfg.dataSource] A custom data source through which the XKTLoaderPlugin can load model and metadata files. Defaults to an instance of {@link XKTDefaultDataSource}, which loads uover HTTP. - * @param {String[]} [cfg.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. - * @param {String[]} [cfg.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. - * @param {Boolean} [cfg.excludeUnclassifiedObjects=false] When loading metadata and this is ````true````, will only load {@link Entity}s that have {@link MetaObject}s (that are not excluded). This is useful when we don't want Entitys in the Scene that are not represented within IFC navigation components, such as {@link TreeViewPlugin}. - * @param {Boolean} [cfg.reuseGeometries=true] Indicates whether to enable geometry reuse (````true```` by default) or whether to internally expand - * all geometry instances into batches (````false````), and not use instancing to render them. Setting this ````false```` can significantly - * improve Viewer performance for models that have a lot of geometry reuse, but may also increase the amount of - * browser and GPU memory they require. See [#769](https://github.com/xeokit/xeokit-sdk/issues/769) for more info. - * @param {Number} [cfg.maxGeometryBatchSize=50000000] Maximum geometry batch size, as number of vertices. This is optionally supplied - * to limit the size of the batched geometry arrays that {@link VBOSceneModel} internally creates for batched geometries. - * A low value means less heap allocation/de-allocation while loading batched geometries, but more draw calls and - * slower rendering speed. A high value means larger heap allocation/de-allocation while loading, but less draw calls - * and faster rendering speed. It's recommended to keep this somewhere roughly between ````50000```` and ````50000000```. - * @param {KTX2TextureTranscoder} [cfg.textureTranscoder] Transcoder used internally to transcode KTX2 - * textures within the XKT. Only required when the XKT is version 10 or later, and contains KTX2 textures. + * @param {String} [cfg.id="StoreyViews"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Object} [cfg.objectStates] Map of visual states for the {@link Entity}s as rendered within each {@link Storey}. Default value is {@link IFCStoreyPlanObjectStates}. */ constructor(viewer, cfg = {}) { - super("XKTLoader", viewer, cfg); - - this._maxGeometryBatchSize = cfg.maxGeometryBatchSize; + super("StoreyViews", viewer); - this.textureTranscoder = cfg.textureTranscoder; - this.dataSource = cfg.dataSource; - this.objectDefaults = cfg.objectDefaults; - this.includeTypes = cfg.includeTypes; - this.excludeTypes = cfg.excludeTypes; - this.excludeUnclassifiedObjects = cfg.excludeUnclassifiedObjects; - this.reuseGeometries = cfg.reuseGeometries; + this._objectsMemento = new ObjectsMemento(); + this._cameraMemento = new CameraMemento(); + + /** + * A {@link Storey} for each ````IfcBuildingStorey```. + * + * There will be a {@link Storey} for every existing {@link MetaObject} whose {@link MetaObject#type} equals "IfcBuildingStorey". + * + * These are created and destroyed automatically as models are loaded and destroyed. + * + * @type {{String:Storey}} + */ + this.storeys = {}; + + /** + * A set of {@link Storey}s for each {@link MetaModel}. + * + * These are created and destroyed automatically as models are loaded and destroyed. + * + * @type {{String: {String:Storey}}} + */ + this.modelStoreys = {}; + + this.objectStates = cfg.objectStates; + + this._onModelLoaded = this.viewer.scene.on("modelLoaded", (modelId) => { + this._registerModelStoreys(modelId); + this.fire("storeys", this.storeys); + }); } - /** - * Gets the ````.xkt```` format versions supported by this XKTLoaderPlugin/ - * @returns {string[]} - */ - get supportedVersions() { - return Object.keys(parsers); + _registerModelStoreys(modelId) { + const viewer = this.viewer; + const scene = viewer.scene; + const metaScene = viewer.metaScene; + const metaModel = metaScene.metaModels[modelId]; + const model = scene.models[modelId]; + if (!metaModel || !metaModel.rootMetaObject) { + return; + } + const storeyIds = metaModel.rootMetaObject.getObjectIDsInSubtreeByType(["IfcBuildingStorey"]); + for (let i = 0, len = storeyIds.length; i < len; i++) { + const storeyId = storeyIds[i]; + const metaObject = metaScene.metaObjects[storeyId]; + const childObjectIds = metaObject.getObjectIDsInSubtree(); + const aabb = scene.getAABB(childObjectIds); + const numObjects = (Math.random() > 0.5) ? childObjectIds.length : 0; + const storey = new Storey(this, aabb, modelId, storeyId, numObjects); + storey._onModelDestroyed = model.once("destroyed", () => { + this._deregisterModelStoreys(modelId); + this.fire("storeys", this.storeys); + }); + this.storeys[storeyId] = storey; + if (!this.modelStoreys[modelId]) { + this.modelStoreys[modelId] = {}; + } + this.modelStoreys[modelId][storeyId] = storey; + } + } + + _deregisterModelStoreys(modelId) { + const storeys = this.modelStoreys[modelId]; + if (storeys) { + const scene = this.viewer.scene; + for (let storyObjectId in storeys) { + if (storeys.hasOwnProperty(storyObjectId)) { + const storey = storeys[storyObjectId]; + const model = scene.models[storey.modelId]; + if (model) { + model.off(storey._onModelDestroyed); + } + delete this.storeys[storyObjectId]; + } + } + delete this.modelStoreys[modelId]; + } } /** - * Gets the texture transcoder. + * Sets map of visual states for the {@link Entity}s as rendered within each {@link Storey}. * - * @type {TextureTranscoder} + * Default value is {@link IFCStoreyPlanObjectStates}. + * + * @type {{String: Object}} */ - get textureTranscoder() { - return this._textureTranscoder; + set objectStates(value) { + this._objectStates = value || IFCStoreyPlanObjectStates; } /** - * Sets the texture transcoder. + * Gets map of visual states for the {@link Entity}s as rendered within each {@link Storey}. * - * @type {TextureTranscoder} - */ - set textureTranscoder(textureTranscoder) { - this._textureTranscoder = textureTranscoder; - } - - /** - * Gets the custom data source through which the XKTLoaderPlugin can load models and metadata. - * - * Default value is {@link XKTDefaultDataSource}, which loads via HTTP. + * Default value is {@link IFCStoreyPlanObjectStates}. * - * @type {Object} + * @type {{String: Object}} */ - get dataSource() { - return this._dataSource; + get objectStates() { + return this._objectStates; } /** - * Sets a custom data source through which the XKTLoaderPlugin can load models and metadata. + * Arranges the {@link Camera} for a 3D orthographic view of the {@link Entity}s within the given storey. * - * Default value is {@link XKTDefaultDataSource}, which loads via HTTP. + * See also: {@link CameraMemento}, which saves and restores the state of the {@link Scene}'s {@link Camera} * - * @type {Object} + * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. + * @param {*} [options] Options for arranging the Camera. + * @param {String} [options.projection] Projection type to transition the Camera to. Accepted values are "perspective" and "ortho". + * @param {Function} [options.done] Callback to fire when the Camera has arrived. When provided, causes an animated flight to the saved state. Otherwise jumps to the saved state. */ - set dataSource(value) { - this._dataSource = value || new XKTDefaultDataSource(); - } + gotoStoreyCamera(storeyId, options = {}) { - /** - * Gets map of initial default states for each loaded {@link Entity} that represents an object. - * - * Default value is {@link IFCObjectDefaults}. - * - * @type {{String: Object}} - */ - get objectDefaults() { - return this._objectDefaults; - } + const storey = this.storeys[storeyId]; - /** - * Sets map of initial default states for each loaded {@link Entity} that represents an object. - * - * Default value is {@link IFCObjectDefaults}. - * - * @type {{String: Object}} - */ - set objectDefaults(value) { - this._objectDefaults = value || IFCObjectDefaults; - } + if (!storey) { + this.error("IfcBuildingStorey not found with this ID: " + storeyId); + if (options.done) { + options.done(); + } + return; + } - /** - * Gets the whitelist of the IFC types loaded by this XKTLoaderPlugin. - * - * When loading models with metadata, causes this XKTLoaderPlugin to only load objects whose types are in this - * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. - * - * Default value is ````undefined````. - * - * @type {String[]} - */ - get includeTypes() { - return this._includeTypes; - } + const viewer = this.viewer; + const scene = viewer.scene; + const camera = scene.camera; + const aabb = storey.aabb; - /** - * Sets the whitelist of the IFC types loaded by this XKTLoaderPlugin. - * - * When loading models with metadata, causes this XKTLoaderPlugin to only load objects whose types are in this - * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. - * - * Default value is ````undefined````. - * - * @type {String[]} - */ - set includeTypes(value) { - this._includeTypes = value; - } + if (aabb[3] < aabb[0] || aabb[4] < aabb[1] || aabb[5] < aabb[2]) { // Don't fly to an inverted boundary + if (options.done) { + options.done(); + } + return; + } + if (aabb[3] === aabb[0] && aabb[4] === aabb[1] && aabb[5] === aabb[2]) { // Don't fly to an empty boundary + if (options.done) { + options.done(); + } + return; + } + const look2 = math.getAABB3Center(aabb); + const diag = math.getAABB3Diag(aabb); + const fitFOV = 45; // fitFOV; + const sca = Math.abs(diag / Math.tan(fitFOV * math.DEGTORAD)); - /** - * Gets the blacklist of IFC types that are never loaded by this XKTLoaderPlugin. - * - * When loading models with metadata, causes this XKTLoaderPlugin to **not** load objects whose types are in this - * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. - * - * Default value is ````undefined````. - * - * @type {String[]} - */ - get excludeTypes() { - return this._excludeTypes; - } + const orthoScale2 = diag * 1.3; - /** - * Sets the blacklist of IFC types that are never loaded by this XKTLoaderPlugin. - * - * When loading models with metadata, causes this XKTLoaderPlugin to **not** load objects whose types are in this - * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. - * - * Default value is ````undefined````. - * - * @type {String[]} - */ - set excludeTypes(value) { - this._excludeTypes = value; - } + const eye2 = tempVec3a$2; - /** - * Gets whether we load objects that don't have IFC types. - * - * When loading models with metadata and this is ````true````, XKTLoaderPlugin will not load objects - * that don't have IFC types. - * - * Default value is ````false````. - * - * @type {Boolean} - */ - get excludeUnclassifiedObjects() { - return this._excludeUnclassifiedObjects; - } + eye2[0] = look2[0] + (camera.worldUp[0] * sca); + eye2[1] = look2[1] + (camera.worldUp[1] * sca); + eye2[2] = look2[2] + (camera.worldUp[2] * sca); - /** - * Sets whether we load objects that don't have IFC types. - * - * When loading models with metadata and this is ````true````, XKTLoaderPlugin will not load objects - * that don't have IFC types. - * - * Default value is ````false````. - * - * @type {Boolean} - */ - set excludeUnclassifiedObjects(value) { - this._excludeUnclassifiedObjects = !!value; - } + const up2 = camera.worldForward; - /** - * Gets whether XKTLoaderPlugin globalizes each {@link Entity#id} and {@link MetaObject#id} as it loads a model. - * - * Default value is ````false````. - * - * @type {Boolean} - */ - get globalizeObjectIds() { - return this._globalizeObjectIds; + if (options.done) { + + viewer.cameraFlight.flyTo(utils.apply(options, { + eye: eye2, + look: look2, + up: up2, + orthoScale: orthoScale2 + }), () => { + options.done(); + }); + + } else { + + viewer.cameraFlight.jumpTo(utils.apply(options, { + eye: eye2, + look: look2, + up: up2, + orthoScale: orthoScale2 + })); + + viewer.camera.ortho.scale = orthoScale2; + } } /** - * Sets whether XKTLoaderPlugin globalizes each {@link Entity#id} and {@link MetaObject#id} as it loads a model. - * - * Set this ````true```` when you need to load multiple instances of the same model, to avoid ID clashes - * between the objects in the different instances. - * - * When we load a model with this set ````true````, then each {@link Entity#id} and {@link MetaObject#id} will be - * prefixed by the ID of the model, ie. ````#````. + * Shows the {@link Entity}s within the given storey. * - * {@link Entity#originalSystemId} and {@link MetaObject#originalSystemId} will always hold the original, un-prefixed, ID values. + * Optionally hides all other Entitys. * - * Default value is ````false````. + * Optionally sets the visual appearance of each of the Entitys according to its IFC type. The appearance of + * IFC types in plan views is configured by {@link StoreyViewsPlugin#objectStates}. * - * See the main {@link XKTLoaderPlugin} class documentation for usage info. + * See also: {@link ObjectsMemento}, which saves and restores a memento of the visual state + * of the {@link Entity}'s that represent objects within a {@link Scene}. * - * @type {Boolean} + * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. + * @param {*} [options] Options for showing the Entitys within the storey. + * @param {Boolean} [options.hideOthers=false] When ````true````, hide all other {@link Entity}s. + * @param {Boolean} [options.useObjectStates=false] When ````true````, apply the custom visibilities and appearances configured for IFC types in {@link StoreyViewsPlugin#objectStates}. */ - set globalizeObjectIds(value) { - this._globalizeObjectIds = !!value; - } + showStoreyObjects(storeyId, options = {}) { - /** - * Gets whether XKTLoaderPlugin enables geometry reuse when loading models. - * - * Default value is ````true````. - * - * @type {Boolean} - */ - get reuseGeometries() { - return this._reuseGeometries; + const storey = this.storeys[storeyId]; + + if (!storey) { + this.error("IfcBuildingStorey not found with this ID: " + storeyId); + return; + } + + const viewer = this.viewer; + const scene = viewer.scene; + const metaScene = viewer.metaScene; + const storeyMetaObject = metaScene.metaObjects[storeyId]; + + if (!storeyMetaObject) { + return; + } + + if (options.hideOthers) { + scene.setObjectsVisible(viewer.scene.visibleObjectIds, false); + } + + this.withStoreyObjects(storeyId, (entity, metaObject) => { + if (entity) { + if (options.useObjectStates) { + const props = this._objectStates[metaObject.type] || this._objectStates["DEFAULT"]; + if (props) { + entity.visible = props.visible; + entity.edges = props.edges; + // entity.xrayed = props.xrayed; // FIXME: Buggy + // entity.highlighted = props.highlighted; + // entity.selected = props.selected; + if (props.colorize) { + entity.colorize = props.colorize; + } + if (props.opacity !== null && props.opacity !== undefined) { + entity.opacity = props.opacity; + } + } + } else { + entity.visible = true; + } + } + }); } /** - * Sets whether XKTLoaderPlugin enables geometry reuse when loading models. - * - * Default value is ````true````. + * Executes a callback on each of the objects within the given storey. * - * Geometry reuse saves memory, but can impact Viewer performance when there are many reused geometries. For - * this reason, we can set this ````false```` to disable geometry reuse for models loaded by this XKTLoaderPlugin - * (which will then "expand" the geometry instances into batches instead). + * ## Usage * - * The result will be be less WebGL draw calls (which are expensive), at the cost of increased memory footprint. + * In the example below, we'll show all the {@link Entity}s, within the given ````IfcBuildingStorey````, + * that have {@link MetaObject}s with type ````IfcSpace````. Note that the callback will only be given + * an {@link Entity} when one exists for the given {@link MetaObject}. * - * See [#769](https://github.com/xeokit/xeokit-sdk/issues/769) for more info. + * ````JavaScript + * myStoreyViewsPlugin.withStoreyObjects(storeyId, (entity, metaObject) => { + * if (entity && metaObject && metaObject.type === "IfcSpace") { + * entity.visible = true; + * } + * }); + * ```` * - * @type {Boolean} + * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. + * @param {Function} callback The callback. */ - set reuseGeometries(value) { - this._reuseGeometries = value !== false; + withStoreyObjects(storeyId, callback) { + const viewer = this.viewer; + const scene = viewer.scene; + const metaScene = viewer.metaScene; + const rootMetaObject = metaScene.metaObjects[storeyId]; + if (!rootMetaObject) { + return; + } + const storeySubObjects = rootMetaObject.getObjectIDsInSubtree(); + for (var i = 0, len = storeySubObjects.length; i < len; i++) { + const objectId = storeySubObjects[i]; + const metaObject = metaScene.metaObjects[objectId]; + const entity = scene.objects[objectId]; + if (entity) { + callback(entity, metaObject); + } + } } /** - * Loads an ````.xkt```` model into this XKTLoaderPlugin's {@link Viewer}. - * - * Since xeokit/xeokit-sdk 1.9.0, XKTLoaderPlugin has supported XKT 8, which bundles the metamodel - * data (eg. an IFC element hierarchy) in the XKT file itself. For XKT 8, we therefore no longer need to - * load the metamodel data from a separate accompanying JSON file, as we did with previous XKT versions. - * However, if we do choose to specify a separate metamodel JSON file to load (eg. for backward compatibility - * in data pipelines), then that metamodel will be loaded and the metamodel in the XKT 8 file will be ignored. + * Creates a 2D map of the given storey. * - * @param {*} params Loading parameters. - * @param {String} [params.id] ID to assign to the root {@link Entity#id}, unique among all components in the Viewer's {@link Scene}, generated automatically by default. - * @param {String} [params.src] Path to a *````.xkt````* file, as an alternative to the ````xkt```` parameter. - * @param {ArrayBuffer} [params.xkt] The *````.xkt````* file data, as an alternative to the ````src```` parameter. - * @param {String} [params.metaModelSrc] Path to an optional metadata file, as an alternative to the ````metaModelData```` parameter. - * @param {*} [params.metaModelData] JSON model metadata, as an alternative to the ````metaModelSrc```` parameter. - * @param {{String:Object}} [params.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. - * @param {String[]} [params.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. - * @param {String[]} [params.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. - * @param {Boolean} [params.edges=false] Whether or not xeokit renders the model with edges emphasized. - * @param {Number[]} [params.origin=[0,0,0]] The model's World-space double-precision 3D origin. Use this to position the model within xeokit's World coordinate system, using double-precision coordinates. - * @param {Number[]} [params.position=[0,0,0]] The model single-precision 3D position, relative to the ````origin```` parameter. - * @param {Number[]} [params.scale=[1,1,1]] The model's scale. - * @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, given as Euler angles in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. Relative to ````origin````. - * @param {Boolean} [params.edges=false] Indicates if the model's edges are initially emphasized. - * @param {Boolean} [params.saoEnabled=true] Indicates if Scalable Ambient Obscurance (SAO) is enabled for the model. SAO is configured by the Scene's {@link SAO} component. Only works when {@link SAO#enabled} is also ````true```` - * @param {Boolean} [params.pbrEnabled=true] Indicates if physically-based rendering (PBR) is enabled for the model. Overrides ````colorTextureEnabled````. Only works when {@link Scene#pbrEnabled} is also ````true````. - * @param {Boolean} [params.colorTextureEnabled=true] Indicates if base color texture rendering is enabled for the model. Overridden by ````pbrEnabled````. Only works when {@link Scene#colorTextureEnabled} is also ````true````. - * @param {Number} [params.backfaces=false] When we set this ````true````, then we force rendering of backfaces for the model. When - * we leave this ````false````, then we allow the Viewer to decide when to render backfaces. In that case, the - * Viewer will hide backfaces on watertight meshes, show backfaces on open meshes, and always show backfaces on meshes when we slice them open with {@link SectionPlane}s. - * @param {Boolean} [params.excludeUnclassifiedObjects=false] When loading metadata and this is ````true````, will only load {@link Entity}s that have {@link MetaObject}s (that are not excluded). This is useful when we don't want Entitys in the Scene that are not represented within IFC navigation components, such as {@link TreeViewPlugin}. - * @param {Boolean} [params.globalizeObjectIds=false] Indicates whether to globalize each {@link Entity#id} and {@link MetaObject#id}, in case you need to prevent ID clashes with other models. See {@link XKTLoaderPlugin#globalizeObjectIds} for more info. - * @param {Boolean} [params.reuseGeometries=true] Indicates whether to enable geometry reuse (````true```` by default) or whether to expand - * all geometry instances into batches (````false````), and not use instancing to render them. Setting this ````false```` can significantly - * improve Viewer performance for models that have excessive geometry reuse, but may also increases the amount of - * browser and GPU memory used by the model. See [#769](https://github.com/xeokit/xeokit-sdk/issues/769) for more info. - * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. + * @param {String} storeyId ID of the ````IfcBuildingStorey```` object. + * @param {*} [options] Options for creating the image. + * @param {Number} [options.width=300] Image width in pixels. Height will be automatically determined from this, if not given. + * @param {Number} [options.height=300] Image height in pixels, as an alternative to width. Width will be automatically determined from this, if not given. + * @param {String} [options.format="png"] Image format. Accepted values are "png" and "jpeg". + * @returns {StoreyMap} The StoreyMap. */ - load(params = {}) { + createStoreyMap(storeyId, options = {}) { - if (params.id && this.viewer.scene.components[params.id]) { - this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); - delete params.id; + const storey = this.storeys[storeyId]; + if (!storey) { + this.error("IfcBuildingStorey not found with this ID: " + storeyId); + return EMPTY_IMAGE; } - const sceneModel = new VBOSceneModel(this.viewer.scene, utils.apply(params, { - isModel: true, - textureTranscoder: this._textureTranscoder, - maxGeometryBatchSize: this._maxGeometryBatchSize, - origin: params.origin - })); + const viewer = this.viewer; + const scene = viewer.scene; + const format = options.format || "png"; + const aabb = storey.aabb; + const aspect = (aabb[5] - aabb[2]) / (aabb[3] - aabb[0]); + const padding = options.padding || 0; - const modelId = sceneModel.id; // In case ID was auto-generated + let width; + let height; - if (!params.src && !params.xkt) { - this.error("load() param expected: src or xkt"); - return sceneModel; // Return new empty model - } + if (options.width && options.height) { + width = options.width; + height = options.height; - const options = {}; - const includeTypes = params.includeTypes || this._includeTypes; - const excludeTypes = params.excludeTypes || this._excludeTypes; - const objectDefaults = params.objectDefaults || this._objectDefaults; + } else if (options.height) { + height = options.height; + width = height / aspect; - options.reuseGeometries = (params.reuseGeometries !== null && params.reuseGeometries !== undefined ) ? params.reuseGeometries : (this._reuseGeometries !== false); + } else if (options.width) { + width = options.width; + height = width * aspect; - if (includeTypes) { - options.includeTypesMap = {}; - for (let i = 0, len = includeTypes.length; i < len; i++) { - options.includeTypesMap[includeTypes[i]] = true; - } + } else { + width = 300; + height = width * aspect; } - if (excludeTypes) { - options.excludeTypesMap = {}; - for (let i = 0, len = excludeTypes.length; i < len; i++) { - options.excludeTypesMap[excludeTypes[i]] = true; - } - } + this._objectsMemento.saveObjects(scene); + this._cameraMemento.saveCamera(scene); - if (objectDefaults) { - options.objectDefaults = objectDefaults; - } + viewer.beginSnapshot(); - options.excludeUnclassifiedObjects = (params.excludeUnclassifiedObjects !== undefined) ? (!!params.excludeUnclassifiedObjects) : this._excludeUnclassifiedObjects; - options.globalizeObjectIds = (params.globalizeObjectIds !== undefined) ? (!!params.globalizeObjectIds) : this._globalizeObjectIds; + this.showStoreyObjects(storeyId, utils.apply(options, { + useObjectStates: true, + hideOthers: true + })); - if (params.metaModelSrc || params.metaModelData) { + this._arrangeStoreyMapCamera(storey); - const processMetaModelData = (metaModelData) => { + const src = viewer.getSnapshot({ + width: width, + height: height, + format: format, + }); - const metaModel = this.viewer.metaScene.createMetaModel(modelId, metaModelData, { - includeTypes: includeTypes, - excludeTypes: excludeTypes, - globalizeObjectIds: this.globalizeObjectIds - }); + this._objectsMemento.restoreObjects(scene); + this._cameraMemento.restoreCamera(scene); - if (!metaModel) { - return false; - } + viewer.endSnapshot(); - if (params.src) { - this._loadModel(params.src, params, options, sceneModel); - } else { - this._parseModel(params.xkt, params, options, sceneModel); - } + return new StoreyMap(storeyId, src, format, width, height, padding); + } - sceneModel.once("destroyed", () => { - this.viewer.metaScene.destroyMetaModel(sceneModel.id); - }); + _arrangeStoreyMapCamera(storey) { + const viewer = this.viewer; + const scene = viewer.scene; + const camera = scene.camera; + const aabb = storey.aabb; + const look = math.getAABB3Center(aabb); + const sca = 0.5; + const eye = tempVec3a$2; + eye[0] = look[0] + (camera.worldUp[0] * sca); + eye[1] = look[1] + (camera.worldUp[1] * sca); + eye[2] = look[2] + (camera.worldUp[2] * sca); + const up = camera.worldForward; + viewer.cameraFlight.jumpTo({eye: eye, look: look, up: up}); + const xHalfSize = (aabb[3] - aabb[0]) / 2; + const yHalfSize = (aabb[4] - aabb[1]) / 2; + const zHalfSize = (aabb[5] - aabb[2]) / 2; + const xmin = -xHalfSize; + const xmax = +xHalfSize; + const ymin = -yHalfSize; + const ymax = +yHalfSize; + const zmin = -zHalfSize; + const zmax = +zHalfSize; + viewer.camera.customProjection.matrix = math.orthoMat4c(xmin, xmax, zmin, zmax, ymin, ymax, tempMat4); + viewer.camera.projection = "customProjection"; + } - return true; - }; + /** + * Attempts to pick an {@link Entity} at the given pixel coordinates within a StoreyMap image. + * + * @param {StoreyMap} storeyMap The StoreyMap. + * @param {Number[]} imagePos 2D pixel coordinates within the bounds of {@link StoreyMap#imageData}. + * @param {*} [options] Picking options. + * @param {Boolean} [options.pickSurface=false] Whether to return the picked position on the surface of the Entity. + * @returns {PickResult} The pick result, if an Entity was successfully picked, else null. + */ + pickStoreyMap(storeyMap, imagePos, options = {}) { - if (params.metaModelSrc) { + const storeyId = storeyMap.storeyId; + const storey = this.storeys[storeyId]; - const metaModelSrc = params.metaModelSrc; + if (!storey) { + this.error("IfcBuildingStorey not found with this ID: " + storeyId); + return null + } - this.viewer.scene.canvas.spinner.processes++; + const normX = 1.0 - (imagePos[0] / storeyMap.width); + const normZ = 1.0 - (imagePos[1] / storeyMap.height); - this._dataSource.getMetaModel(metaModelSrc, (metaModelData) => { + const aabb = storey.aabb; - if (sceneModel.destroyed) { - return; - } + const xmin = aabb[0]; + const ymin = aabb[1]; + const zmin = aabb[2]; + const xmax = aabb[3]; + const ymax = aabb[4]; + const zmax = aabb[5]; - if (!processMetaModelData(metaModelData)) { + const xWorldSize = xmax - xmin; + const yWorldSize = ymax - ymin; + const zWorldSize = zmax - zmin; - this.error(`load(): Failed to load model metadata for model '${modelId} from '${metaModelSrc}' - metadata not valid`); + const origin = math.vec3([xmin + (xWorldSize * normX), ymin + (yWorldSize * 0.5), zmin + (zWorldSize * normZ)]); + const direction = math.vec3([0, -1, 0]); + const look = math.addVec3(origin, direction, tempVec3a$2); + const worldForward = this.viewer.camera.worldForward; + const matrix = math.lookAtMat4v(origin, look, worldForward, tempMat4); - sceneModel.fire("error", "Metadata not valid"); - } + const pickResult = this.viewer.scene.pick({ // Picking with arbitrarily-positioned ray + pickSurface: options.pickSurface, + pickInvisible: true, + matrix: matrix + }); - this.viewer.scene.canvas.spinner.processes--; + if (pickResult) { + const metaObject = this.viewer.metaScene.metaObjects[pickResult.entity.id]; + const objectState = this.objectStates[metaObject.type]; + if (!objectState || !objectState.visible) { + return null; + } + } - }, (errMsg) => { + return pickResult; + } - this.error(`load(): Failed to load model metadata for model '${modelId} from '${metaModelSrc}' - ${errMsg}`); + /** + * Gets the ID of the storey that contains the given 3D World-space position. + *. + * @param {Number[]} worldPos 3D World-space position. + * @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys. + */ + getStoreyContainingWorldPos(worldPos) { + for (var storeyId in this.storeys) { + const storey = this.storeys[storeyId]; + if (math.point3AABB3Intersect(storey.aabb, worldPos)) { + return storeyId; + } + } + return null; + } - sceneModel.fire("error", `Failed to load model metadata from '${metaModelSrc}' - ${errMsg}`); + /** + * Converts a 3D World-space position to a 2D position within a StoreyMap image. + * + * Use {@link StoreyViewsPlugin#pickStoreyMap} to convert 2D image positions to 3D world-space. + * + * @param {StoreyMap} storeyMap The StoreyMap. + * @param {Number[]} worldPos 3D World-space position within the storey. + * @param {Number[]} imagePos 2D pixel position within the {@link StoreyMap#imageData}. + * @returns {Boolean} True if ````imagePos```` is within the bounds of the {@link StoreyMap#imageData}, else ````false```` if it falls outside. + */ + worldPosToStoreyMap(storeyMap, worldPos, imagePos) { - this.viewer.scene.canvas.spinner.processes--; - }); + const storeyId = storeyMap.storeyId; + const storey = this.storeys[storeyId]; - } else if (params.metaModelData) { + if (!storey) { + this.error("IfcBuildingStorey not found with this ID: " + storeyId); + return false + } - if (!processMetaModelData(params.metaModelData)) { + const aabb = storey.aabb; - this.error(`load(): Failed to load model metadata for model '${modelId} from '${params.metaModelSrc}' - metadata not valid`); + const xmin = aabb[0]; + const ymin = aabb[1]; + const zmin = aabb[2]; - sceneModel.fire("error", "Metadata not valid"); - } - } + const xmax = aabb[3]; + const ymax = aabb[4]; + const zmax = aabb[5]; + + const xWorldSize = xmax - xmin; + const yWorldSize = ymax - ymin; + const zWorldSize = zmax - zmin; + + const camera = this.viewer.camera; + const worldUp = camera.worldUp; + + const xUp = worldUp[0] > worldUp[1] && worldUp[0] > worldUp[2]; + const yUp = !xUp && worldUp[1] > worldUp[0] && worldUp[1] > worldUp[2]; + !xUp && !yUp && worldUp[2] > worldUp[0] && worldUp[2] > worldUp[1]; + + const ratioX = (storeyMap.width / xWorldSize); + const ratioY = yUp ? (storeyMap.height / zWorldSize) : (storeyMap.height / yWorldSize); // Assuming either Y or Z is "up", but never X + + imagePos[0] = Math.floor(storeyMap.width - ((worldPos[0] - xmin) * ratioX)); + imagePos[1] = Math.floor(storeyMap.height - ((worldPos[2] - zmin) * ratioY)); + + return (imagePos[0] >= 0 && imagePos[0] < storeyMap.width && imagePos[1] >= 0 && imagePos[1] <= storeyMap.height); + } + /** + * Converts a 3D World-space direction vector to a 2D vector within a StoreyMap image. + * + * @param {StoreyMap} storeyMap The StoreyMap. + * @param {Number[]} worldDir 3D World-space direction vector. + * @param {Number[]} imageDir Normalized 2D direction vector. + */ + worldDirToStoreyMap(storeyMap, worldDir, imageDir) { + const camera = this.viewer.camera; + const eye = camera.eye; + const look = camera.look; + const eyeLookDir = math.subVec3(look, eye, tempVec3a$2); + const worldUp = camera.worldUp; + const xUp = worldUp[0] > worldUp[1] && worldUp[0] > worldUp[2]; + const yUp = !xUp && worldUp[1] > worldUp[0] && worldUp[1] > worldUp[2]; + !xUp && !yUp && worldUp[2] > worldUp[0] && worldUp[2] > worldUp[1]; + if (xUp) { + imageDir[0] = eyeLookDir[1]; + imageDir[1] = eyeLookDir[2]; + } else if (yUp) { + imageDir[0] = eyeLookDir[0]; + imageDir[1] = eyeLookDir[2]; } else { - if (params.src) { - this._loadModel(params.src, params, options, sceneModel); - } else { - this._parseModel(params.xkt, params, options, sceneModel); - } + imageDir[0] = eyeLookDir[0]; + imageDir[1] = eyeLookDir[1]; } + math.normalizeVec2(imageDir); + } - return sceneModel; + /** + * Destroys this StoreyViewsPlugin. + */ + destroy() { + this.viewer.scene.off(this._onModelLoaded); + super.destroy(); } +} - _loadModel(src, params, options, sceneModel) { +/** + * Tests if {@link TreeViewPlugin} would be able to create a "types" hierarchy for the given {@link MetaModel}. + * + * @param {MetaModel} metaModel The MetaModel. + * @param {String[]} errors Accumulates messages for validation errors. + * @return {boolean} Returns ````true```` if no errors found, else ````false````. + */ +function validateMetaModelForTreeViewTypesHierarchy(metaModel, errors) { + const rootMetaObject = metaModel.rootMetaObject; + if (!rootMetaObject) { + errors.push("Can't build types hierarchy: model is empty"); + return false; + } + return true; +} - const spinner = this.viewer.scene.canvas.spinner; +/** + * Tests if {@link TreeViewPlugin} would be able to create a "storeys" hierarchy for the given {@link MetaModel}. + * + * @param {MetaModel} metaModel The MetaModel. + * @param {String[]} errors Accumulates messages for validation errors. + * @return {boolean} Returns ````true```` if no errors found, else ````false````. + */ +function validateMetaModelForTreeViewStoreysHierarchy(metaModel, errors) { + const rootMetaObject = metaModel.rootMetaObject; + if (!rootMetaObject) { + errors.push("Can't build storeys hierarchy: model is empty"); + return false; + } + return _validateMetaModelForStoreysHierarchy(rootMetaObject, errors); +} - spinner.processes++; +/** + * Tests if {@link TreeViewPlugin} would be able to create a "containment" hierarchy for the given {@link MetaModel}. + * + * @param {MetaModel} metaModel The MetaModel. + * @param {String[]} errors Accumulates messages for validation errors. + * @return {boolean} Returns ````true```` if no errors found, else ````false````. + */ +function validateMetaModelForTreeViewContainmentHierarchy(metaModel, errors) { + const rootMetaObject = metaModel.rootMetaObject; + if (!rootMetaObject) { + errors.push("Can't build containment hierarchy: model is empty"); + return false; + } + return true; +} - this._dataSource.getXKT(params.src, (arrayBuffer) => { - this._parseModel(arrayBuffer, params, options, sceneModel); - spinner.processes--; - }, - (errMsg) => { - spinner.processes--; - this.error(errMsg); - sceneModel.fire("error", errMsg); - }); +/** + * @private + */ +function _validateMetaModelForStoreysHierarchy(metaObject, errors, level = 0, ctx, buildingNode) { + ctx = ctx || { + foundIFCBuildingStoreys: false + }; + const metaObjectType = metaObject.type; + const children = metaObject.children; + if (metaObjectType === "IfcBuilding") { + buildingNode = true; + } else if (metaObjectType === "IfcBuildingStorey") { + if (!buildingNode) { + errors.push("Can't build storeys hierarchy: IfcBuildingStorey found without parent IfcBuilding"); + return false; + } + ctx.foundIFCBuildingStoreys = true; + } + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + const childMetaObject = children[i]; + if (!_validateMetaModelForStoreysHierarchy(childMetaObject, errors, level + 1, ctx, buildingNode)) { + return false; + } + } + } + if (level === 0) { + if (!ctx.foundIFCBuildingStoreys) ; } + return true; +} - _parseModel(arrayBuffer, params, options, sceneModel) { +const idMap = new Map$1(); - if (sceneModel.destroyed) { - return; - } +/** + * @desc Represents a model tree view within a {@link TreeViewPlugin}. + * + * * Stored in {@link treeViewPlugin#modelTreeViews}, mapped to the model ID. + * * Created by each call to {@link TreeViewPlugin#addModel}. + */ +class ModelTreeView { - const dataView = new DataView(arrayBuffer); - const dataArray = new Uint8Array(arrayBuffer); - const xktVersion = dataView.getUint32(0, true); - const parser = parsers[xktVersion]; + /** + * @private + */ + constructor(viewer, treeViewPlugin, model, metaModel, cfg) { - if (!parser) { - this.error("Unsupported .XKT file version: " + xktVersion + " - this XKTLoaderPlugin supports versions " + Object.keys(parsers)); + if (!cfg.containerElement) { + throw "Config expected: containerElement"; + } + + const rootMetaObject = metaModel.rootMetaObject; + if (!rootMetaObject) { return; } - this.log("Loading .xkt V" + xktVersion); + /** + * Contains messages for any errors found in the MetaModel for this ModelTreeView. + * @type {String[]} + */ + this.errors = []; - const numElements = dataView.getUint32(4, true); - const elements = []; - let byteOffset = (numElements + 2) * 4; - for (let i = 0; i < numElements; i++) { - const elementSize = dataView.getUint32((i + 2) * 4, true); - elements.push(dataArray.subarray(byteOffset, byteOffset + elementSize)); - byteOffset += elementSize; - } + /** + * True if errors were found in the MetaModel for this ModelTreeView. + * @type {boolean} + */ + this.valid = true; - parser.parse(this.viewer, options, elements, sceneModel); + /** + * The MetaModel corresponding to this ModelTreeView. + * @type {MetaModel} + */ + this.metaModel = metaModel; - sceneModel.finalize(); + this._id = idMap.addItem(); + this._baseId = "" + this._id; + this._viewer = viewer; + this._treeViewPlugin = treeViewPlugin; + this._rootMetaObject = rootMetaObject; + this._containerElement = cfg.containerElement; + this._rootElement = null; + this._muteSceneEvents = false; + this._muteTreeEvents = false; + this._rootNodes = []; + this._objectNodes = {}; + this._rootName = cfg.rootName; + this._sortNodes = cfg.sortNodes; + this._pruneEmptyNodes = cfg.pruneEmptyNodes; - this._createDefaultMetaModelIfNeeded(sceneModel, params, options); + this._showListItemElementId = null; - sceneModel.scene.once("tick", () => { - if (sceneModel.destroyed) { + this._containerElement.oncontextmenu = (e) => { + e.preventDefault(); + }; + + this._onObjectVisibility = this._viewer.scene.on("objectVisibility", (entity) => { + if (this._muteSceneEvents) { return; } - sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events - sceneModel.fire("loaded", true, false); // Don't forget the event, for late subscribers + const objectId = entity.id; + const node = this._objectNodes[objectId]; + if (!node) { + return; // Not in this tree + } + const visible = entity.visible; + const updated = (visible !== node.checked); + if (!updated) { + return; + } + this._muteTreeEvents = true; + node.checked = visible; + if (visible) { + node.numVisibleEntities++; + } else { + node.numVisibleEntities--; + } + const checkbox = document.getElementById(node.nodeId); + if (checkbox) { + checkbox.checked = visible; + } + let parent = node.parent; + while (parent) { + parent.checked = visible; + if (visible) { + parent.numVisibleEntities++; + } else { + parent.numVisibleEntities--; + } + const parentCheckbox = document.getElementById(parent.nodeId); + if (parentCheckbox) { + const newChecked = (parent.numVisibleEntities > 0); + if (newChecked !== parentCheckbox.checked) { + parentCheckbox.checked = newChecked; + } + } + parent = parent.parent; + } + this._muteTreeEvents = false; }); - } - - _createDefaultMetaModelIfNeeded(sceneModel, params, options) { - - const metaModelId = sceneModel.id; - if (!this.viewer.metaScene.metaModels[metaModelId]) { + this.switchExpandHandler = (event) => { + event.preventDefault(); + event.stopPropagation(); + const switchElement = event.target; + this._expandSwitchElement(switchElement); + }; - const metaModelData = { - metaObjects: [] - }; + this.switchCollapseHandler = (event) => { + event.preventDefault(); + event.stopPropagation(); + const switchElement = event.target; + this._collapseSwitchElement(switchElement); + }; - metaModelData.metaObjects.push({ - id: metaModelId, - type: "default", - name: metaModelId, - parent: null + this._checkboxChangeHandler = (event) => { + if (this._muteTreeEvents) { + return; + } + this._muteSceneEvents = true; + const checkbox = event.target; + const visible = checkbox.checked; + const nodeId = checkbox.id; + const checkedObjectId = this._nodeToObjectID(nodeId); + const checkedNode = this._objectNodes[checkedObjectId]; + const objects = this._viewer.scene.objects; + let numUpdated = 0; + this._withNodeTree(checkedNode, (node) => { + const objectId = node.objectId; + const checkBoxId = node.nodeId; + const entity = objects[objectId]; + const isLeaf = (node.children.length === 0); + node.numVisibleEntities = visible ? node.numEntities : 0; + if (isLeaf && (visible !== node.checked)) { + numUpdated++; + } + node.checked = visible; + const checkbox2 = document.getElementById(checkBoxId); + if (checkbox2) { + checkbox2.checked = visible; + } + if (entity) { + entity.visible = visible; + } }); - - const entityList = sceneModel.entityList; - - for (let i = 0, len = entityList.length; i < len; i++) { - const entity = entityList[i]; - if (entity.isObject) { - metaModelData.metaObjects.push({ - id: entity.id, - type: "default", - name: entity.id, - parent: metaModelId - }); + let parent = checkedNode.parent; + while (parent) { + parent.checked = visible; + const checkbox2 = document.getElementById(parent.nodeId); // Parent checkboxes are always in DOM + if (visible) { + parent.numVisibleEntities += numUpdated; + } else { + parent.numVisibleEntities -= numUpdated; + } + const newChecked = (parent.numVisibleEntities > 0); + if (newChecked !== checkbox2.checked) { + checkbox2.checked = newChecked; } + parent = parent.parent; } + this._muteSceneEvents = false; + }; - const src = params.src; - - this.viewer.metaScene.createMetaModel(metaModelId, metaModelData, { - - includeTypes: options.includeTypes, - excludeTypes: options.excludeTypes, - globalizeObjectIds: options.globalizeObjectIds, + this._hierarchy = cfg.hierarchy || "containment"; + this._autoExpandDepth = cfg.autoExpandDepth || 0; - getProperties: async (propertiesId) => { - return await this._dataSource.getProperties(src, propertiesId); - } - }); + this._createNodes(); + } - sceneModel.once("destroyed", () => { - this.viewer.metaScene.destroyMetaModel(metaModelId); - }); - } + _nodeToObjectID(nodeId) { + return nodeId.substring(this._baseId.length); } -} -/** - * @desc Configures the normal rendered appearance of {@link Mesh}es using the non-realistic but GPU-efficient Lambertian flat shading model for calculating reflectance. - * - * * Useful for efficiently rendering non-realistic objects for high-detail CAD. - * * Use {@link PhongMaterial} when you need specular highlights. - * * Use the physically-based {@link MetallicMaterial} or {@link SpecularMaterial} when you need more realism. - * * For LambertMaterial, the illumination calculation is performed at each triangle vertex, and the resulting color is interpolated across the face of the triangle. For {@link PhongMaterial}, {@link MetallicMaterial} and - * {@link SpecularMaterial}, vertex normals are interpolated across the surface of the triangle, and the illumination calculation is performed at each texel. - * - * ## Usage - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_LambertMaterial)] - * - * In the example below we'll create a {@link Mesh} with a shape defined by a {@link buildTorusGeometry} and normal rendering appearance configured with a LambertMaterial. - * - * ```` javascript - * import {Viewer, Mesh, buildTorusGeometry, ReadableGeometry, LambertMaterial} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0, 0, 5]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ - * center: [0, 0, 0], - * radius: 1.5, - * tube: 0.5, - * radialSegments: 12, - * tubeSegments: 8, - * arc: Math.PI * 2.0 - * }), - * material: new LambertMaterial(viewer.scene, { - * ambient: [0.3, 0.3, 0.3], - * color: [0.5, 0.5, 0.0], - * alpha: 1.0, // Default - * lineWidth: 1, - * pointSize: 1, - * backfaces: false, - * frontFace: "ccw" - * }) - * }); - * ```` - * - * ## LambertMaterial Properties - * - * The following table summarizes LambertMaterial properties: - * - * | Property | Type | Range | Default Value | Space | Description | - * |:--------:|:----:|:-----:|:-------------:|:-----:|:-----------:| - * | {@link LambertMaterial#ambient} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the ambient light reflected by the material. | - * | {@link LambertMaterial#color} | Array | [0, 1] for all components | [1,1,1,1] | linear | The RGB components of the diffuse light reflected by the material. | - * | {@link LambertMaterial#emissive} | Array | [0, 1] for all components | [0,0,0] | linear | The RGB components of the light emitted by the material. | - * | {@link LambertMaterial#alpha} | Number | [0, 1] | 1 | linear | The transparency of the material surface (0 fully transparent, 1 fully opaque). | - * | {@link LambertMaterial#lineWidth} | Number | [0..100] | 1 | | Line width in pixels. | - * | {@link LambertMaterial#pointSize} | Number | [0..100] | 1 | | Point size in pixels. | - * | {@link LambertMaterial#backfaces} | Boolean | | false | | Whether to render {@link Geometry} backfaces. | - * | {@link LambertMaterial#frontface} | String | "ccw", "cw" | "ccw" | | The winding order for {@link Geometry} frontfaces - "cw" for clockwise, or "ccw" for counter-clockwise. | - * - */ -class LambertMaterial extends Material { + _objectToNodeID(objectId) { + return this._baseId + objectId; + } /** - @private + * @private + * @param depth */ - get type() { - return "LambertMaterial"; + setAutoExpandDepth(depth = 0) { + this._autoExpandDepth = depth; } /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] The LambertMaterial configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {String:Object} [cfg.meta=null] Metadata to attach to this LambertMaterial. - * @param {Number[]} [cfg.ambient=[1.0, 1.0, 1.0 ]] LambertMaterial ambient color. - * @param {Number[]} [cfg.color=[ 1.0, 1.0, 1.0 ]] LambertMaterial diffuse color. - * @param {Number[]} [cfg.emissive=[ 0.0, 0.0, 0.0 ]] LambertMaterial emissive color. - * @param {Number} [cfg.alpha=1]Scalar in range 0-1 that controls alpha, where 0 is completely transparent and 1 is completely opaque. - * @param {Number} [cfg.reflectivity=1]Scalar in range 0-1 that controls how much {@link ReflectionMap} is reflected. - * @param {Number} [cfg.lineWidth=1] Scalar that controls the width of {@link Geometry} lines. - * @param {Number} [cfg.pointSize=1] Scalar that controls the size of points for {@link Geometry} with {@link Geometry#primitive} set to "points". - * @param {Boolean} [cfg.backfaces=false] Whether to render {@link Geometry} backfaces. - * @param {Boolean} [cfg.frontface="ccw"] The winding order for {@link Geometry} front faces - "cw" for clockwise, or "ccw" for counter-clockwise. + * @private + * @param hierarchy */ - constructor(owner, cfg = {}) { - - super(owner, cfg); + setHierarchy(hierarchy) { + if (this._hierarchy === hierarchy) { + return; + } + this._hierarchy = hierarchy; + this._createNodes(); + } - this._state = new RenderState({ - type: "LambertMaterial", - ambient: math.vec3([1.0, 1.0, 1.0]), - color: math.vec3([1.0, 1.0, 1.0]), - emissive: math.vec3([0.0, 0.0, 0.0]), - alpha: null, - alphaMode: 0, // 2 ("blend") when transparent, so renderer knows when to add to transparency bin - lineWidth: null, - pointSize: null, - backfaces: null, - frontface: null, // Boolean for speed; true == "ccw", false == "cw" - hash: "/lam;" - }); + _createNodes() { + if (this._rootElement) { + this._rootElement.parentNode.removeChild(this._rootElement); + this._rootElement = null; + } + this._rootNodes = []; + this._objectNodes = {}; + this._validate(); + if (this.valid || (this._hierarchy !== "storeys")) { + this._createEnabledNodes(); + } else { + this._createDisabledNodes(); + } + } - this.ambient = cfg.ambient; - this.color = cfg.color; - this.emissive = cfg.emissive; - this.alpha = cfg.alpha; - this.lineWidth = cfg.lineWidth; - this.pointSize = cfg.pointSize; - this.backfaces = cfg.backfaces; - this.frontface = cfg.frontface; + _validate() { + this.errors = []; + switch (this._hierarchy) { + case "storeys": + this.valid = validateMetaModelForTreeViewStoreysHierarchy(this.metaModel, this.errors); + break; + case "types": + this.valid = validateMetaModelForTreeViewTypesHierarchy(this.metaModel, this.errors); + break; + case "containment": + default: + this.valid = validateMetaModelForTreeViewContainmentHierarchy(this.metaModel, this.errors); + break; + } + return this.valid; } - /** - * Sets the LambertMaterial's ambient color. - * - * Default value is ````[0.3, 0.3, 0.3]````. - * - * @type {Number[]} - */ - set ambient(value) { - let ambient = this._state.ambient; - if (!ambient) { - ambient = this._state.ambient = new Float32Array(3); - } else if (value && ambient[0] === value[0] && ambient[1] === value[1] && ambient[2] === value[2]) { - return; + _createEnabledNodes() { + if (this._pruneEmptyNodes) { + this._findEmptyNodes(); } - if (value) { - ambient[0] = value[0]; - ambient[1] = value[1]; - ambient[2] = value[2]; - } else { - ambient[0] = .2; - ambient[1] = .2; - ambient[2] = .2; + switch (this._hierarchy) { + case "storeys": + this._createStoreysNodes(); + if (this._rootNodes.length === 0) { + this._treeViewPlugin.error("Failed to build storeys hierarchy for model '" + this.metaModel.id + "' - perhaps this model is not an IFC model?"); + } + break; + case "types": + this._createTypesNodes(); + break; + case "containment": + default: + this._createContainmentNodes(); } - this.glRedraw(); + if (this._sortNodes) { + this._doSortNodes(); + } + this._synchNodesToEntities(); + this._createTrees(); + this.expandToDepth(this._autoExpandDepth); } - /** - * Gets the LambertMaterial's ambient color. - * - * Default value is ````[0.3, 0.3, 0.3]````. - * - * @type {Number[]} - */ - get ambient() { - return this._state.ambient; + _createDisabledNodes() { + + const metaObject = this._rootMetaObject; + const metaObjectType = metaObject.type; + const metaObjectName = metaObject.name; + + const rootName = ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType); + + const ul = document.createElement('ul'); + const li = document.createElement('li'); + ul.appendChild(li); + this._containerElement.appendChild(ul); + this._rootElement = ul; + + const switchElement = document.createElement('a'); + switchElement.href = '#'; + switchElement.textContent = '!'; + switchElement.classList.add('warn'); + switchElement.classList.add('warning'); + li.appendChild(switchElement); + + const span = document.createElement('span'); + span.textContent = rootName; + li.appendChild(span); } - /** - * Sets the LambertMaterial's diffuse color. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @type {Number[]} - */ - set color(value) { - let color = this._state.color; - if (!color) { - color = this._state.color = new Float32Array(3); - } else if (value && color[0] === value[0] && color[1] === value[1] && color[2] === value[2]) { + _findEmptyNodes(metaObject = this._rootMetaObject, countEntities = 0) { + const viewer = this._treeViewPlugin.viewer; + const scene = viewer.scene; + const children = metaObject.children; + const objectId = metaObject.id; + const entity = scene.objects[objectId]; + metaObject._countEntities = 0; + if (entity) { + metaObject._countEntities++; + } + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + const childMetaObject = children[i]; + childMetaObject._countEntities = this._findEmptyNodes(childMetaObject); + metaObject._countEntities += childMetaObject._countEntities; + } + } + return metaObject._countEntities; + } + + _createStoreysNodes( + metaObject = this._rootMetaObject, + buildingNode, + storeyNode, + typeNodes) { + if (this._pruneEmptyNodes && (metaObject._countEntities === 0)) { return; } - if (value) { - color[0] = value[0]; - color[1] = value[1]; - color[2] = value[2]; + const metaObjectType = metaObject.type; + const metaObjectName = metaObject.name; + const children = metaObject.children; + const objectId = metaObject.id; + if (metaObjectType === "IfcBuilding") { + buildingNode = { + nodeId: this._objectToNodeID(objectId), + objectId: objectId, + title: this._rootName || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType), + type: metaObjectType, + parent: null, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + this._rootNodes.push(buildingNode); + this._objectNodes[buildingNode.objectId] = buildingNode; + } else if (metaObjectType === "IfcBuildingStorey") { + if (!buildingNode) { + this._treeViewPlugin.error("Failed to build storeys hierarchy for model '" + this.metaModel.id + "' - model does not have an IfcBuilding object, or is not an IFC model"); + return; + } + storeyNode = { + nodeId: this._objectToNodeID(objectId), + objectId: objectId, + title: (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, + type: metaObjectType, + parent: buildingNode, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + buildingNode.children.push(storeyNode); + this._objectNodes[storeyNode.objectId] = storeyNode; + typeNodes = {}; } else { - color[0] = 1; - color[1] = 1; - color[2] = 1; + if (storeyNode) { + const objects = this._viewer.scene.objects; + const object = objects[objectId]; + if (object) { + typeNodes = typeNodes || {}; + let typeNode = typeNodes[metaObjectType]; + if (!typeNode) { + const typeNodeObjectId = storeyNode.objectId + "." + metaObjectType; + const typeNodeNodeId = this._objectToNodeID(typeNodeObjectId); + typeNode = { + nodeId: typeNodeNodeId, + objectId: typeNodeObjectId, + title: metaObjectType, + type: metaObjectType, + parent: storeyNode, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + storeyNode.children.push(typeNode); + this._objectNodes[typeNodeObjectId] = typeNode; + typeNodes[metaObjectType] = typeNode; + } + const node = { + nodeId: this._objectToNodeID(objectId), + objectId: objectId, + title: (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, + type: metaObjectType, + parent: typeNode, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + typeNode.children.push(node); + this._objectNodes[node.objectId] = node; + } + } + } + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + const childMetaObject = children[i]; + this._createStoreysNodes(childMetaObject, buildingNode, storeyNode, typeNodes); + } } - this.glRedraw(); } - /** - * Gets the LambertMaterial's diffuse color. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @type {Number[]} - */ - get color() { - return this._state.color; + _createTypesNodes(metaObject = this._rootMetaObject, rootNode, typeNodes) { + if (this._pruneEmptyNodes && (metaObject._countEntities === 0)) { + return; + } + const metaObjectType = metaObject.type; + const metaObjectName = metaObject.name; + const children = metaObject.children; + const objectId = metaObject.id; + if (metaObject.id === this._rootMetaObject.id) { + rootNode = { + nodeId: this._objectToNodeID(objectId), + objectId: objectId, + title: this._rootName || ((metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType), + type: metaObjectType, + parent: null, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + this._rootNodes.push(rootNode); + this._objectNodes[rootNode.objectId] = rootNode; + typeNodes = {}; + } else { + if (rootNode) { + const objects = this._viewer.scene.objects; + const object = objects[objectId]; + if (object) { + let typeNode = typeNodes[metaObjectType]; + if (!typeNode) { + typeNode = { + nodeId: this._objectToNodeID(rootNode.objectId + "." + metaObjectType), + objectId: rootNode.objectId + "." + metaObjectType, + title: metaObjectType, + type: metaObjectType, + parent: rootNode, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + rootNode.children.push(typeNode); + this._objectNodes[typeNode.objectId] = typeNode; + typeNodes[metaObjectType] = typeNode; + } + const node = { + nodeId: this._objectToNodeID(objectId), + objectId: objectId, + title: (metaObjectName && metaObjectName !== "" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, + type: metaObjectType, + parent: typeNode, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + typeNode.children.push(node); + this._objectNodes[node.objectId] = node; + } + } + } + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + const childMetaObject = children[i]; + this._createTypesNodes(childMetaObject, rootNode, typeNodes); + } + } } - /** - * Sets the LambertMaterial's emissive color. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @type {Number[]} - */ - set emissive(value) { - let emissive = this._state.emissive; - if (!emissive) { - emissive = this._state.emissive = new Float32Array(3); - } else if (value && emissive[0] === value[0] && emissive[1] === value[1] && emissive[2] === value[2]) { + _createContainmentNodes(metaObject = this._rootMetaObject, parent) { + if (this._pruneEmptyNodes && (metaObject._countEntities === 0)) { return; } - if (value) { - emissive[0] = value[0]; - emissive[1] = value[1]; - emissive[2] = value[2]; + const metaObjectType = metaObject.type; + const metaObjectName = metaObject.name || metaObjectType; + const children = metaObject.children; + const objectId = metaObject.id; + const node = { + nodeId: this._objectToNodeID(objectId), + objectId: objectId, + title: (!parent) ? (this._rootName || metaObjectName) : (metaObjectName && metaObjectName !== "" && metaObjectName !== "Undefined" && metaObjectName !== "Default") ? metaObjectName : metaObjectType, + type: metaObjectType, + parent: parent, + numEntities: 0, + numVisibleEntities: 0, + checked: false, + children: [] + }; + if (parent) { + parent.children.push(node); } else { - emissive[0] = 0; - emissive[1] = 0; - emissive[2] = 0; + this._rootNodes.push(node); + } + this._objectNodes[node.objectId] = node; + + if (children) { + for (let i = 0, len = children.length; i < len; i++) { + const childMetaObject = children[i]; + this._createContainmentNodes(childMetaObject, node); + } } - this.glRedraw(); } - /** - * Gets the LambertMaterial's emissive color. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @type {Number[]} - */ - get emissive() { - return this._state.emissive; + _doSortNodes() { + for (let i = 0, len = this._rootNodes.length; i < len; i++) { + const rootNode = this._rootNodes[i]; + this._sortChildren(rootNode); + } } - /** - * Sets factor in the range ````[0..1]```` indicating how transparent the LambertMaterial is. - * - * A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. - * - * Default value is ````1.0```` - * - * @type {Number} - */ - set alpha(value) { - value = (value !== undefined && value !== null) ? value : 1.0; - if (this._state.alpha === value) { + _sortChildren(node) { + const children = node.children; + if (!children || children.length === 0) { return; } - this._state.alpha = value; - this._state.alphaMode = value < 1.0 ? 2 /* blend */ : 0; - /* opaque */ - this.glRedraw(); + if (this._hierarchy === "storeys" && node.type === "IfcBuilding") { + // Assumes that children of an IfcBuilding will always be IfcBuildingStoreys + children.sort(this._getSpatialSortFunc()); + } else { + children.sort(this._alphaSortFunc); + } + for (let i = 0, len = children.length; i < len; i++) { + const node = children[i]; + this._sortChildren(node); + } } - /** - * Gets factor in the range ````[0..1]```` indicating how transparent the LambertMaterial is. - * - * A value of ````0.0```` indicates fully transparent, ````1.0```` is fully opaque. - * - * Default value is ````1.0```` - * - * @type {Number} - */ - get alpha() { - return this._state.alpha; + _getSpatialSortFunc() { // Creates cached sort func with Viewer in scope + const viewer = this._treeViewPlugin.viewer; + const scene = viewer.scene; + const camera = scene.camera; + const metaScene = viewer.metaScene; + return this._spatialSortFunc || (this._spatialSortFunc = (node1, node2) => { + if (!node1.aabb || !node2.aabb) { + // Sorting on lowest point of the AABB is likely more more robust when objects could overlap storeys + if (!node1.aabb) { + node1.aabb = scene.getAABB(metaScene.getObjectIDsInSubtree(node1.objectId)); + } + if (!node2.aabb) { + node2.aabb = scene.getAABB(metaScene.getObjectIDsInSubtree(node2.objectId)); + } + } + let idx = 0; + if (camera.xUp) { + idx = 0; + } else if (camera.yUp) { + idx = 1; + } else { + idx = 2; + } + if (node1.aabb[idx] > node2.aabb[idx]) { + return -1; + } + if (node1.aabb[idx] < node2.aabb[idx]) { + return 1; + } + return 0; + }); } - /** - * Sets the LambertMaterial's line width. - * - * This is not supported by WebGL implementations based on DirectX [2019]. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set lineWidth(value) { - this._state.lineWidth = value || 1.0; - this.glRedraw(); + _alphaSortFunc(node1, node2) { + const title1 = node1.title.toUpperCase(); // FIXME: Should be case sensitive? + const title2 = node2.title.toUpperCase(); + if (title1 < title2) { + return -1; + } + if (title1 > title2) { + return 1; + } + return 0; } - /** - * Gets the LambertMaterial's line width. - * - * This is not supported by WebGL implementations based on DirectX [2019]. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - get lineWidth() { - return this._state.lineWidth; + _synchNodesToEntities() { + const rootMetaObject = this._rootMetaObject; + const objectIds = rootMetaObject.getObjectIDsInSubtree(); + const metaObjects = this._viewer.metaScene.metaObjects; + const objects = this._viewer.scene.objects; + for (let i = 0, len = objectIds.length; i < len; i++) { + const objectId = objectIds[i]; + const metaObject = metaObjects[objectId]; + if (metaObject) { + const node = this._objectNodes[objectId]; + if (node) { + const entity = objects[objectId]; + if (entity) { + const visible = entity.visible; + node.numEntities = 1; + if (visible) { + node.numVisibleEntities = 1; + node.checked = true; + } else { + node.numVisibleEntities = 0; + node.checked = false; + } + let parent = node.parent; // Synch parents + while (parent) { + parent.numEntities++; + if (visible) { + parent.numVisibleEntities++; + parent.checked = true; + } + parent = parent.parent; + } + } + } + } + } } - /** - * Sets the LambertMaterial's point size. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - set pointSize(value) { - this._state.pointSize = value || 1.0; - this.glRedraw(); + _withNodeTree(node, callback) { + callback(node); + const children = node.children; + if (!children) { + return; + } + for (let i = 0, len = children.length; i < len; i++) { + this._withNodeTree(children[i], callback); + } } - /** - * Gets the LambertMaterial's point size. - * - * Default value is ````1.0````. - * - * @type {Number} - */ - get pointSize() { - return this._state.pointSize; + _createTrees() { + if (this._rootNodes.length === 0) { + return; + } + const rootNodeElements = this._rootNodes.map((rootNode) => { + return this._createNodeElement(rootNode); + }); + const ul = document.createElement('ul'); + rootNodeElements.forEach((nodeElement) => { + ul.appendChild(nodeElement); + }); + this._containerElement.appendChild(ul); + this._rootElement = ul; } - /** - * Sets whether backfaces are visible on attached {@link Mesh}es. - * - * @type {Boolean} - */ - set backfaces(value) { - value = !!value; - if (this._state.backfaces === value) { - return; + _createNodeElement(node) { + const nodeElement = document.createElement('li'); + //const nodeId = this._objectToNodeID(node.objectId); + const nodeId = node.nodeId; + nodeElement.id = 'node-' + nodeId; + if (node.children.length > 0) { + const switchElementId = "switch-" + nodeId; + const switchElement = document.createElement('a'); + switchElement.href = '#'; + switchElement.id = switchElementId; + switchElement.textContent = '+'; + switchElement.classList.add('plus'); + switchElement.addEventListener('click', this.switchExpandHandler); + nodeElement.appendChild(switchElement); } - this._state.backfaces = value; - this.glRedraw(); + const checkbox = document.createElement('input'); + checkbox.id = nodeId; + checkbox.type = "checkbox"; + checkbox.checked = node.checked; + checkbox.style["pointer-events"] = "all"; + checkbox.addEventListener("change", this._checkboxChangeHandler); + nodeElement.appendChild(checkbox); + const span = document.createElement('span'); + span.textContent = node.title; + nodeElement.appendChild(span); + span.oncontextmenu = (e) => { + this._treeViewPlugin.fire("contextmenu", { + event: e, + viewer: this._viewer, + treeViewPlugin: this._treeViewPlugin, + treeViewNode: node + }); + e.preventDefault(); + }; + span.onclick = (e) => { + this._treeViewPlugin.fire("nodeTitleClicked", { + event: e, + viewer: this._viewer, + treeViewPlugin: this._treeViewPlugin, + treeViewNode: node + }); + e.preventDefault(); + }; + return nodeElement; } /** - * Gets whether backfaces are visible on attached {@link Mesh}es. - * - * @type {Boolean} + * @private + * @param depth */ - get backfaces() { - return this._state.backfaces; + expandToDepth(depth) { + const expand = (node, countDepth) => { + if (countDepth === depth) { + return; + } + const nodeId = node.nodeId; + const switchElementId = "switch-" + nodeId; + const switchElement = document.getElementById(switchElementId); + if (switchElement) { + this._expandSwitchElement(switchElement); + const childNodes = node.children; + for (var i = 0, len = childNodes.length; i < len; i++) { + const childNode = childNodes[i]; + expand(childNode, countDepth + 1); + } + } + }; + for (let i = 0, len = this._rootNodes.length; i < len; i++) { + const rootNode = this._rootNodes[i]; + expand(rootNode, 0); + } } /** - * Sets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. - * - * Default value is ````"ccw"````. - * - * @type {String} + * @private */ - set frontface(value) { - value = value !== "cw"; - if (this._state.frontface === value) { - return; + collapse() { + for (let i = 0, len = this._rootNodes.length; i < len; i++) { + const rootNode = this._rootNodes[i]; + const objectId = rootNode.objectId; + this._collapseNode(objectId); } - this._state.frontface = value; - this.glRedraw(); } /** - * Gets the winding direction of front faces of {@link Geometry} of attached {@link Mesh}es. - * - * Default value is ````"ccw"````. - * - * @type {String} + * @private + * @param objectId */ - get frontface() { - return this._state.frontface ? "ccw" : "cw"; - } - - _getState() { - return this._state; + showNode(objectId) { + if (this._showListItemElementId) { + this.unShowNode(); + } + const node = this._objectNodes[objectId]; + if (!node) { + return; // Node may not exist for the given object if (this._pruneEmptyNodes == true) + } + const nodeId = node.nodeId; + const switchElementId = "switch-" + nodeId; + const switchElement = document.getElementById(switchElementId); + if (switchElement) { + this._expandSwitchElement(switchElement); + switchElement.scrollIntoView(); + return; + } + const path = []; + path.unshift(node); + let parent = node.parent; + while (parent) { + path.unshift(parent); + parent = parent.parent; + } + for (let i = 0, len = path.length; i < len; i++) { + const node = path[i]; + const nodeId = node.nodeId; + const switchElementId = "switch-" + nodeId; + const switchElement = document.getElementById(switchElementId); + if (switchElement) { + this._expandSwitchElement(switchElement); + } + } + const listItemElementId = 'node-' + nodeId; + const listItemElement = document.getElementById(listItemElementId); + listItemElement.scrollIntoView({block: "center"}); + listItemElement.classList.add("highlighted-node"); + this._showListItemElementId = listItemElementId; } /** - * Destroys this LambertMaterial. + * @private */ - destroy() { - super.destroy(); - this._state.destroy(); - } -} - -/* - Copyright (c) 2013 Gildas Lormeau. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. - - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, - INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @private - * @type {{}} - */ -var zipLib = {}; - -(function (obj) { - - var ERR_BAD_FORMAT = "File format is not recognized."; - var ERR_CRC = "CRC failed."; - var ERR_ENCRYPTED = "File contains encrypted entry."; - var ERR_ZIP64 = "File is using Zip64 (4gb+ file size)."; - var ERR_READ = "Error while reading zip file."; - var ERR_WRITE = "Error while writing zip file."; - var ERR_WRITE_DATA = "Error while writing file data."; - var ERR_READ_DATA = "Error while reading file data."; - var ERR_DUPLICATED_NAME = "File already exists."; - var CHUNK_SIZE = 512 * 1024; - - var TEXT_PLAIN = "text/plain"; - - var appendABViewSupported; - try { - appendABViewSupported = new Blob([new DataView(new ArrayBuffer(0))]).size === 0; - } catch (e) { - } - - function Crc32() { - this.crc = -1; - } - - Crc32.prototype.append = function append(data) { - var crc = this.crc | 0, table = this.table; - for (var offset = 0, len = data.length | 0; offset < len; offset++) - crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]; - this.crc = crc; - }; - Crc32.prototype.get = function get() { - return ~this.crc; - }; - Crc32.prototype.table = (function () { - var i, j, t, table = []; // Uint32Array is actually slower than [] - for (i = 0; i < 256; i++) { - t = i; - for (j = 0; j < 8; j++) - if (t & 1) - t = (t >>> 1) ^ 0xEDB88320; - else - t = t >>> 1; - table[i] = t; + unShowNode() { + if (!this._showListItemElementId) { + return; } - return table; - })(); - - // "no-op" codec - function NOOP() { - } - - NOOP.prototype.append = function append(bytes, onprogress) { - return bytes; - }; - NOOP.prototype.flush = function flush() { - }; - - function blobSlice(blob, index, length) { - if (index < 0 || length < 0 || index + length > blob.size) - throw new RangeError('offset:' + index + ', length:' + length + ', size:' + blob.size); - if (blob.slice) - return blob.slice(index, index + length); - else if (blob.webkitSlice) - return blob.webkitSlice(index, index + length); - else if (blob.mozSlice) - return blob.mozSlice(index, index + length); - else if (blob.msSlice) - return blob.msSlice(index, index + length); + const listItemElement = document.getElementById(this._showListItemElementId); + if (!listItemElement) { + this._showListItemElementId = null; + return; + } + listItemElement.classList.remove("highlighted-node"); + this._showListItemElementId = null; } - function getDataHelper(byteLength, bytes) { - var dataBuffer, dataArray; - dataBuffer = new ArrayBuffer(byteLength); - dataArray = new Uint8Array(dataBuffer); - if (bytes) - dataArray.set(bytes, 0); - return { - buffer: dataBuffer, - array: dataArray, - view: new DataView(dataBuffer) - }; + _expandSwitchElement(switchElement) { + const parentElement = switchElement.parentElement; + const expanded = parentElement.getElementsByTagName('li')[0]; + if (expanded) { + return; + } + const nodeId = parentElement.id.replace('node-', ''); + const objectId = this._nodeToObjectID(nodeId); + const switchNode = this._objectNodes[objectId]; + const childNodes = switchNode.children; + const nodeElements = childNodes.map((node) => { + return this._createNodeElement(node); + }); + const ul = document.createElement('ul'); + nodeElements.forEach((nodeElement) => { + ul.appendChild(nodeElement); + }); + parentElement.appendChild(ul); + switchElement.classList.remove('plus'); + switchElement.classList.add('minus'); + switchElement.textContent = '-'; + switchElement.removeEventListener('click', this.switchExpandHandler); + switchElement.addEventListener('click', this.switchCollapseHandler); } - // Readers - function Reader() { + _collapseNode(objectId) { + const nodeId = this._objectToNodeID(objectId); + const switchElementId = "switch-" + nodeId; + const switchElement = document.getElementById(switchElementId); + this._collapseSwitchElement(switchElement); } - function TextReader(text) { - var that = this, blobReader; - - function init(callback, onerror) { - var blob = new Blob([text], { - type: TEXT_PLAIN - }); - blobReader = new BlobReader(blob); - blobReader.init(function () { - that.size = blobReader.size; - callback(); - }, onerror); - } - - function readUint8Array(index, length, callback, onerror) { - blobReader.readUint8Array(index, length, callback, onerror); + _collapseSwitchElement(switchElement) { + if (!switchElement) { + return; } - - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } - - TextReader.prototype = new Reader(); - TextReader.prototype.constructor = TextReader; - - function Data64URIReader(dataURI) { - var that = this, dataStart; - - function init(callback) { - var dataEnd = dataURI.length; - while (dataURI.charAt(dataEnd - 1) == "=") - dataEnd--; - dataStart = dataURI.indexOf(",") + 1; - that.size = Math.floor((dataEnd - dataStart) * 0.75); - callback(); + const parent = switchElement.parentElement; + if (!parent) { + return; } - - function readUint8Array(index, length, callback) { - var i, data = getDataHelper(length); - var start = Math.floor(index / 3) * 4; - var end = Math.ceil((index + length) / 3) * 4; - var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart)); - var delta = index - Math.floor(start / 4) * 3; - for (i = delta; i < delta + length; i++) - data.array[i - delta] = bytes.charCodeAt(i); - callback(data.array); + const ul = parent.querySelector('ul'); + if (!ul) { + return; } - - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; + parent.removeChild(ul); + switchElement.classList.remove('minus'); + switchElement.classList.add('plus'); + switchElement.textContent = '+'; + switchElement.removeEventListener('click', this.switchCollapseHandler); + switchElement.addEventListener('click', this.switchExpandHandler); } - Data64URIReader.prototype = new Reader(); - Data64URIReader.prototype.constructor = Data64URIReader; - - function BlobReader(blob) { - var that = this; - - function init(callback) { - that.size = blob.size; - callback(); - } - - function readUint8Array(index, length, callback, onerror) { - var reader = new FileReader(); - reader.onload = function (e) { - callback(new Uint8Array(e.target.result)); - }; - reader.onerror = onerror; - try { - reader.readAsArrayBuffer(blobSlice(blob, index, length)); - } catch (e) { - onerror(e); - } + /** + * Destroys this ModelTreeView. + * @private + */ + destroy() { + if (this._rootElement && !this._destroyed) { + this._rootElement.parentNode.removeChild(this._rootElement); + this._viewer.scene.off(this._onObjectVisibility); + this._destroyed = true; + idMap.removeItem(this._id); } - - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } - - BlobReader.prototype = new Reader(); - BlobReader.prototype.constructor = BlobReader; - - // Writers - - function Writer() { } +} - Writer.prototype.getData = function (callback) { - callback(this.data); - }; - - function TextWriter(encoding) { - var that = this, blob; +/** + * @desc A {@link Viewer} plugin that provides an HTML tree view to navigate the IFC elements in models. + *
    + * + * + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_WestRiverSideHospital)] + * + * ## Overview + * + * * A fast HTML tree view, with zero external dependencies, that works with huge numbers of objects. + * * Each tree node has a checkbox to control the visibility of its object. + * * Has three hierarchy modes: "containment", "types" and "storeys". + * * Automatically contains all models (that have metadata) that are currently in the {@link Scene}. + * * Sorts tree nodes by default - spatially, from top-to-bottom for ````IfcBuildingStorey```` nodes, and alphanumerically for other nodes. + * * Allows custom CSS styling. + * * Use {@link ContextMenu} to create a context menu for the tree nodes. + * + * ## Credits + * + * TreeViewPlugin is based on techniques described in [*Super Fast Tree View in JavaScript*](https://chrissmith.xyz/super-fast-tree-view-in-javascript/) by [Chris Smith](https://twitter.com/chris22smith). + * + * ## Usage + * + * In the example below, we'll add a TreeViewPlugin which, by default, will automatically show the structural + * hierarchy of the IFC elements in each model we load. + * + * Then we'll use an {@link XKTLoaderPlugin} to load the Schependomlaan model from an + * [.xkt file](https://github.com/xeokit/xeokit-sdk/tree/master/examples/models/xkt/schependomlaan). + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_Schependomlaan)] + * + * ````javascript + * import {Viewer, XKTLoaderPlugin, TreeViewPlugin} from "xeokit-sdk.es.js"; + * + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [-2.56, 8.38, 8.27]; + * viewer.camera.look = [13.44, 3.31, -14.83]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer") + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true + * }); + * ```` + * + * ## Manually Adding Models + * + * Instead of adding models automatically, we can control which models appear in our TreeViewPlugin by adding them manually. + * + * In the next example, we'll configure the TreeViewPlugin to not add models automatically. Then, once the model + * has loaded, we'll add it manually using {@link TreeViewPlugin#addModel}. + * + * ````javascript + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer"), + * autoAddModels: false // <<---------------- Don't auto-add models + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true + * }); + * + * model.on("loaded", () => { + * treeView.addModel(model.id); + * }); + * ```` + * + * Adding models manually also allows us to set some options for the model. For example, the ````rootName```` option allows us to provide a custom name for + * the root node, which is sometimes desirable when the model's "IfcProject" element's name is not suitable: + * + * ````javascript + * model.on("loaded", () => { + * treeView.addModel(model.id, { + * rootName: "Schependomlaan Model" + * }); + * }); + * ```` + * + * ## Initially Expanding the Hierarchy + * + * We can also configure TreeViewPlugin to initially expand each model's nodes to a given depth. + * + * Let's automatically expand the first three nodes from the root, for every model added: + * + * ````javascript + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer"), + * autoExpandDepth: 3 + * }); + * ```` + * + * ## Showing a Node by ID + * + * We can show a given node using its ID. This causes the TreeViewPlugin to collapse, then expand and scroll the node into view, then highlight the node. + * + * See the documentation for the {@link TreeViewPlugin#showNode} method for more information, including how to define a custom highlighted appearance for the node using CSS. + * + * Let's make the TreeViewPlugin show the node corresponding to whatever object {@link Entity} that we pick: + * + * ````javascript + * viewer.cameraControl.on("picked", function (e) { + * var objectId = e.entity.id; + * treeView.showNode(objectId); + * }); + * ```` + * + * This will de-highlight any node that was previously shown by this method. + * + * Note that this method only works if the picked {@link Entity} is an object that belongs to a model that's represented in the TreeViewPlugin. + * + * ## Customizing Appearance + * + * We can customize the appearance of our TreeViewPlugin by defining custom CSS for its HTML + * elements. See our example's [source code](https://github.com/xeokit/xeokit-sdk/blob/master/examples/BIMOffline_XKT_Schependomlaan.html) + * for an example of custom CSS rules. + * + * ## Model Hierarchies + * + * TreeViewPlugin has three hierarchies for organizing its nodes: + * + * * "containment" - organizes the tree nodes to indicate the containment hierarchy of the {@link MetaObject}s. + * * "types" - groups nodes by their IFC types. + * * "storeys" - groups nodes within their ````IfcBuildingStoreys````, and sub-groups them by their IFC types. + * + *
    + * The table below shows what the hierarchies look like: + *
    + * + * | 1. Containment Hierarchy | 2. Types Hierarchy | 3. Storeys Hierarchy | + * |---|---|---| + * | | | | + *
    + * + * Let's create a TreeViewPlugin that groups nodes by their building stories and IFC types: + * + * ````javascript + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer"), + * hierarchy: "stories" + * }); + * ```` + * + * ## Sorting Nodes + * + * TreeViewPlugin sorts its tree nodes by default. For a "storeys" hierarchy, it orders ````IfcBuildingStorey```` nodes + * spatially, with the node for the highest story at the top, down to the lowest at the bottom. + * + * For all the hierarchy types ("containment", "classes" and "storeys"), TreeViewPlugin sorts the other node types + * alphanumerically on their titles. + * + * If for some reason you need to prevent sorting, create your TreeViewPlugin with the option disabled, like so: + * + * ````javascript + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer"), + * hierarchy: "stories", + * sortNodes: false // <<------ Disable node sorting + * }); + * ```` + * + * Note that, for all hierarchy modes, node sorting is only done for each model at the time that it is added to the TreeViewPlugin, and will not + * update dynamically if we later transform the {@link Entity}s corresponding to the nodes. + * + * ## Pruning empty nodes + * + * Sometimes a model contains subtrees of objects that don't have any geometry. These are models whose + * {@link MetaModel} contains trees of {@link MetaObject}s that don't have any {@link Entity}s in the {@link Scene}. + * + * For these models, the tree view would contain nodes that don't do anything in the Scene when we interact with them, + * which is undesirable. + * + * By default, TreeViewPlugin will not create nodes for those objects. However, we can override that behaviour if we want + * to have nodes for those objects (perhaps for debugging the model): + * + * ````javascript + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer"), + * hierarchy: "stories", + * pruneEmptyNodes: false // <<------ Create nodes for object subtrees without geometry + * }); + * ```` + * + * ## Context Menu + * + * TreeViewPlugin fires a "contextmenu" event whenever we right-click on a tree node. + * + * The event contains: + * + * * ````event```` - the original [contextmenu](https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event) [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) + * * ````viewer```` - the {@link Viewer} + * * ````treeViewPlugin```` - the TreeViewPlugin + * * ````treeViewNode```` - the {@link TreeViewNode} representing the tree node + *

    + * + * Let's use {@link ContextMenu} to show a simple context menu for the node we clicked. + * + * [[Run an example](https://xeokit.github.io/xeokit-sdk/examples/#ContextMenu_Canvas_TreeViewPlugin_Custom)] + * + * ````javascript + * import {ContextMenu} from "../src/extras/ContextMenu/ContextMenu.js"; + * + * const treeViewContextMenu = new ContextMenu({ + * items: [ + * [ + * [ + * { + * title: "Hide", + * doAction: function (context) { + * context.treeViewPlugin.withNodeTree(context.treeViewNode, (treeViewNode) => { + * if (treeViewNode.objectId) { + * const entity = context.viewer.scene.objects[treeViewNode.objectId]; + * if (entity) { + * entity.visible = false; + * } + * } + * }); + * } + * }, + * { + * title: "Hide all", + * doAction: function (context) { + * context.viewer.scene.setObjectsVisible(context.viewer.scene.visibleObjectIds, false); + * } + * } + * ], + * [ + * { + * title: "Show", + * doAction: function (context) { + * context.treeViewPlugin.withNodeTree(context.treeViewNode, (treeViewNode) => { + * if (treeViewNode.objectId) { + * const entity = context.viewer.scene.objects[treeViewNode.objectId]; + * if (entity) { + * entity.visible = true; + * entity.xrayed = false; + * entity.selected = false; + * } + * } + * }); + * } + * }, + * { + * title: "Show all", + * doAction: function (context) { + * const scene = context.viewer.scene; + * scene.setObjectsVisible(scene.objectIds, true); + * scene.setObjectsXRayed(scene.xrayedObjectIds, false); + * scene.setObjectsSelected(scene.selectedObjectIds, false); + * } + * } + * ] + * ] + * ] + * }); + * + * treeView.on("contextmenu", (e) => { + * + * const event = e.event; // MouseEvent + * const viewer = e.viewer; // Viewer + * const treeViewPlugin = e.treeViewPlugin; // TreeViewPlugin + * const treeViewNode = e.treeViewNode; // TreeViewNode + * + * treeViewContextMenu.show(e.event.pageX, e.event.pageY); + * + * treeViewContextMenu.context = { + * viewer: e.viewer, + * treeViewPlugin: e.treeViewPlugin, + * treeViewNode: e.treeViewNode + * }; + * }); + * ```` + * + * ## Clicking Node Titles + * + * TreeViewPlugin fires a "nodeTitleClicked" event whenever we left-click on a tree node. + * + * Like the "contextmenu" event, this event contains: + * + * * ````event```` - the original [click](https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event) [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent) + * * ````viewer```` - the {@link Viewer} + * * ````treeViewPlugin```` - the TreeViewPlugin + * * ````treeViewNode```` - the {@link TreeViewNode} representing the tree node + *

    + * + * Let's register a callback to isolate and fit-to-view the {@link Entity}(s) represented by the node. This callback is + * going to X-ray all the other Entitys, fly the camera to fit the Entity(s) for the clicked node, then hide the other Entitys. + * + * [[Run an example](https://xeokit.github.io/xeokit-sdk/examples/#ContextMenu_Canvas_TreeViewPlugin_Custom)] + * + * ````javascript + * treeView.on("nodeTitleClicked", (e) => { + * const scene = viewer.scene; + * const objectIds = []; + * e.treeViewPlugin.withNodeTree(e.treeViewNode, (treeViewNode) => { + * if (treeViewNode.objectId) { + * objectIds.push(treeViewNode.objectId); + * } + * }); + * scene.setObjectsXRayed(scene.objectIds, true); + * scene.setObjectsVisible(scene.objectIds, true); + * scene.setObjectsXRayed(objectIds, false); + * viewer.cameraFlight.flyTo({ + * aabb: scene.getAABB(objectIds), + * duration: 0.5 + * }, () => { + * setTimeout(function () { + * scene.setObjectsVisible(scene.xrayedObjectIds, false); + * scene.setObjectsXRayed(scene.xrayedObjectIds, false); + * }, 500); + * }); + * }); + * ```` + * + * To make the cursor change to a pointer when we hover over the node titles, and also to make the titles change to blue, we'll also define this CSS for the ```````` elements + * that represent the titles of our TreeViewPlugin nodes: + * + * ````css + * #treeViewContainer ul li span:hover { + * color: blue; + * cursor: pointer; + * } + * ```` + * + * @class TreeViewPlugin + */ +class TreeViewPlugin extends Plugin { - function init(callback) { - blob = new Blob([], { - type: TEXT_PLAIN - }); - callback(); + /** + * @constructor + * + * @param {Viewer} viewer The Viewer. + * @param {*} cfg Plugin configuration. + * @param {HTMLElement} cfg.containerElement DOM element to contain the TreeViewPlugin. + * @param {Boolean} [cfg.autoAddModels=true] When ````true```` (default), will automatically add each model as it's created. Set this ````false```` if you want to manually add models using {@link TreeViewPlugin#addModel} instead. + * @param {Number} [cfg.autoExpandDepth] Optional depth to which to initially expand the tree. + * @param {String} [cfg.hierarchy="containment"] How to organize the tree nodes: "containment", "storeys" or "types". See the class documentation for details. + * @param {Boolean} [cfg.sortNodes=true] When true, will sort the children of each node. For a "storeys" hierarchy, the + * ````IfcBuildingStorey```` nodes will be ordered spatially, from the highest storey down to the lowest, on the + * vertical World axis. For all hierarchy types, other node types will be ordered in the ascending alphanumeric order of their titles. + * @param {Boolean} [cfg.pruneEmptyNodes=true] When true, will not contain nodes that don't have content in the {@link Scene}. These are nodes whose {@link MetaObject}s don't have {@link Entity}s. + */ + constructor(viewer, cfg = {}) { + + super("TreeViewPlugin", viewer); + + if (!cfg.containerElement) { + this.error("Config expected: containerElement"); + return; } - function writeUint8Array(array, callback) { - blob = new Blob([blob, appendABViewSupported ? array : array.buffer], { - type: TEXT_PLAIN + this._containerElement = cfg.containerElement; + this._modelTreeViews = {}; + this._autoAddModels = (cfg.autoAddModels !== false); + this._autoExpandDepth = (cfg.autoExpandDepth || 0); + this._sortNodes = (cfg.sortNodes !== false); + this._pruneEmptyNodes = (cfg.pruneEmptyNodes !== false); + + if (this._autoAddModels) { + const modelIds = Object.keys(this.viewer.metaScene.metaModels); + for (let i = 0, len = modelIds.length; i < len; i++) { + const modelId = modelIds[i]; + this.addModel(modelId); + } + this.viewer.scene.on("modelLoaded", (modelId) => { + if (this.viewer.metaScene.metaModels[modelId]) { + this.addModel(modelId); + } }); - callback(); } - function getData(callback, onerror) { - var reader = new FileReader(); - reader.onload = function (e) { - callback(e.target.result); - }; - reader.onerror = onerror; - reader.readAsText(blob, encoding); - } + this.hierarchy = cfg.hierarchy; + } - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; + /** + * Returns the map of {@link ModelTreeView}s. + * + * Each ModelTreeView is mapped to the ID of its model. + * + * @return {*|{}} + */ + get modelTreeViews() { + return this._modelTreeViews; } - TextWriter.prototype = new Writer(); - TextWriter.prototype.constructor = TextWriter; + /** + * Sets how the nodes are organized within this tree view. + * + * Accepted values are: + * + * * "containment" - organizes the nodes to indicate the containment hierarchy of the IFC objects. + * * "types" - groups the nodes within their IFC types. + * * "storeys" - groups the nodes within ````IfcBuildingStoreys```` and sub-groups them by their IFC types. + * + *
    + * This can be updated dynamically. + * + * Default value is "containment". + * + * @type {String} + */ + set hierarchy(hierarchy) { + hierarchy = hierarchy || "containment"; + if (hierarchy !== "containment" && hierarchy !== "storeys" && hierarchy !== "types") { + this.error("Unsupported value for `hierarchy' - defaulting to 'containment'"); + hierarchy = "containment"; + } + this._hierarchy = hierarchy; + for (let modelId in this._modelTreeViews) { + if (this._modelTreeViews.hasOwnProperty(modelId)) { + this._modelTreeViews[modelId].setHierarchy(this._hierarchy); + } + } + } - function Data64URIWriter(contentType) { - var that = this, data = "", pending = ""; + /** + * Gets how the nodes are organized within this tree view. + * + * @type {String} + */ + get hierarchy() { + return this._hierarchy; + } - function init(callback) { - data += "data:" + (contentType || "") + ";base64,"; - callback(); + /** + * Adds a model to this tree view. + * + * The model will be automatically removed when destroyed. + * + * To automatically add each model as it's created, instead of manually calling this method each time, + * provide a ````autoAddModels: true```` to the TreeViewPlugin constructor. + * + * @param {String} modelId ID of a model {@link Entity} in {@link Scene#models}. + * @param {Object} [options] Options for model in the tree view. + * @param {String} [options.rootName] Optional display name for the root node. Ordinary, for "containment" + * and "storeys" hierarchy types, the tree would derive the root node name from the model's "IfcProject" element + * name. This option allows to override that name when it is not suitable as a display name. + * @returns {ModelTreeView} ModelTreeView for the newly-added model. If this method succeeded in adding the model, + * then {@link ModelTreeView#valid} will equal ````true````. Otherwise, that property will be ````false```` + * and {@link ModelTreeView#errors} will contain error messages. + */ + addModel(modelId, options = {}) { + if (!this._containerElement) { + return; } - - function writeUint8Array(array, callback) { - var i, delta = pending.length, dataString = pending; - pending = ""; - for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++) - dataString += String.fromCharCode(array[i]); - for (; i < array.length; i++) - pending += String.fromCharCode(array[i]); - if (dataString.length > 2) - data += obj.btoa(dataString); - else - pending = dataString; - callback(); + const model = this.viewer.scene.models[modelId]; + if (!model) { + throw "Model not found: " + modelId; } - - function getData(callback) { - callback(data + obj.btoa(pending)); + const metaModel = this.viewer.metaScene.metaModels[modelId]; + if (!metaModel) { + this.error("MetaModel not found: " + modelId); + return; } - - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; + if (this._modelTreeViews[modelId]) { + this.warn("Model already added: " + modelId); + return; + } + const modelTreeView = new ModelTreeView(this.viewer, this, model, metaModel, { + containerElement: this._containerElement, + autoExpandDepth: this._autoExpandDepth, + hierarchy: this._hierarchy, + sortNodes: this._sortNodes, + pruneEmptyNodes: this._pruneEmptyNodes, + rootName: options.rootName + }); + this._modelTreeViews[modelId] = modelTreeView; + model.on("destroyed", () => { + this.removeModel(model.id); + }); + return modelTreeView; } - Data64URIWriter.prototype = new Writer(); - Data64URIWriter.prototype.constructor = Data64URIWriter; - - function BlobWriter(contentType) { - var blob, that = this; - - function init(callback) { - blob = new Blob([], { - type: contentType - }); - callback(); + /** + * Removes a model from this tree view. + * + * Does nothing if model not currently in tree view. + * + * @param {String} modelId ID of a model {@link Entity} in {@link Scene#models}. + */ + removeModel(modelId) { + if (!this._containerElement) { + return; } - - function writeUint8Array(array, callback) { - blob = new Blob([blob, appendABViewSupported ? array : array.buffer], { - type: contentType - }); - callback(); + const modelTreeView = this._modelTreeViews[modelId]; + if (!modelTreeView) { + return; } + modelTreeView.destroy(); + delete this._modelTreeViews[modelId]; + } - function getData(callback) { - callback(blob); + /** + * Collapses all trees within this tree view. + */ + collapse() { + for (let modelId in this._modelTreeViews) { + if (this._modelTreeViews.hasOwnProperty(modelId)) { + const modelTreeView = this._modelTreeViews[modelId]; + modelTreeView.collapse(); + } } - - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; } - BlobWriter.prototype = new Writer(); - BlobWriter.prototype.constructor = BlobWriter; - /** - * inflate/deflate core functions - * @param worker {Worker} web worker for the task. - * @param initialMessage {Object} initial message to be sent to the worker. should contain - * sn(serial number for distinguishing multiple tasks sent to the worker), and codecClass. - * This function may add more properties before sending. + * Highlights the tree view node that represents the given object {@link Entity}. + * + * This causes the tree view to collapse, then expand to reveal the node, then highlight the node. + * + * If a node is previously highlighted, de-highlights that node and collapses the tree first. + * + * Note that if the TreeViewPlugin was configured with ````pruneEmptyNodes: true```` (default configuration), then the + * node won't exist in the tree if it has no Entitys in the {@link Scene}. in that case, nothing will happen. + * + * Within the DOM, the node is represented by an ````
  • ```` element. This method will add a ````.highlighted-node```` class to + * the element to make it appear highlighted, removing that class when de-highlighting it again. See the CSS rules + * in the TreeViewPlugin examples for an example of that class. + * + * @param {String} objectId ID of the {@link Entity}. */ - function launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror) { - var chunkIndex = 0, index, outputSize, sn = initialMessage.sn, crc; - - function onflush() { - worker.removeEventListener('message', onmessage, false); - onend(outputSize, crc); + showNode(objectId) { + this.unShowNode(); + const metaObject = this.viewer.metaScene.metaObjects[objectId]; + if (!metaObject) { + this.error("MetaObject not found: " + objectId); + return; + } + const metaModel = metaObject.metaModel; + const modelId = metaModel.id; + const modelTreeView = this._modelTreeViews[modelId]; + if (!modelTreeView) { + this.error("Object not in this TreeView: " + objectId); + return; } + modelTreeView.showNode(objectId); + } - function onmessage(event) { - var message = event.data, data = message.data, err = message.error; - if (err) { - err.toString = function () { - return 'Error: ' + this.message; - }; - onreaderror(err); - return; + /** + * De-highlights the node previously shown with {@link TreeViewPlugin#showNode}. + * + * Does nothing if no node is currently shown. + * + * If the node is currently scrolled into view, keeps the node in view. + */ + unShowNode() { + for (let modelId in this._modelTreeViews) { + if (this._modelTreeViews.hasOwnProperty(modelId)) { + const modelTreeView = this._modelTreeViews[modelId]; + modelTreeView.unShowNode(); } - if (message.sn !== sn) - return; - if (typeof message.codecTime === 'number') - worker.codecTime += message.codecTime; // should be before onflush() - if (typeof message.crcTime === 'number') - worker.crcTime += message.crcTime; + } + } - switch (message.type) { - case 'append': - if (data) { - outputSize += data.length; - writer.writeUint8Array(data, function () { - step(); - }, onwriteerror); - } else - step(); - break; - case 'flush': - crc = message.crc; - if (data) { - outputSize += data.length; - writer.writeUint8Array(data, function () { - onflush(); - }, onwriteerror); - } else - onflush(); - break; - case 'progress': - if (onprogress) - onprogress(index + message.loaded, size); - break; - case 'importScripts': //no need to handle here - case 'newTask': - case 'echo': - break; - default: - console.warn('zip.js:launchWorkerProcess: unknown message: ', message); + /** + * Expands the tree to the given depth. + * + * Collapses the tree first. + * + * @param {Number} depth Depth to expand to. + */ + expandToDepth(depth) { + for (let modelId in this._modelTreeViews) { + if (this._modelTreeViews.hasOwnProperty(modelId)) { + const modelTreeView = this._modelTreeViews[modelId]; + modelTreeView.collapse(); + modelTreeView.expandToDepth(depth); } } + } - function step() { - index = chunkIndex * CHUNK_SIZE; - // use `<=` instead of `<`, because `size` may be 0. - if (index <= size) { - reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function (array) { - if (onprogress) - onprogress(index, size); - var msg = index === 0 ? initialMessage : {sn: sn}; - msg.type = 'append'; - msg.data = array; + /** + * Iterates over a subtree of the tree view's {@link TreeViewNode}s, calling the given callback for each + * node in depth-first pre-order. + * + * @param {TreeViewNode} node Root of the subtree. + * @param {Function} callback Callback called at each {@link TreeViewNode}, with the TreeViewNode given as the argument. + */ + withNodeTree(node, callback) { + callback(node); + const children = node.children; + if (!children) { + return; + } + for (let i = 0, len = children.length; i < len; i++) { + this.withNodeTree(children[i], callback); + } + } - // posting a message with transferables will fail on IE10 - try { - worker.postMessage(msg, [array.buffer]); - } catch (ex) { - worker.postMessage(msg); // retry without transferables - } - chunkIndex++; - }, onreaderror); - } else { - worker.postMessage({ - sn: sn, - type: 'flush' - }); + /** + * Destroys this TreeViewPlugin. + */ + destroy() { + if (!this._containerElement) { + return; + } + for (let modelId in this._modelTreeViews) { + if (this._modelTreeViews.hasOwnProperty(modelId)) { + this._modelTreeViews[modelId].destroy(); } } - - outputSize = 0; - worker.addEventListener('message', onmessage, false); - step(); + this._modelTreeViews = {}; + super.destroy(); } +} - function launchProcess(process, reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror) { - var chunkIndex = 0, index, outputSize = 0, - crcInput = crcType === 'input', - crcOutput = crcType === 'output', - crc = new Crc32(); +const tempVec3a$1 = math.vec3(); +const tempVec3b$1 = math.vec3(); +const tempMat4a = math.mat4(); - function step() { - var outputData; - index = chunkIndex * CHUNK_SIZE; - if (index < size) - reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function (inputData) { - var outputData; - try { - outputData = process.append(inputData, function (loaded) { - if (onprogress) - onprogress(index + loaded, size); - }); - } catch (e) { - onreaderror(e); - return; - } - if (outputData) { - outputSize += outputData.length; - writer.writeUint8Array(outputData, function () { - chunkIndex++; - setTimeout(step, 1); - }, onwriteerror); - if (crcOutput) - crc.append(outputData); - } else { - chunkIndex++; - setTimeout(step, 1); - } - if (crcInput) - crc.append(inputData); - if (onprogress) - onprogress(index, size); - }, onreaderror); - else { - try { - outputData = process.flush(); - } catch (e) { - onreaderror(e); - return; - } - if (outputData) { - if (crcOutput) - crc.append(outputData); - outputSize += outputData.length; - writer.writeUint8Array(outputData, function () { - onend(outputSize, crc.get()); - }, onwriteerror); - } else - onend(outputSize, crc.get()); - } - } +/** + * @private + */ +class FrustumPlane { - step(); + constructor() { + this.normal = math.vec3(); + this.offset = 0; + this.testVertex = math.vec3(); } - function inflate(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { - var crcType = computeCrc32 ? 'output' : 'none'; - if (obj.zip.useWebWorkers) { - var initialMessage = { - sn: sn, - codecClass: 'Inflater', - crcType: crcType, - }; - launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror); - } else - launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror); + set(nx, ny, nz, offset) { + const s = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz); + this.normal[0] = nx * s; + this.normal[1] = ny * s; + this.normal[2] = nz * s; + this.offset = offset * s; + this.testVertex[0] = (this.normal[0] >= 0.0) ? 1 : 0; + this.testVertex[1] = (this.normal[1] >= 0.0) ? 1 : 0; + this.testVertex[2] = (this.normal[2] >= 0.0) ? 1 : 0; } +} - function deflate(worker, sn, reader, writer, level, onend, onprogress, onreaderror, onwriteerror) { - var crcType = 'input'; - if (obj.zip.useWebWorkers) { - var initialMessage = { - sn: sn, - options: {level: level}, - codecClass: 'Deflater', - crcType: crcType, - }; - launchWorkerProcess(worker, initialMessage, reader, writer, 0, reader.size, onprogress, onend, onreaderror, onwriteerror); - } else - launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, crcType, onprogress, onend, onreaderror, onwriteerror); +/** + * @private + */ +class Frustum { + constructor() { + this.planes = [ + new FrustumPlane(), new FrustumPlane(), new FrustumPlane(), + new FrustumPlane(), new FrustumPlane(), new FrustumPlane() + ]; } +} - function copy(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { - var crcType = 'input'; - if (obj.zip.useWebWorkers && computeCrc32) { - var initialMessage = { - sn: sn, - codecClass: 'NOOP', - crcType: crcType, - }; - launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror); - } else - launchProcess(new NOOP(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror); - } +Frustum.INSIDE = 0; +Frustum.INTERSECT = 1; +Frustum.OUTSIDE = 2; - // ZipReader +/** @private */ +function setFrustum(frustum, viewMat, projMat) { - function decodeASCII(str) { - var i, out = "", charCode, extendedASCII = ['\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', - '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', - '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', - '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6', - '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3', - '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE', - '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE', - '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7', - '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ']; - for (i = 0; i < str.length; i++) { - charCode = str.charCodeAt(i) & 0xFF; - if (charCode > 127) - out += extendedASCII[charCode - 128]; - else - out += String.fromCharCode(charCode); - } - return out; - } + const m = math.mulMat4(projMat, viewMat, tempMat4a); - function decodeUTF8(string) { - return decodeURIComponent(escape(string)); - } + const m0 = m[0]; + const m1 = m[1]; + const m2 = m[2]; + const m3 = m[3]; + const m4 = m[4]; + const m5 = m[5]; + const m6 = m[6]; + const m7 = m[7]; + const m8 = m[8]; + const m9 = m[9]; + const m10 = m[10]; + const m11 = m[11]; + const m12 = m[12]; + const m13 = m[13]; + const m14 = m[14]; + const m15 = m[15]; - function getString(bytes) { - var i, str = ""; - for (i = 0; i < bytes.length; i++) - str += String.fromCharCode(bytes[i]); - return str; - } + frustum.planes[0].set(m3 - m0, m7 - m4, m11 - m8, m15 - m12); + frustum.planes[1].set(m3 + m0, m7 + m4, m11 + m8, m15 + m12); + frustum.planes[2].set(m3 - m1, m7 - m5, m11 - m9, m15 - m13); + frustum.planes[3].set(m3 + m1, m7 + m5, m11 + m9, m15 + m13); + frustum.planes[4].set(m3 - m2, m7 - m6, m11 - m10, m15 - m14); + frustum.planes[5].set(m3 + m2, m7 + m6, m11 + m10, m15 + m14); +} - function getDate(timeRaw) { - var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff; - try { - return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, - (time & 0x001F) * 2, 0); - } catch (e) { - } - } +/** @private */ +function frustumIntersectsAABB3(frustum, aabb) { - function readCommonHeader(entry, data, index, centralDirectory, onerror) { - entry.version = data.view.getUint16(index, true); - entry.bitFlag = data.view.getUint16(index + 2, true); - entry.compressionMethod = data.view.getUint16(index + 4, true); - entry.lastModDateRaw = data.view.getUint32(index + 6, true); - entry.lastModDate = getDate(entry.lastModDateRaw); - if ((entry.bitFlag & 0x01) === 0x01) { - onerror(ERR_ENCRYPTED); - return; - } - if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) { - entry.crc32 = data.view.getUint32(index + 10, true); - entry.compressedSize = data.view.getUint32(index + 14, true); - entry.uncompressedSize = data.view.getUint32(index + 18, true); + let ret = Frustum.INSIDE; + + const min = tempVec3a$1; + const max = tempVec3b$1; + + min[0] = aabb[0]; + min[1] = aabb[1]; + min[2] = aabb[2]; + max[0] = aabb[3]; + max[1] = aabb[4]; + max[2] = aabb[5]; + + const bminmax = [min, max]; + + for (let i = 0; i < 6; ++i) { + const plane = frustum.planes[i]; + if (((plane.normal[0] * bminmax[plane.testVertex[0]][0]) + + (plane.normal[1] * bminmax[plane.testVertex[1]][1]) + + (plane.normal[2] * bminmax[plane.testVertex[2]][2]) + + (plane.offset)) < 0.0) { + return Frustum.OUTSIDE; } - if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) { - onerror(ERR_ZIP64); - return; + + if (((plane.normal[0] * bminmax[1 - plane.testVertex[0]][0]) + + (plane.normal[1] * bminmax[1 - plane.testVertex[1]][1]) + + (plane.normal[2] * bminmax[1 - plane.testVertex[2]][2]) + + (plane.offset)) < 0.0) { + ret = Frustum.INTERSECT; } - entry.filenameLength = data.view.getUint16(index + 22, true); - entry.extraFieldLength = data.view.getUint16(index + 24, true); } - function createZipReader(reader, callback, onerror) { - var inflateSN = 0; - - function Entry() { - } + return ret; +} - Entry.prototype.getData = function (writer, onend, onprogress, checkCrc32) { - var that = this; +/** + * For each Entity in its Scene, efficiently combines updates from multiple culling systems into a single "culled" state. + * + * Two culling systems are supported: + * + * * View culling - culls Entities when they fall outside the current view frustum, and + * * Detail culling - momentarily culls less visually-significant Entities while we are moving the camera. + * + * @private + */ +class ObjectCullStates { - function testCrc32(crc32) { - var dataCrc32 = getDataHelper(4); - dataCrc32.view.setUint32(0, crc32); - return that.crc32 == dataCrc32.view.getUint32(0); - } + /** + * @private + * @param scene + */ + constructor(scene) { - function getWriterData(uncompressedSize, crc32) { - if (checkCrc32 && !testCrc32(crc32)) - onerror(ERR_CRC); - else - writer.getData(function (data) { - onend(data); - }); - } + this._scene = scene; - function onreaderror(err) { - onerror(err || ERR_READ_DATA); - } + this._objects = []; // Array of all Entity instances that represent objects + this._objectsViewCulled = []; // A flag for each object to indicate its view-cull status + this._objectsDetailCulled = []; // A flag for each object to indicate its detail-cull status + this._objectsChanged = []; // A flag for each object, set whenever its cull status has changed since last _applyChanges() + this._objectsChangedList = []; // A list of objects whose cull status has changed, applied and cleared by _applyChanges() - function onwriteerror(err) { - onerror(err || ERR_WRITE_DATA); - } + this._modelInfos = {}; - reader.readUint8Array(that.offset, 30, function (bytes) { - var data = getDataHelper(bytes.length, bytes), dataOffset; - if (data.view.getUint32(0) != 0x504b0304) { - onerror(ERR_BAD_FORMAT); - return; - } - readCommonHeader(that, data, 4, false, onerror); - dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength; - writer.init(function () { - if (that.compressionMethod === 0) - copy(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); - else - inflate(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); - }, onwriteerror); - }, onreaderror); - }; + this._numObjects = 0; + this._lenObjectsChangedList = 0; - function seekEOCDR(eocdrCallback) { - // "End of central directory record" is the last part of a zip archive, and is at least 22 bytes long. - // Zip file comment is the last part of EOCDR and has max length of 64KB, - // so we only have to search the last 64K + 22 bytes of a archive for EOCDR signature (0x06054b50). - var EOCDR_MIN = 22; - if (reader.size < EOCDR_MIN) { - onerror(ERR_BAD_FORMAT); - return; - } - var ZIP_COMMENT_MAX = 256 * 256, EOCDR_MAX = EOCDR_MIN + ZIP_COMMENT_MAX; + this._dirty = true; - // In most cases, the EOCDR is EOCDR_MIN bytes long - doSeek(EOCDR_MIN, function () { - // If not found, try within EOCDR_MAX bytes - doSeek(Math.min(EOCDR_MAX, reader.size), function () { - onerror(ERR_BAD_FORMAT); - }); - }); + this._onModelLoaded = scene.on("modelLoaded", (modelId) => { + const model = scene.models[modelId]; + if (model) { + this._addModel(model); + } + }); - // seek last length bytes of file for EOCDR - function doSeek(length, eocdrNotFoundCallback) { - reader.readUint8Array(reader.size - length, length, function (bytes) { - for (var i = bytes.length - EOCDR_MIN; i >= 0; i--) { - if (bytes[i] === 0x50 && bytes[i + 1] === 0x4b && bytes[i + 2] === 0x05 && bytes[i + 3] === 0x06) { - eocdrCallback(new DataView(bytes.buffer, i, EOCDR_MIN)); - return; - } - } - eocdrNotFoundCallback(); - }, function () { - onerror(ERR_READ); - }); + this._onTick = scene.on("tick", () => { + if (this._dirty) { + this._build(); } - } + this._applyChanges(); + }); + } - var zipReader = { - getEntries: function (callback) { - var worker = this._worker; - // look for End of central directory record - seekEOCDR(function (dataView) { - var datalength, fileslength; - datalength = dataView.getUint32(16, true); - fileslength = dataView.getUint16(8, true); - if (datalength < 0 || datalength >= reader.size) { - onerror(ERR_BAD_FORMAT); - return; - } - reader.readUint8Array(datalength, reader.size - datalength, function (bytes) { - var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes); - for (i = 0; i < fileslength; i++) { - entry = new Entry(); - entry._worker = worker; - if (data.view.getUint32(index) != 0x504b0102) { - onerror(ERR_BAD_FORMAT); - return; - } - readCommonHeader(entry, data, index + 6, true, onerror); - entry.commentLength = data.view.getUint16(index + 32, true); - entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10); - entry.offset = data.view.getUint32(index + 42, true); - filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength)); - entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename); - if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/") - entry.directory = true; - comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46 - + entry.filenameLength + entry.extraFieldLength + entry.commentLength)); - entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment); - entries.push(entry); - index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength; - } - callback(entries); - }, function () { - onerror(ERR_READ); - }); - }); - }, - close: function (callback) { - if (this._worker) { - this._worker.terminate(); - this._worker = null; - } - if (callback) - callback(); - }, - _worker: null + _addModel(model) { + const modelInfo = { + model: model, + onDestroyed: model.on("destroyed", () => { + this._removeModel(model); + }) }; + this._modelInfos[model.id] = modelInfo; + this._dirty = true; + } - if (!obj.zip.useWebWorkers) - callback(zipReader); - else { - createWorker('inflater', - function (worker) { - zipReader._worker = worker; - callback(zipReader); - }, - function (err) { - onerror(err); - } - ); + _removeModel(model) { + const modelInfo = this._modelInfos[model.id]; + if (modelInfo) { + modelInfo.model.off(modelInfo.onDestroyed); + delete this._modelInfos[model.id]; + this._dirty = true; } } - // ZipWriter + _build() { + if (!this._dirty) { + return; + } + this._applyChanges(); + const objects = this._scene.objects; + for (let i = 0; i < this._numObjects; i++) { + this._objects[i] = null; + } + this._numObjects = 0; + for (let objectId in objects) { + const entity = objects[objectId]; + this._objects[this._numObjects++] = entity; + } + this._lenObjectsChangedList = 0; + this._dirty = false; + } - function encodeUTF8(string) { - return unescape(encodeURIComponent(string)); + _applyChanges() { + if (this._lenObjectsChangedList > 0) { + for (let i = 0; i < this._lenObjectsChangedList; i++) { + const objectIdx = this._objectsChangedList[i]; + const object = this._objects[objectIdx]; + const viewCulled = this._objectsViewCulled[objectIdx]; + const detailCulled = this._objectsDetailCulled[objectIdx]; + const culled = (viewCulled || detailCulled); + object.culled = culled; + this._objectsChanged[objectIdx] = false; + } + this._lenObjectsChangedList = 0; + } } - function getBytes(str) { - var i, array = []; - for (i = 0; i < str.length; i++) - array.push(str.charCodeAt(i)); - return array; + /** + * Array of {@link Entity} instances that represent objects in the {@link Scene}. + * + * ObjectCullStates rebuilds this from {@link Scene#objects} whenever ````Scene```` fires a ````modelLoaded```` event. + * + * @returns {Entity[]} + */ + get objects() { + if (this._dirty) { + this._build(); + } + return this._objects; } - function createZipWriter(writer, callback, onerror, dontDeflate) { - var files = {}, filenames = [], datalength = 0; - var deflateSN = 0; + /** + * Number of objects in {@link ObjectCullStates#objects}, + * + * Updated whenever ````Scene```` fires a ````modelLoaded```` event. + * + * @returns {Number} + */ + get numObjects() { + if (this._dirty) { + this._build(); + } + return this._numObjects; + } - function onwriteerror(err) { - onerror(err || ERR_WRITE); + /** + * Updates an object's view-cull status. + * + * @param {Number} objectIdx Index of the object in {@link ObjectCullStates#objects} + * @param {boolean} culled Whether to view-cull or not. + */ + setObjectViewCulled(objectIdx, culled) { + if (this._dirty) { + this._build(); + } + if (this._objectsViewCulled[objectIdx] === culled) { + return; + } + this._objectsViewCulled[objectIdx] = culled; + if (!this._objectsChanged[objectIdx]) { + this._objectsChanged[objectIdx] = true; + this._objectsChangedList[this._lenObjectsChangedList++] = objectIdx; } + } - function onreaderror(err) { - onerror(err || ERR_READ_DATA); + /** + * Updates an object's detail-cull status. + * + * @param {Number} objectIdx Index of the object in {@link ObjectCullStates#objects} + * @param {boolean} culled Whether to detail-cull or not. + */ + setObjectDetailCulled(objectIdx, culled) { + if (this._dirty) { + this._build(); + } + if (this._objectsDetailCulled[objectIdx] === culled) { + return; + } + this._objectsDetailCulled[objectIdx] = culled; + if (!this._objectsChanged[objectIdx]) { + this._objectsChanged[objectIdx] = true; + this._objectsChangedList[this._lenObjectsChangedList++] = objectIdx; } + } - var zipWriter = { - add: function (name, reader, onend, onprogress, options) { - var header, filename, date; - var worker = this._worker; + /** + * Destroys this ObjectCullStAtes. + */ + _destroy() { + this._clear(); + this._scene.off(this._onModelLoaded); + this._scene.off(this._onTick); + } - function writeHeader(callback) { - var data; - date = options.lastModDate || new Date(); - header = getDataHelper(26); - files[name] = { - headerArray: header.array, - directory: options.directory, - filename: filename, - offset: datalength, - comment: getBytes(encodeUTF8(options.comment || "")) - }; - header.view.setUint32(0, 0x14000808); - if (options.version) - header.view.setUint8(0, options.version); - if (!dontDeflate && options.level !== 0 && !options.directory) - header.view.setUint16(4, 0x0800); - header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true); - header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true); - header.view.setUint16(22, filename.length, true); - data = getDataHelper(30 + filename.length); - data.view.setUint32(0, 0x504b0304); - data.array.set(header.array, 4); - data.array.set(filename, 30); - datalength += data.array.length; - writer.writeUint8Array(data.array, callback, onwriteerror); - } + _clear() { + for (let modelId in this._modelInfos) { + const modelInfo = this._modelInfos[modelId]; + modelInfo.model.off(modelInfo.onDestroyed); + } + this._modelInfos = {}; + this._dirty = true; + } +} - function writeFooter(compressedLength, crc32) { - var footer = getDataHelper(16); - datalength += compressedLength || 0; - footer.view.setUint32(0, 0x504b0708); - if (typeof crc32 != "undefined") { - header.view.setUint32(10, crc32, true); - footer.view.setUint32(4, crc32, true); - } - if (reader) { - footer.view.setUint32(8, compressedLength, true); - header.view.setUint32(14, compressedLength, true); - footer.view.setUint32(12, reader.size, true); - header.view.setUint32(18, reader.size, true); - } - writer.writeUint8Array(footer.array, function () { - datalength += 16; - onend(); - }, onwriteerror); - } +const sceneObjectCullStates = {}; - function writeFile() { - options = options || {}; - name = name.trim(); - if (options.directory && name.charAt(name.length - 1) != "/") - name += "/"; - if (files.hasOwnProperty(name)) { - onerror(ERR_DUPLICATED_NAME); - return; - } - filename = getBytes(encodeUTF8(name)); - filenames.push(name); - writeHeader(function () { - if (reader) - if (dontDeflate || options.level === 0) - copy(worker, deflateSN++, reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror); - else - deflate(worker, deflateSN++, reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror); - else - writeFooter(); - }); - } +/** + * @private + */ +function getObjectCullStates(scene) { + const sceneId = scene.id; + let objectCullStates = sceneObjectCullStates[sceneId]; + if (!objectCullStates) { + objectCullStates = new ObjectCullStates(scene); + sceneObjectCullStates[sceneId] = objectCullStates; + scene.on("destroyed", () => { + delete sceneObjectCullStates[sceneId]; + objectCullStates._destroy(); + }); + } + return objectCullStates; +} - if (reader) - reader.init(writeFile, onreaderror); - else - writeFile(); - }, - close: function (callback) { - if (this._worker) { - this._worker.terminate(); - this._worker = null; - } +const MAX_KD_TREE_DEPTH = 8; // Increase if greater precision needed - var data, length = 0, index = 0, indexFilename, file; - for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { - file = files[filenames[indexFilename]]; - length += 46 + file.filename.length + file.comment.length; - } - data = getDataHelper(length + 22); - for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { - file = files[filenames[indexFilename]]; - data.view.setUint32(index, 0x504b0102); - data.view.setUint16(index + 4, 0x1400); - data.array.set(file.headerArray, index + 6); - data.view.setUint16(index + 32, file.comment.length, true); - if (file.directory) - data.view.setUint8(index + 38, 0x10); - data.view.setUint32(index + 42, file.offset, true); - data.array.set(file.filename, index + 46); - data.array.set(file.comment, index + 46 + file.filename.length); - index += 46 + file.filename.length + file.comment.length; - } - data.view.setUint32(index, 0x504b0506); - data.view.setUint16(index + 8, filenames.length, true); - data.view.setUint16(index + 10, filenames.length, true); - data.view.setUint32(index + 12, length, true); - data.view.setUint32(index + 16, datalength, true); - writer.writeUint8Array(data.array, function () { - writer.getData(callback); - }, onwriteerror); - }, - _worker: null +const kdTreeDimLength = new Float32Array(3); + +/** + * {@link Viewer} plugin that performs view frustum culling to accelerate rendering performance. + * + * For each {@link Entity} that represents an object, ````ViewCullPlugin```` will automatically + * set {@link Entity#culled}````false```` whenever it falls outside our field of view. + * + * When culled, an ````Entity```` is not processed by xeokit's renderer. + * + * Internally, ````ViewCullPlugin```` organizes {@link Entity}s in + * a [bounding volume hierarchy](https://en.wikipedia.org/wiki/Bounding_volume_hierarchy), implemented as + * a [kd-tree](https://en.wikipedia.org/wiki/K-d_tree). + * + * On each {@link Scene} "tick" event, ````ViewCullPlugin```` searches the kd-tree using a frustum generated from + * the {@link Camera}, marking each ````Entity```` **culled** if it falls outside the frustum. + * + * Use ````ViewCullPlugin```` by simply adding it to your ````Viewer````: + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * const viewCullPlugin = new ViewCullPlugin(viewer, { + * maxTreeDepth: 20 + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * const model = xktLoader.load({ + * id: "myModel", + * src: "./models/xkt/OTCConferenceCenter.xkt" + * }); + * ```` + */ +class ViewCullPlugin extends Plugin { + + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="ViewCull"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Number} [cfg.maxTreeDepth=8] Maximum depth of the kd-tree. + */ + constructor(viewer, cfg = {}) { + + super("ViewCull", viewer); + + this._objectCullStates = getObjectCullStates(viewer.scene); // Combines updates from multiple culling systems for its Scene's Entities + + this._maxTreeDepth = cfg.maxTreeDepth || MAX_KD_TREE_DEPTH; + this._modelInfos = {}; + this._frustum = new Frustum(); + this._kdRoot = null; + + this._frustumDirty = false; + this._kdTreeDirty = false; + + this._onViewMatrix = viewer.scene.camera.on("viewMatrix", () => { + this._frustumDirty = true; + }); + + this._onProjMatrix = viewer.scene.camera.on("projMatMatrix", () => { + this._frustumDirty = true; + }); + + this._onModelLoaded = viewer.scene.on("modelLoaded", (modelId) => { + const model = this.viewer.scene.models[modelId]; + if (model) { + this._addModel(model); + } + }); + + this._onSceneTick = viewer.scene.on("tick", () => { + this._doCull(); + }); + } + + /** + * Sets whether view culling is enabled. + * + * @param {Boolean} enabled Whether to enable view culling. + */ + set enabled(enabled) { + this._enabled = enabled; + } + + /** + * Gets whether view culling is enabled. + * + * @retutns {Boolean} Whether view culling is enabled. + */ + get enabled() { + return this._enabled; + } + + _addModel(model) { + const modelInfo = { + model: model, + onDestroyed: model.on("destroyed", () => { + this._removeModel(model); + }) }; + this._modelInfos[model.id] = modelInfo; + this._kdTreeDirty = true; + } - if (!obj.zip.useWebWorkers) - callback(zipWriter); - else { - createWorker('deflater', - function (worker) { - zipWriter._worker = worker; - callback(zipWriter); - }, - function (err) { - onerror(err); - } - ); + _removeModel(model) { + const modelInfo = this._modelInfos[model.id]; + if (modelInfo) { + modelInfo.model.off(modelInfo.onDestroyed); + delete this._modelInfos[model.id]; + this._kdTreeDirty = true; } } - function resolveURLs(urls) { - var a = document.createElement('a'); - return urls.map(function (url) { - a.href = url; - return a.href; - }); + _doCull() { + const cullDirty = (this._frustumDirty || this._kdTreeDirty); + if (this._frustumDirty) { + this._buildFrustum(); + } + if (this._kdTreeDirty) { + this._buildKDTree(); + } + if (cullDirty) { + const kdNode = this._kdRoot; + if (kdNode) { + this._visitKDNode(kdNode); + } + } } - var DEFAULT_WORKER_SCRIPTS = { - deflater: ['z-worker.js', 'deflate.js'], - inflater: ['z-worker.js', 'inflate.js'] - }; + _buildFrustum() { + const camera = this.viewer.scene.camera; + setFrustum(this._frustum, camera.viewMatrix, camera.projMatrix); + this._frustumDirty = false; + } - function createWorker(type, callback, onerror) { - if (obj.zip.workerScripts !== null && obj.zip.workerScriptsPath !== null) { - onerror(new Error('Either zip.workerScripts or zip.workerScriptsPath may be set, not both.')); + _buildKDTree() { + const viewer = this.viewer; + const scene = viewer.scene; + const depth = 0; + if (this._kdRoot) ; + this._kdRoot = { + aabb: scene.getAABB(), + intersection: Frustum.INTERSECT + }; + for (let objectIdx = 0, len = this._objectCullStates.numObjects; objectIdx < len; objectIdx++) { + const entity = this._objectCullStates.objects[objectIdx]; + this._insertEntityIntoKDTree(this._kdRoot, entity, objectIdx, depth + 1); + } + this._kdTreeDirty = false; + } + + _insertEntityIntoKDTree(kdNode, entity, objectIdx, depth) { + + const entityAABB = entity.aabb; + + if (depth >= this._maxTreeDepth) { + kdNode.objects = kdNode.objects || []; + kdNode.objects.push(objectIdx); + math.expandAABB3(kdNode.aabb, entityAABB); return; } - var scripts; - if (obj.zip.workerScripts) { - scripts = obj.zip.workerScripts[type]; - if (!Array.isArray(scripts)) { - onerror(new Error('zip.workerScripts.' + type + ' is not an array!')); + + if (kdNode.left) { + if (math.containsAABB3(kdNode.left.aabb, entityAABB)) { + this._insertEntityIntoKDTree(kdNode.left, entity, objectIdx, depth + 1); return; } - scripts = resolveURLs(scripts); - } else { - scripts = DEFAULT_WORKER_SCRIPTS[type].slice(0); - scripts[0] = (obj.zip.workerScriptsPath || '') + scripts[0]; } - var worker = new Worker(scripts[0]); - // record total consumed time by inflater/deflater/crc32 in this worker - worker.codecTime = worker.crcTime = 0; - worker.postMessage({type: 'importScripts', scripts: scripts.slice(1)}); - worker.addEventListener('message', onmessage); - function onmessage(ev) { - var msg = ev.data; - if (msg.error) { - worker.terminate(); // should before onerror(), because onerror() may throw. - onerror(msg.error); + + if (kdNode.right) { + if (math.containsAABB3(kdNode.right.aabb, entityAABB)) { + this._insertEntityIntoKDTree(kdNode.right, entity, objectIdx, depth + 1); return; } - if (msg.type === 'importScripts') { - worker.removeEventListener('message', onmessage); - worker.removeEventListener('error', errorHandler); - callback(worker); + } + + const nodeAABB = kdNode.aabb; + + kdTreeDimLength[0] = nodeAABB[3] - nodeAABB[0]; + kdTreeDimLength[1] = nodeAABB[4] - nodeAABB[1]; + kdTreeDimLength[2] = nodeAABB[5] - nodeAABB[2]; + + let dim = 0; + + if (kdTreeDimLength[1] > kdTreeDimLength[dim]) { + dim = 1; + } + + if (kdTreeDimLength[2] > kdTreeDimLength[dim]) { + dim = 2; + } + + if (!kdNode.left) { + const aabbLeft = nodeAABB.slice(); + aabbLeft[dim + 3] = ((nodeAABB[dim] + nodeAABB[dim + 3]) / 2.0); + kdNode.left = { + aabb: aabbLeft, + intersection: Frustum.INTERSECT + }; + if (math.containsAABB3(aabbLeft, entityAABB)) { + this._insertEntityIntoKDTree(kdNode.left, entity, objectIdx, depth + 1); + return; } } - // catch entry script loading error and other unhandled errors - worker.addEventListener('error', errorHandler); - function errorHandler(err) { - worker.terminate(); - onerror(err); + if (!kdNode.right) { + const aabbRight = nodeAABB.slice(); + aabbRight[dim] = ((nodeAABB[dim] + nodeAABB[dim + 3]) / 2.0); + kdNode.right = { + aabb: aabbRight, + intersection: Frustum.INTERSECT + }; + if (math.containsAABB3(aabbRight, entityAABB)) { + this._insertEntityIntoKDTree(kdNode.right, entity, objectIdx, depth + 1); + return; + } } + + kdNode.objects = kdNode.objects || []; + kdNode.objects.push(objectIdx); + + math.expandAABB3(kdNode.aabb, entityAABB); } - function onerror_default(error) { - console.error(error); + _visitKDNode(kdNode, intersects = Frustum.INTERSECT) { + if (intersects !== Frustum.INTERSECT && kdNode.intersects === intersects) { + return; + } + if (intersects === Frustum.INTERSECT) { + intersects = frustumIntersectsAABB3(this._frustum, kdNode.aabb); + kdNode.intersects = intersects; + } + const culled = (intersects === Frustum.OUTSIDE); + const objects = kdNode.objects; + if (objects && objects.length > 0) { + for (let i = 0, len = objects.length; i < len; i++) { + const objectIdx = objects[i]; + this._objectCullStates.setObjectViewCulled(objectIdx, culled); + } + } + if (kdNode.left) { + this._visitKDNode(kdNode.left, intersects); + } + if (kdNode.right) { + this._visitKDNode(kdNode.right, intersects); + } } - obj.zip = { - Reader: Reader, - Writer: Writer, - BlobReader: BlobReader, - Data64URIReader: Data64URIReader, - TextReader: TextReader, - BlobWriter: BlobWriter, - Data64URIWriter: Data64URIWriter, - TextWriter: TextWriter, - createReader: function (reader, callback, onerror) { - onerror = onerror || onerror_default; + /** + * @private + */ + send(name, value) { + } - reader.init(function () { - createZipReader(reader, callback, onerror); - }, onerror); - }, - createWriter: function (writer, callback, onerror, dontDeflate) { - onerror = onerror || onerror_default; - dontDeflate = !!dontDeflate; + /** + * Destroys this ViewCullPlugin. + */ + destroy() { + super.destroy(); + this._clear(); + const scene = this.viewer.scene; + const camera = scene.camera; + scene.off(this._onModelLoaded); + scene.off(this._onSceneTick); + camera.off(this._onViewMatrix); + camera.off(this._onProjMatrix); + } - writer.init(function () { - createZipWriter(writer, callback, onerror, dontDeflate); - }, onerror); - }, - useWebWorkers: true, - /** - * Directory containing the default worker scripts (z-worker.js, deflate.js, and inflate.js), relative to current base url. - * E.g.: zip.workerScripts = './'; - */ - workerScriptsPath: null, - /** - * Advanced option to control which scripts are loaded in the Web worker. If this option is specified, then workerScriptsPath must not be set. - * workerScripts.deflater/workerScripts.inflater should be arrays of urls to scripts for deflater/inflater, respectively. - * Scripts in the array are executed in order, and the first one should be z-worker.js, which is used to start the worker. - * All urls are relative to current base url. - * E.g.: - * zip.workerScripts = { - * deflater: ['z-worker.js', 'deflate.js'], - * inflater: ['z-worker.js', 'inflate.js'] - * }; - */ - workerScripts: null, - }; + _clear() { + for (let modelId in this._modelInfos) { + const modelInfo = this._modelInfos[modelId]; + modelInfo.model.off(modelInfo.onDestroyed); + } + this._modelInfos = {}; + this._kdRoot = null; + this._kdTreeDirty = true; + } +} -})(zipLib); +/** + * Default data access strategy for {@link XKTLoaderPlugin}. + */ +class XKTDefaultDataSource { -/* - Copyright (c) 2013 Gildas Lormeau. All rights reserved. + constructor() { + } - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: + /** + * Gets metamodel JSON. + * + * @param {String|Number} metaModelSrc Identifies the metamodel JSON asset. + * @param {Function} ok Fired on successful loading of the metamodel JSON asset. + * @param {Function} error Fired on error while loading the metamodel JSON asset. + */ + getMetaModel(metaModelSrc, ok, error) { + utils.loadJSON(metaModelSrc, + (json) => { + ok(json); + }, + function (errMsg) { + error(errMsg); + }); + } - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. + /** + * Gets the contents of the given ````.xkt```` file in an arraybuffer. + * + * @param {String|Number} src Path or ID of an ````.xkt```` file. + * @param {Function} ok Callback fired on success, argument is the ````.xkt```` file in an arraybuffer. + * @param {Function} error Callback fired on error. + */ + getXKT(src, ok, error) { + var defaultCallback = () => { + }; + ok = ok || defaultCallback; + error = error || defaultCallback; + const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; + const dataUriRegexResult = src.match(dataUriRegex); + if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest + const isBase64 = !!dataUriRegexResult[2]; + var data = dataUriRegexResult[3]; + data = window.decodeURIComponent(data); + if (isBase64) { + data = window.atob(data); + } + try { + const buffer = new ArrayBuffer(data.length); + const view = new Uint8Array(buffer); + for (var i = 0; i < data.length; i++) { + view[i] = data.charCodeAt(i); + } + ok(buffer); + } catch (errMsg) { + error(errMsg); + } + } else { + const request = new XMLHttpRequest(); + request.open('GET', src, true); + request.responseType = 'arraybuffer'; + request.onreadystatechange = function () { + if (request.readyState === 4) { + if (request.status === 200) { + ok(request.response); + } else { + error('getXKT error : ' + request.response); + } + } + }; + request.send(null); + } + } +} - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the distribution. +/*! pako 2.0.4 https://github.com/nodeca/pako @license (MIT AND Zlib) */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.pako = {})); +}(undefined, (function (exports) { + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. - 3. The names of the authors may not be used to endorse or promote products - derived from this software without specific prior written permission. + /* eslint-disable space-unary-ops */ - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, - INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, - INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, - OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ + /* Public constants ==========================================================*/ + /* ===========================================================================*/ -/** - * @private - */ -const zipExt = function(zipObj) { - var ERR_HTTP_RANGE = "HTTP Range not supported."; + //const Z_FILTERED = 1; + //const Z_HUFFMAN_ONLY = 2; + //const Z_RLE = 3; + const Z_FIXED$1 = 4; + //const Z_DEFAULT_STRATEGY = 0; - var Reader = zipObj.Reader; - var Writer = zipObj.Writer; + /* Possible values of the data_type field (though see inflate()) */ + const Z_BINARY = 0; + const Z_TEXT = 1; + //const Z_ASCII = 1; // = Z_TEXT + const Z_UNKNOWN$1 = 2; - var ZipDirectoryEntry; + /*============================================================================*/ - var appendABViewSupported; - try { - appendABViewSupported = new Blob([new DataView(new ArrayBuffer(0))]).size === 0; - } catch (e) { - } - function isHttpFamily(url) { - var a = document.createElement("a"); - a.href = url; - return a.protocol === "http:" || a.protocol === "https:"; - } + function zero$1(buf) { let len = buf.length; while (--len >= 0) { buf[len] = 0; } } - function HttpReader(url) { - var that = this; + // From zutil.h - function getData(callback, onerror) { - var request; - if (!that.data) { - request = new XMLHttpRequest(); - request.addEventListener("load", function () { - if (!that.size) - that.size = Number(request.getResponseHeader("Content-Length")) || Number(request.response.byteLength); - that.data = new Uint8Array(request.response); - callback(); - }, false); - request.addEventListener("error", onerror, false); - request.open("GET", url); - request.responseType = "arraybuffer"; - request.send(); - } else - callback(); - } + const STORED_BLOCK = 0; + const STATIC_TREES = 1; + const DYN_TREES = 2; + /* The three kinds of block type */ - function init(callback, onerror) { - if (!isHttpFamily(url)) { - // For schemas other than http(s), HTTP HEAD may be unavailable, - // so use HTTP GET instead. - getData(callback, onerror); - return; - } - var request = new XMLHttpRequest(); - request.addEventListener("load", function () { - that.size = Number(request.getResponseHeader("Content-Length")); - // If response header doesn't return size then prefetch the content. - if (!that.size) { - getData(callback, onerror); - } else { - callback(); - } - }, false); - request.addEventListener("error", onerror, false); - request.open("HEAD", url); - request.send(); - } + const MIN_MATCH$1 = 3; + const MAX_MATCH$1 = 258; + /* The minimum and maximum match lengths */ - function readUint8Array(index, length, callback, onerror) { - getData(function () { - callback(new Uint8Array(that.data.subarray(index, index + length))); - }, onerror); - } + // From deflate.h + /* =========================================================================== + * Internal compression state. + */ - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } + const LENGTH_CODES$1 = 29; + /* number of length codes, not counting the special END_BLOCK code */ - HttpReader.prototype = new Reader(); - HttpReader.prototype.constructor = HttpReader; + const LITERALS$1 = 256; + /* number of literal bytes 0..255 */ - function HttpRangeReader(url) { - var that = this; + const L_CODES$1 = LITERALS$1 + 1 + LENGTH_CODES$1; + /* number of Literal or Length codes, including the END_BLOCK code */ - function init(callback, onerror) { - var request = new XMLHttpRequest(); - request.addEventListener("load", function () { - that.size = Number(request.getResponseHeader("Content-Length")); - if (request.getResponseHeader("Accept-Ranges") == "bytes") - callback(); - else - onerror(ERR_HTTP_RANGE); - }, false); - request.addEventListener("error", onerror, false); - request.open("HEAD", url); - request.send(); - } + const D_CODES$1 = 30; + /* number of distance codes */ - function readArrayBuffer(index, length, callback, onerror) { - var request = new XMLHttpRequest(); - request.open("GET", url); - request.responseType = "arraybuffer"; - request.setRequestHeader("Range", "bytes=" + index + "-" + (index + length - 1)); - request.addEventListener("load", function () { - callback(request.response); - }, false); - request.addEventListener("error", onerror, false); - request.send(); - } + const BL_CODES$1 = 19; + /* number of codes used to transfer the bit lengths */ - function readUint8Array(index, length, callback, onerror) { - readArrayBuffer(index, length, function (arraybuffer) { - callback(new Uint8Array(arraybuffer)); - }, onerror); - } + const HEAP_SIZE$1 = 2 * L_CODES$1 + 1; + /* maximum heap size */ - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } + const MAX_BITS$1 = 15; + /* All codes must not exceed MAX_BITS bits */ - HttpRangeReader.prototype = new Reader(); - HttpRangeReader.prototype.constructor = HttpRangeReader; + const Buf_size = 16; + /* size of bit buffer in bi_buf */ - function ArrayBufferReader(arrayBuffer) { - var that = this; - function init(callback, onerror) { - that.size = arrayBuffer.byteLength; - callback(); - } + /* =========================================================================== + * Constants + */ - function readUint8Array(index, length, callback, onerror) { - callback(new Uint8Array(arrayBuffer.slice(index, index + length))); - } + const MAX_BL_BITS = 7; + /* Bit length codes must not exceed MAX_BL_BITS bits */ - that.size = 0; - that.init = init; - that.readUint8Array = readUint8Array; - } + const END_BLOCK = 256; + /* end of block literal code */ - ArrayBufferReader.prototype = new Reader(); - ArrayBufferReader.prototype.constructor = ArrayBufferReader; + const REP_3_6 = 16; + /* repeat previous bit length 3-6 times (2 bits of repeat count) */ - function ArrayBufferWriter() { - var array, that = this; + const REPZ_3_10 = 17; + /* repeat a zero length 3-10 times (3 bits of repeat count) */ - function init(callback, onerror) { - array = new Uint8Array(); - callback(); - } + const REPZ_11_138 = 18; + /* repeat a zero length 11-138 times (7 bits of repeat count) */ - function writeUint8Array(arr, callback, onerror) { - var tmpArray = new Uint8Array(array.length + arr.length); - tmpArray.set(array); - tmpArray.set(arr, array.length); - array = tmpArray; - callback(); - } + /* eslint-disable comma-spacing,array-bracket-spacing */ + const extra_lbits = /* extra bits for each length code */ + new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]); - function getData(callback) { - callback(array.buffer); - } + const extra_dbits = /* extra bits for each distance code */ + new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]); - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; - } + const extra_blbits = /* extra bits for each bit length code */ + new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]); - ArrayBufferWriter.prototype = new Writer(); - ArrayBufferWriter.prototype.constructor = ArrayBufferWriter; + const bl_order = + new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]); + /* eslint-enable comma-spacing,array-bracket-spacing */ - function FileWriter(fileEntry, contentType) { - var writer, that = this; + /* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ - function init(callback, onerror) { - fileEntry.createWriter(function (fileWriter) { - writer = fileWriter; - callback(); - }, onerror); - } + /* =========================================================================== + * Local data. These are initialized only once. + */ - function writeUint8Array(array, callback, onerror) { - var blob = new Blob([appendABViewSupported ? array : array.buffer], { - type: contentType - }); - writer.onwrite = function () { - writer.onwrite = null; - callback(); - }; - writer.onerror = onerror; - writer.write(blob); - } + // We pre-fill arrays with 0 to avoid uninitialized gaps - function getData(callback) { - fileEntry.file(callback); - } + const DIST_CODE_LEN = 512; /* see definition of array dist_code below */ - that.init = init; - that.writeUint8Array = writeUint8Array; - that.getData = getData; - } + // !!!! Use flat array instead of structure, Freq = i*2, Len = i*2+1 + const static_ltree = new Array((L_CODES$1 + 2) * 2); + zero$1(static_ltree); + /* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ - FileWriter.prototype = new Writer(); - FileWriter.prototype.constructor = FileWriter; + const static_dtree = new Array(D_CODES$1 * 2); + zero$1(static_dtree); + /* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ - zipObj.FileWriter = FileWriter; - zipObj.HttpReader = HttpReader; - zipObj.HttpRangeReader = HttpRangeReader; - zipObj.ArrayBufferReader = ArrayBufferReader; - zipObj.ArrayBufferWriter = ArrayBufferWriter; + const _dist_code = new Array(DIST_CODE_LEN); + zero$1(_dist_code); + /* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ - if (zipObj.fs) { - ZipDirectoryEntry = zipObj.fs.ZipDirectoryEntry; - ZipDirectoryEntry.prototype.addHttpContent = function (name, URL, useRangeHeader) { - function addChild(parent, name, params, directory) { - if (parent.directory) - return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new zipObj.fs.ZipFileEntry(parent.fs, name, params, parent); - else - throw "Parent entry is not a directory."; - } + const _length_code = new Array(MAX_MATCH$1 - MIN_MATCH$1 + 1); + zero$1(_length_code); + /* length code for each normalized match length (0 == MIN_MATCH) */ - return addChild(this, name, { - data: URL, - Reader: useRangeHeader ? HttpRangeReader : HttpReader - }); - }; - ZipDirectoryEntry.prototype.importHttpContent = function (URL, useRangeHeader, onend, onerror) { - this.importZip(useRangeHeader ? new HttpRangeReader(URL) : new HttpReader(URL), onend, onerror); - }; - zipObj.fs.FS.prototype.importHttpContent = function (URL, useRangeHeader, onend, onerror) { - this.entries = []; - this.root = new ZipDirectoryEntry(this); - this.root.importHttpContent(URL, useRangeHeader, onend, onerror); - }; - } -}; + const base_length = new Array(LENGTH_CODES$1); + zero$1(base_length); + /* First normalized length for each code (0 = MIN_MATCH) */ -const zip = zipLib.zip; -zipExt(zip); + const base_dist = new Array(D_CODES$1); + zero$1(base_dist); + /* First normalized distance for each code (0 = distance of 1) */ -const supportedSchemas = ["4.2"]; -/** - * @private - */ -class XML3DSceneGraphLoader { + function StaticTreeDesc(static_tree, extra_bits, extra_base, elems, max_length) { - constructor(plugin, cfg = {}) { + this.static_tree = static_tree; /* static tree or NULL */ + this.extra_bits = extra_bits; /* extra bits for each code or NULL */ + this.extra_base = extra_base; /* base index for extra_bits */ + this.elems = elems; /* max number of elements in the tree */ + this.max_length = max_length; /* max bit length for the codes */ - /** - * Supported 3DXML schema versions - * @property supportedSchemas - * @type {string[]} - */ - this.supportedSchemas = supportedSchemas; + // show if `static_tree` has data or dummy - needed for monomorphic objects + this.has_stree = static_tree && static_tree.length; + } - this._xrayOpacity = 0.7; - this._src = null; - this._options = cfg; - /** - * Default viewpoint, containing eye, look and up vectors. - * Only defined if found in the 3DXML file. - * @property viewpoint - * @type {Number[]} - */ - this.viewpoint = null; + let static_l_desc; + let static_d_desc; + let static_bl_desc; - if (!cfg.workerScriptsPath) { - plugin.error("Config expected: workerScriptsPath"); - return - } - zip.workerScriptsPath = cfg.workerScriptsPath; - this.src = cfg.src; - this.xrayOpacity = 0.7; - this.displayEffect = cfg.displayEffect; - this.createMetaModel = cfg.createMetaModel; + function TreeDesc(dyn_tree, stat_desc) { + this.dyn_tree = dyn_tree; /* the dynamic tree */ + this.max_code = 0; /* largest code with non zero frequency */ + this.stat_desc = stat_desc; /* the corresponding static tree */ } - load(plugin, modelNode, src, options, ok, error) { - switch (options.materialType) { - case "MetallicMaterial": - modelNode._defaultMaterial = new MetallicMaterial(modelNode, { - baseColor: [1, 1, 1], - metallic: 0.6, - roughness: 0.6 - }); - break; - case "SpecularMaterial": - modelNode._defaultMaterial = new SpecularMaterial(modelNode, { - diffuse: [1, 1, 1], - specular: math.vec3([1.0, 1.0, 1.0]), - glossiness: 0.5 - }); - break; + const d_code = (dist) => { - default: - modelNode._defaultMaterial = new PhongMaterial(modelNode, { - reflectivity: 0.75, - shiness: 100, - diffuse: [1, 1, 1] - }); + return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)]; + }; + + + /* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ + const put_short = (s, w) => { + // put_byte(s, (uch)((w) & 0xff)); + // put_byte(s, (uch)((ush)(w) >> 8)); + s.pending_buf[s.pending++] = (w) & 0xff; + s.pending_buf[s.pending++] = (w >>> 8) & 0xff; + }; + + + /* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ + const send_bits = (s, value, length) => { + + if (s.bi_valid > (Buf_size - length)) { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + put_short(s, s.bi_buf); + s.bi_buf = value >> (Buf_size - s.bi_valid); + s.bi_valid += length - Buf_size; + } else { + s.bi_buf |= (value << s.bi_valid) & 0xffff; + s.bi_valid += length; } + }; - modelNode._wireframeMaterial = new LambertMaterial(modelNode, { - color: [0, 0, 0], - lineWidth: 2 - }); - var spinner = modelNode.scene.canvas.spinner; - spinner.processes++; + const send_code = (s, c, tree) => { - load3DXML(plugin, modelNode, src, options, function () { - spinner.processes--; - if (ok) { - ok(); - } - modelNode.fire("loaded", true, false); - }, - function (msg) { - spinner.processes--; - modelNode.error(msg); - if (error) { - error(msg); - } - /** - Fired whenever this XML3D fails to load the 3DXML file - specified by {@link XML3D/src}. - @event error - @param msg {String} Description of the error - */ - modelNode.fire("error", msg); - }, - function (err) { - console.log("Error, Will Robinson: " + err); - }); - } -} + send_bits(s, tree[c * 2]/*.Code*/, tree[c * 2 + 1]/*.Len*/); + }; -var load3DXML = (function () { - return function (plugin, modelNode, src, options, ok, error) { - loadZIP(src, function (zip) { // OK - parse3DXML(plugin, zip, options, modelNode, ok, error); - }, - error); + + /* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ + const bi_reverse = (code, len) => { + + let res = 0; + do { + res |= code & 1; + code >>>= 1; + res <<= 1; + } while (--len > 0); + return res >>> 1; }; -})(); -var parse3DXML = (function () { - return function (plugin, zip, options, modelNode, ok) { - var ctx = { - plugin: plugin, - zip: zip, - edgeThreshold: 30, // Guess at degrees of normal deviation between adjacent tris below which we remove edge between them - materialType: options.materialType, - scene: modelNode.scene, - modelNode: modelNode, - info: { - references: {} - }, - materials: {} - }; - if (options.createMetaModel) { - ctx.metaModelData = { - modelId: modelNode.id, - metaObjects: [{ - name: modelNode.id, - type: "Default", - id: modelNode.id - }] - }; - } - modelNode.scene.loading++; // Disables (re)compilation + /* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ + const bi_flush = (s) => { - parseDocument(ctx, function () { - if (ctx.metaModelData) { - plugin.viewer.metaScene.createMetaModel(modelNode.id, ctx.metaModelData); - } - modelNode.scene.loading--; // Re-enables (re)compilation - ok(); - }); + if (s.bi_valid === 16) { + put_short(s, s.bi_buf); + s.bi_buf = 0; + s.bi_valid = 0; + + } else if (s.bi_valid >= 8) { + s.pending_buf[s.pending++] = s.bi_buf & 0xff; + s.bi_buf >>= 8; + s.bi_valid -= 8; + } }; - function parseDocument(ctx, ok) { - ctx.zip.getFile("Manifest.xml", function (xmlDoc, json) { - var node = json; - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Manifest": - parseManifest(ctx, child, ok); - break; - } + + /* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ + const gen_bitlen = (s, desc) => + // deflate_state *s; + // tree_desc *desc; /* the tree descriptor */ + { + const tree = desc.dyn_tree; + const max_code = desc.max_code; + const stree = desc.stat_desc.static_tree; + const has_stree = desc.stat_desc.has_stree; + const extra = desc.stat_desc.extra_bits; + const base = desc.stat_desc.extra_base; + const max_length = desc.stat_desc.max_length; + let h; /* heap index */ + let n, m; /* iterate over the tree elements */ + let bits; /* bit length */ + let xbits; /* extra bits */ + let f; /* frequency */ + let overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS$1; bits++) { + s.bl_count[bits] = 0; + } + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s.heap[s.heap_max] * 2 + 1]/*.Len*/ = 0; /* root of the heap */ + + for (h = s.heap_max + 1; h < HEAP_SIZE$1; h++) { + n = s.heap[h]; + bits = tree[tree[n * 2 + 1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1; + if (bits > max_length) { + bits = max_length; + overflow++; } - }); - } + tree[n * 2 + 1]/*.Len*/ = bits; + /* We overwrite tree[n].Dad which is no longer needed */ - function parseManifest(ctx, manifest, ok) { - var children = manifest.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Root": - var rootFileSrc = child.children[0]; - ctx.zip.getFile(rootFileSrc, function (xmlDoc, json) { - parseRoot(ctx, json, ok); - }); - break; + if (n > max_code) { continue; } /* not a leaf node */ + + s.bl_count[bits]++; + xbits = 0; + if (n >= base) { + xbits = extra[n - base]; + } + f = tree[n * 2]/*.Freq*/; + s.opt_len += f * (bits + xbits); + if (has_stree) { + s.static_len += f * (stree[n * 2 + 1]/*.Len*/ + xbits); } } - } + if (overflow === 0) { return; } - function parseRoot(ctx, node, ok) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Model_3dxml": - parseModel(ctx, child, ok); - break; + // Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length - 1; + while (s.bl_count[bits] === 0) { bits--; } + s.bl_count[bits]--; /* move one leaf down the tree */ + s.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + s.bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits !== 0; bits--) { + n = s.bl_count[bits]; + while (n !== 0) { + m = s.heap[--h]; + if (m > max_code) { continue; } + if (tree[m * 2 + 1]/*.Len*/ !== bits) { + // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s.opt_len += (bits - tree[m * 2 + 1]/*.Len*/) * tree[m * 2]/*.Freq*/; + tree[m * 2 + 1]/*.Len*/ = bits; + } + n--; } } - } + }; - function parseModel(ctx, node, ok) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Header": - parseHeader(ctx, child); - break; - case "ProductStructure": - parseProductStructure(ctx, child, ok); - break; - case "DefaultView": - parseDefaultView(ctx, child); - break; - } + + /* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ + const gen_codes = (tree, max_code, bl_count) => + // ct_data *tree; /* the tree to decorate */ + // int max_code; /* largest code with non zero frequency */ + // ushf *bl_count; /* number of codes at each bit length */ + { + const next_code = new Array(MAX_BITS$1 + 1); /* next code value for each bit length */ + let code = 0; /* running code value */ + let bits; /* bit index */ + let n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS$1; bits++) { + next_code[bits] = code = (code + bl_count[bits - 1]) << 1; } - } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + //Assert (code + bl_count[MAX_BITS]-1 == (1< { + + let n; /* iterates over tree elements */ + let bits; /* bit counter */ + let length; /* length value */ + let code; /* code value */ + let dist; /* distance index */ + const bl_count = new Array(MAX_BITS$1 + 1); + /* number of codes at each bit length for an optimal tree */ + + // do check in _tr_init() + //if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + /*#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + #endif*/ + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES$1 - 1; code++) { + base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + _length_code[length++] = code; } } - ctx.modelNode.meta = metaData; - } + //Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length - 1] = code; - function isSchemaVersionSupported(ctx, schemaVersion) { - for (var i = 0, len = supportedSchemas.length; i < len; i++) { - if (schemaVersion === supportedSchemas[i]) { - return true; + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + _dist_code[dist++] = code; } } - return false; - } + //Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for (; code < D_CODES$1; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + _dist_code[256 + dist++] = code; + } + } + //Assert (dist == 256, "tr_static_init: 256+dist != 512"); - function parseProductStructure(ctx, productStructureNode, ok) { + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS$1; bits++) { + bl_count[bits] = 0; + } - parseReferenceReps(ctx, productStructureNode, function (referenceReps) { + n = 0; + while (n <= 143) { + static_ltree[n * 2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + while (n <= 255) { + static_ltree[n * 2 + 1]/*.Len*/ = 9; + n++; + bl_count[9]++; + } + while (n <= 279) { + static_ltree[n * 2 + 1]/*.Len*/ = 7; + n++; + bl_count[7]++; + } + while (n <= 287) { + static_ltree[n * 2 + 1]/*.Len*/ = 8; + n++; + bl_count[8]++; + } + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes(static_ltree, L_CODES$1 + 1, bl_count); - // Parse out an intermediate scene DAG representation, that we can then - // recursive descend through to build a xeokit Object hierarchy. + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES$1; n++) { + static_dtree[n * 2 + 1]/*.Len*/ = 5; + static_dtree[n * 2]/*.Code*/ = bi_reverse(n, 5); + } - var children = productStructureNode.children; + // Now data ready and we can init static trees + static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS$1 + 1, L_CODES$1, MAX_BITS$1); + static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES$1, MAX_BITS$1); + static_bl_desc = new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES$1, MAX_BL_BITS); - var reference3Ds = {}; - var instanceReps = {}; - var instance3Ds = {}; + //static_init_done = true; + }; - // Map all the elements - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { + /* =========================================================================== + * Initialize a new block. + */ + const init_block = (s) => { - case "Reference3D": - reference3Ds[child.id] = { - type: "Reference3D", - id: child.id, - name: child.name, - instance3Ds: {}, - instanceReps: {} - }; - break; + let n; /* iterates over tree elements */ - case "InstanceRep": - var isAggregatedBy; - var isInstanceOf; - var relativeMatrix; - for (var j = 0, lenj = child.children.length; j < lenj; j++) { - var child2 = child.children[j]; - switch (child2.type) { - case "IsAggregatedBy": - isAggregatedBy = child2.children[0]; - break; - case "IsInstanceOf": - isInstanceOf = child2.children[0]; - break; - } - } - instanceReps[child.id] = { - type: "InstanceRep", - id: child.id, - name: child.name, - isAggregatedBy: isAggregatedBy, - isInstanceOf: isInstanceOf, - referenceReps: {} - }; - break; + /* Initialize the trees. */ + for (n = 0; n < L_CODES$1; n++) { s.dyn_ltree[n * 2]/*.Freq*/ = 0; } + for (n = 0; n < D_CODES$1; n++) { s.dyn_dtree[n * 2]/*.Freq*/ = 0; } + for (n = 0; n < BL_CODES$1; n++) { s.bl_tree[n * 2]/*.Freq*/ = 0; } - case "Instance3D": - var isAggregatedBy; - var isInstanceOf; - var relativeMatrix; - for (var j = 0, lenj = child.children.length; j < lenj; j++) { - var child2 = child.children[j]; - switch (child2.type) { - case "IsAggregatedBy": - isAggregatedBy = child2.children[0]; - break; - case "IsInstanceOf": - isInstanceOf = child2.children[0]; - break; - case "RelativeMatrix": - relativeMatrix = child2.children[0]; - break; - } - } - instance3Ds[child.id] = { - type: "Instance3D", - id: child.id, - name: child.name, - isAggregatedBy: isAggregatedBy, - isInstanceOf: isInstanceOf, - relativeMatrix: relativeMatrix, - reference3Ds: {} - }; - break; - } - } + s.dyn_ltree[END_BLOCK * 2]/*.Freq*/ = 1; + s.opt_len = s.static_len = 0; + s.last_lit = s.matches = 0; + }; - // Connect Reference3Ds to the Instance3Ds they aggregate - for (var id in instance3Ds) { - var instance3D = instance3Ds[id]; - var reference3D = reference3Ds[instance3D.isAggregatedBy]; - if (reference3D) { - reference3D.instance3Ds[instance3D.id] = instance3D; - } else { - alert("foo"); - } - } + /* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ + const bi_windup = (s) => + { + if (s.bi_valid > 8) { + put_short(s, s.bi_buf); + } else if (s.bi_valid > 0) { + //put_byte(s, (Byte)s->bi_buf); + s.pending_buf[s.pending++] = s.bi_buf; + } + s.bi_buf = 0; + s.bi_valid = 0; + }; - // Connect Instance3Ds to the Reference3Ds they instantiate + /* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ + const copy_block = (s, buf, len, header) => + //DeflateState *s; + //charf *buf; /* the input data */ + //unsigned len; /* its length */ + //int header; /* true if block header must be written */ + { + bi_windup(s); /* align on byte boundary */ - for (var id in instance3Ds) { - var instance3D = instance3Ds[id]; - var reference3D = reference3Ds[instance3D.isInstanceOf]; - instance3D.reference3Ds[reference3D.id] = reference3D; - reference3D.instance3D = instance3D; - } + if (header) { + put_short(s, len); + put_short(s, ~len); + } + // while (len--) { + // put_byte(s, *buf++); + // } + s.pending_buf.set(s.window.subarray(buf, buf + len), s.pending); + s.pending += len; + }; - // Connect InstanceReps to the ReferenceReps they instantiate + /* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ + const smaller = (tree, n, m, depth) => { - for (var id in instanceReps) { - var instanceRep = instanceReps[id]; - var referenceRep = referenceReps[instanceRep.isInstanceOf]; - if (referenceRep) { - instanceRep.referenceReps[referenceRep.id] = referenceRep; - } + const _n2 = n * 2; + const _m2 = m * 2; + return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ || + (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m])); + }; + + /* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ + const pqdownheap = (s, tree, k) => + // deflate_state *s; + // ct_data *tree; /* the tree to restore */ + // int k; /* node to move down */ + { + const v = s.heap[k]; + let j = k << 1; /* left son of k */ + while (j <= s.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s.heap_len && + smaller(tree, s.heap[j + 1], s.heap[j], s.depth)) { + j++; } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s.heap[j], s.depth)) { break; } - // Connect Reference3Ds to the InstanceReps they aggregate + /* Exchange v with the smallest son */ + s.heap[k] = s.heap[j]; + k = j; - for (var id in instanceReps) { - var instanceRep = instanceReps[id]; - var reference3D = reference3Ds[instanceRep.isAggregatedBy]; - if (reference3D) { - reference3D.instanceReps[instanceRep.id] = instanceRep; - } - } + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s.heap[k] = v; + }; - function parseReference3D(ctx, reference3D, group) { - //ctx.plugin.log("parseReference3D( " + reference3D.id + " )"); - for (var id in reference3D.instance3Ds) { - parseInstance3D(ctx, reference3D.instance3Ds[id], group); - } - for (var id in reference3D.instanceReps) { - parseInstanceRep(ctx, reference3D.instanceReps[id], group); - } - } - function parseInstance3D(ctx, instance3D, group) { - //ctx.plugin.log("parseInstance3D( " + instance3D.id + " )"); + // inlined manually + // const SMALLEST = 1; - if (instance3D.relativeMatrix) { - var matrix = parseFloatArray(instance3D.relativeMatrix, 12); - var translate = [matrix[9], matrix[10], matrix[11]]; - var mat3 = matrix.slice(0, 9); // Rotation matrix - var mat4 = math.mat3ToMat4(mat3, math.identityMat4()); // Convert rotation matrix to 4x4 - var childGroup = new Node$1(ctx.modelNode, { - position: translate - }); - if (ctx.metaModelData) { - ctx.metaModelData.metaObjects.push({ - id: childGroup.id, - type: "Default", - name: instance3D.name, - parent: group ? group.id : ctx.modelNode.id - }); - } - if (group) { - group.addChild(childGroup, true); - } else { - ctx.modelNode.addChild(childGroup, true); - } - group = childGroup; - childGroup = new Node$1(ctx.modelNode, { - matrix: mat4 - }); - if (ctx.metaModelData) { - ctx.metaModelData.metaObjects.push({ - id: childGroup.id, - type: "Default", - name: instance3D.name, - parent: group ? group.id : ctx.modelNode.id - }); - } - group.addChild(childGroup, true); - group = childGroup; + /* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ + const compress_block = (s, ltree, dtree) => + // deflate_state *s; + // const ct_data *ltree; /* literal tree */ + // const ct_data *dtree; /* distance tree */ + { + let dist; /* distance of matched string */ + let lc; /* match length or unmatched char (if dist == 0) */ + let lx = 0; /* running index in l_buf */ + let code; /* the code to send */ + let extra; /* number of extra bits to send */ + + if (s.last_lit !== 0) { + do { + dist = (s.pending_buf[s.d_buf + lx * 2] << 8) | (s.pending_buf[s.d_buf + lx * 2 + 1]); + lc = s.pending_buf[s.l_buf + lx]; + lx++; + + if (dist === 0) { + send_code(s, lc, ltree); /* send a literal byte */ + //Tracecv(isgraph(lc), (stderr," '%c' ", lc)); } else { - var childGroup = new Node$1(ctx.modelNode, {}); - if (ctx.metaModelData) { - ctx.metaModelData.metaObjects.push({ - id: childGroup.id, - type: "Default", - name: instance3D.name, - parent: group ? group.id : ctx.modelNode.id - }); + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code + LITERALS$1 + 1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra !== 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ } - if (group) { - group.addChild(childGroup, true); - } else { - ctx.modelNode.addChild(childGroup, true); + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + //Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra !== 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ } - group = childGroup; - } - for (var id in instance3D.reference3Ds) { - parseReference3D(ctx, instance3D.reference3Ds[id], group); - } - } + } /* literal or match pair ? */ - function parseInstanceRep(ctx, instanceRep, group) { - //ctx.plugin.log("parseInstanceRep( " + instanceRep.id + " )"); - if (instanceRep.referenceReps) { - for (var id in instanceRep.referenceReps) { - var referenceRep = instanceRep.referenceReps[id]; - for (var id2 in referenceRep) { - if (id2 === "id") { - continue; // HACK - } - var meshCfg = referenceRep[id2]; - var lines = meshCfg.geometry.primitive === "lines"; - var material = lines ? ctx.modelNode._wireframeMaterial : (meshCfg.materialId ? ctx.materials[meshCfg.materialId] : null); - var colorize = meshCfg.color; - var mesh = new Mesh(ctx.modelNode, { - isObject: true, - geometry: meshCfg.geometry, - material: material || ctx.modelNode._defaultMaterial, - colorize: colorize, - backfaces: false - }); - if (ctx.metaModelData) { - ctx.metaModelData.metaObjects.push({ - id: mesh.id, - type: "Default", - name: instanceRep.name, - parent: group ? group.id : ctx.modelNode.id - }); - } - if (group) { - group.addChild(mesh, true); - } else { - ctx.modelNode.addChild(mesh, true); - } - mesh.colorize = colorize; // HACK: Mesh has inherited modelNode's colorize state, so we need to restore it (we'd better not modify colorize on the modelNode). - } - } - } - } + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + // "pendingBuf overflow"); - // Find the root Reference3D + } while (lx < s.last_lit); + } - for (var id in reference3Ds) { - var reference3D = reference3Ds[id]; - if (!reference3D.instance3D) { - parseReference3D(ctx, reference3D, null); // HACK: Assuming that root has id == "1" - ok(); - return; - } - } + send_code(s, END_BLOCK, ltree); + }; - alert("No root Reference3D element found in this modelNode - can't load."); - ok(); - }); - } + /* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ + const build_tree = (s, desc) => + // deflate_state *s; + // tree_desc *desc; /* the tree descriptor */ + { + const tree = desc.dyn_tree; + const stree = desc.stat_desc.static_tree; + const has_stree = desc.stat_desc.has_stree; + const elems = desc.stat_desc.elems; + let n, m; /* iterate over heap elements */ + let max_code = -1; /* largest code with non zero frequency */ + let node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s.heap_len = 0; + s.heap_max = HEAP_SIZE$1; + + for (n = 0; n < elems; n++) { + if (tree[n * 2]/*.Freq*/ !== 0) { + s.heap[++s.heap_len] = max_code = n; + s.depth[n] = 0; - function parseIntArray(str) { - var parts = str.trim().split(" "); - var result = new Int32Array(parts.length); - for (var i = 0; i < parts.length; i++) { - result[i] = parseInt(parts[i]); + } else { + tree[n * 2 + 1]/*.Len*/ = 0; + } } - return result; - } - function parseReferenceReps(ctx, node, ok) { - var referenceReps = {}; - var children = node.children; - var numToLoad = 0; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - if (child.type === "ReferenceRep") { - numToLoad++; + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s.heap_len < 2) { + node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0); + tree[node * 2]/*.Freq*/ = 1; + s.depth[node] = 0; + s.opt_len--; + + if (has_stree) { + s.static_len -= stree[node * 2 + 1]/*.Len*/; } + /* node is 0 or 1 so it does not have extra bits */ } - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "ReferenceRep": - if (child.associatedFile) { - var src = stripURN(child.associatedFile); - (function () { - var childId = child.id; - ctx.zip.getFile(src, function (xmlDoc, json) { + desc.max_code = max_code; - var materialIds = xmlDoc.getElementsByTagName("MaterialId"); + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); } - loadCATMaterialRefDocuments(ctx, materialIds, function () { + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + //pqremove(s, tree, n); /* n = node of least frequency */ + /*** pqremove ***/ + n = s.heap[1/*SMALLEST*/]; + s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--]; + pqdownheap(s, tree, 1/*SMALLEST*/); + /***/ - // ctx.plugin.log("reference loaded: " + src); - var referenceRep = { - id: childId - }; - parse3DRepDocument(ctx, json, referenceRep); - referenceReps[childId] = referenceRep; - if (--numToLoad === 0) { - ok(referenceReps); - } - }); - }, - function (error) { - // TODO: - }); - })(); - } - break; - } - } - } + m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */ + s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */ + s.heap[--s.heap_max] = m; - function parseDefaultView(ctx, node) { - // ctx.plugin.log("parseDefaultView"); - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Viewpoint": - var children2 = child.children; - ctx.modelNode.viewpoint = {}; - for (var i2 = 0, len2 = children2.length; i2 < len2; i2++) { - var child2 = children2[i]; - switch (child2.type) { - case "Position": - ctx.modelNode.viewpoint.eye = parseFloatArray(child2.children[0], 3); - break; - case "Sight": - ctx.modelNode.viewpoint.look = parseFloatArray(child2.children[0], 3); - break; - case "Up": - ctx.modelNode.viewpoint.up = parseFloatArray(child2.children[0], 3); - break; - } - } - break; - } - } - } + /* Create a new node father of n and m */ + tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/; + s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1; + tree[n * 2 + 1]/*.Dad*/ = tree[m * 2 + 1]/*.Dad*/ = node; - function parse3DRepDocument(ctx, node, result) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "XMLRepresentation": - parseXMLRepresentation(ctx, child, result); - break; - } - } - } + /* and insert the new node in the heap */ + s.heap[1/*SMALLEST*/] = node++; + pqdownheap(s, tree, 1/*SMALLEST*/); - function parseXMLRepresentation(ctx, node, result) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Root": - parse3DRepRoot(ctx, child, result); - break; - } + } while (s.heap_len >= 2); + + s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, s.bl_count); + }; + + + /* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ + const scan_tree = (s, tree, max_code) => + // deflate_state *s; + // ct_data *tree; /* the tree to be scanned */ + // int max_code; /* and its largest code of non zero frequency */ + { + let n; /* iterates over all tree elements */ + let prevlen = -1; /* last emitted length */ + let curlen; /* length of current code */ + + let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ + + let count = 0; /* repeat count of the current code */ + let max_count = 7; /* max repeat count */ + let min_count = 4; /* min repeat count */ + + if (nextlen === 0) { + max_count = 138; + min_count = 3; } - } + tree[(max_code + 1) * 2 + 1]/*.Len*/ = 0xffff; /* guard */ - function parse3DRepRoot(ctx, node, result) { - switch (node["xsi:type"]) { - } - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Rep": - parse3DRepRep(ctx, child, result); - break; + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + s.bl_tree[curlen * 2]/*.Freq*/ += count; + + } else if (curlen !== 0) { + + if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; } + s.bl_tree[REP_3_6 * 2]/*.Freq*/++; + + } else if (count <= 10) { + s.bl_tree[REPZ_3_10 * 2]/*.Freq*/++; + + } else { + s.bl_tree[REPZ_11_138 * 2]/*.Freq*/++; } - } - } - function parse3DRepRep(ctx, node, result) { - switch (node["xsi:type"]) { - } - var meshesResult = { - edgeThreshold: ctx.edgeThreshold || 30, - compressGeometry: true - }; - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Rep": - parse3DRepRep(ctx, child, result); - break; - case "Edges": - // Ignoring edges because we auto-generate our own using xeokit - break; - case "Faces": - meshesResult.primitive = "triangles"; - parseFaces(ctx, child, meshesResult); - break; - case "VertexBuffer": - parseVertexBuffer(ctx, child, meshesResult); - break; - case "SurfaceAttributes": - parseSurfaceAttributes(ctx, child, meshesResult); - break; + count = 0; + prevlen = curlen; + + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; } } - if (meshesResult.positions) { - var geometry = new ReadableGeometry(ctx.modelNode, meshesResult); - result[geometry.id] = { - geometry: geometry, - color: meshesResult.color || [1.0, 1.0, 1.0, 1.0], - materialId: meshesResult.materialId - }; - } - } + }; - function parseFaces(ctx, node, result) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Face": - parseFace(ctx, child, result); - break; - } + + /* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ + const send_tree = (s, tree, max_code) => + // deflate_state *s; + // ct_data *tree; /* the tree to be scanned */ + // int max_code; /* and its largest code of non zero frequency */ + { + let n; /* iterates over all tree elements */ + let prevlen = -1; /* last emitted length */ + let curlen; /* length of current code */ + + let nextlen = tree[0 * 2 + 1]/*.Len*/; /* length of next code */ + + let count = 0; /* repeat count of the current code */ + let max_count = 7; /* max repeat count */ + let min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen === 0) { + max_count = 138; + min_count = 3; } - } - function parseFace(ctx, node, result) { - var strips = node.strips; - if (strips) { - // Triangle strips - var arrays = parseIntArrays(strips); - if (arrays.length > 0) { - result.primitive = "triangles"; - var indices = []; - for (var i = 0, len = arrays.length; i < len; i++) { - var array = convertTriangleStrip(arrays[i]); - for (var j = 0, lenj = array.length; j < lenj; j++) { - indices.push(array[j]); - } + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[(n + 1) * 2 + 1]/*.Len*/; + + if (++count < max_count && curlen === nextlen) { + continue; + + } else if (count < min_count) { + do { send_code(s, curlen, s.bl_tree); } while (--count !== 0); + + } else if (curlen !== 0) { + if (curlen !== prevlen) { + send_code(s, curlen, s.bl_tree); + count--; } - result.indices = indices; // TODO - } - } else { - // Triangle meshes - var triangles = node.triangles; - if (triangles) { - result.primitive = "triangles"; - result.indices = parseIntArray(triangles); - } - } - // Material - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "SurfaceAttributes": - parseSurfaceAttributes(ctx, child, result); - break; + //Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s.bl_tree); + send_bits(s, count - 3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s.bl_tree); + send_bits(s, count - 3, 3); + + } else { + send_code(s, REPZ_11_138, s.bl_tree); + send_bits(s, count - 11, 7); } - } - } - function convertTriangleStrip(indices) { - var indices2 = []; - for (var i = 0, len = indices.length; i < len - 2; i++) { - { - if (i & 1) { // - indices2.push(indices[i]); - indices2.push(indices[i + 2]); - indices2.push(indices[i + 1]); - } else { - indices2.push(indices[i]); - indices2.push(indices[i + 1]); - indices2.push(indices[i + 2]); - } + count = 0; + prevlen = curlen; + if (nextlen === 0) { + max_count = 138; + min_count = 3; + + } else if (curlen === nextlen) { + max_count = 6; + min_count = 3; + + } else { + max_count = 7; + min_count = 4; } } - return indices2; - } + }; - function parseVertexBuffer(ctx, node, result) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Positions": - result.positions = parseFloatArray(child.children[0], 3); - break; - case "Normals": - result.normals = parseFloatArray(child.children[0], 3); - break; - case "TextureCoordinates": // TODO: Support dimension and channel? - result.uv = parseFloatArray(child.children[0], 2); - break; + + /* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ + const build_bl_tree = (s) => { + + let max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, s.dyn_ltree, s.l_desc.max_code); + scan_tree(s, s.dyn_dtree, s.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, s.bl_desc); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES$1 - 1; max_blindex >= 3; max_blindex--) { + if (s.bl_tree[bl_order[max_blindex] * 2 + 1]/*.Len*/ !== 0) { + break; } } - } + /* Update opt_len to include the bit length tree and counts */ + s.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + // s->opt_len, s->static_len)); - function parseIntArrays(str) { - var coordStrings = str.split(","); - var array = []; - for (var i = 0, len = coordStrings.length; i < len; i++) { - var coordStr = coordStrings[i].trim(); - if (coordStr.length > 0) { - var elemStrings = coordStr.trim().split(" "); - var arr = new Int16Array(elemStrings.length); - var arrIdx = 0; - for (var j = 0, lenj = elemStrings.length; j < lenj; j++) { - if (elemStrings[j] !== "") { - arr[arrIdx++] = parseInt(elemStrings[j]); - } - } - array.push(arr); + return max_blindex; + }; + + + /* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ + const send_all_trees = (s, lcodes, dcodes, blcodes) => + // deflate_state *s; + // int lcodes, dcodes, blcodes; /* number of codes for each tree */ + { + let rank; /* index in bl_order */ + + //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + // "too many codes"); + //Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + //Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s.bl_tree[bl_order[rank] * 2 + 1]/*.Len*/, 3); + } + //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_ltree, lcodes - 1); /* literal tree */ + //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, s.dyn_dtree, dcodes - 1); /* distance tree */ + //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); + }; + + + /* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ + const detect_data_type = (s) => { + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + let black_mask = 0xf3ffc07f; + let n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>>= 1) { + if ((black_mask & 1) && (s.dyn_ltree[n * 2]/*.Freq*/ !== 0)) { + return Z_BINARY; } } - return array; - } - function parseFloatArray(str, numElems) { - str = str.split(","); - var arr = new Float32Array(str.length * numElems); - var arrIdx = 0; - for (var i = 0, len = str.length; i < len; i++) { - var value = str[i]; - value = value.split(" "); - for (var j = 0, lenj = value.length; j < lenj; j++) { - if (value[j] !== "") { - arr[arrIdx++] = parseFloat(value[j]); - } + /* Check for textual ("white-listed") bytes. */ + if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 || + s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) { + return Z_TEXT; + } + for (n = 32; n < LITERALS$1; n++) { + if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) { + return Z_TEXT; } } - return arr; - } - function parseIntArray(str) { - str = str.trim().split(" "); - var arr = new Int32Array(str.length); - for (var i = 0, len = str.length; i < len; i++) { - var value = str[i]; - arr[i] = parseInt(value); + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; + }; + + + let static_init_done = false; + + /* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ + const _tr_init$1 = (s) => + { + + if (!static_init_done) { + tr_static_init(); + static_init_done = true; } - return arr; - } - function parseSurfaceAttributes(ctx, node, result) { - result.color = [1, 1, 1, 1]; - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Color": - result.color[0] = child.red; - result.color[1] = child.green; - result.color[2] = child.blue; - result.color[3] = child.alpha; - break; - case "MaterialApplication": - var children2 = child.children; - for (var j = 0, lenj = children2.length; j < lenj; j++) { - var child2 = children2[j]; - switch (child2.type) { - case "MaterialId": - var materialId = getIDFromURI(child2.id); - var material = ctx.materials[materialId]; - if (!material) { - ctx.plugin.error("material not found: " + materialId); - } - result.materialId = materialId; - break; - } - } - break; + s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc); + s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc); + s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc); + + s.bi_buf = 0; + s.bi_valid = 0; + + /* Initialize the first block of the first file: */ + init_block(s); + }; + + + /* =========================================================================== + * Send a stored block + */ + const _tr_stored_block$1 = (s, buf, stored_len, last) => + //DeflateState *s; + //charf *buf; /* input block */ + //ulg stored_len; /* length of input block */ + //int last; /* one if this is the last block for a file */ + { + send_bits(s, (STORED_BLOCK << 1) + (last ? 1 : 0), 3); /* send block type */ + copy_block(s, buf, stored_len, true); /* with header */ + }; + + + /* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ + const _tr_align$1 = (s) => { + send_bits(s, STATIC_TREES << 1, 3); + send_code(s, END_BLOCK, static_ltree); + bi_flush(s); + }; + + + /* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ + const _tr_flush_block$1 = (s, buf, stored_len, last) => + //DeflateState *s; + //charf *buf; /* input block, or NULL if too old */ + //ulg stored_len; /* length of input block */ + //int last; /* one if this is the last block for a file */ + { + let opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + let max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s.level > 0) { + + /* Check if the file is binary or text */ + if (s.strm.data_type === Z_UNKNOWN$1) { + s.strm.data_type = detect_data_type(s); } - } - } -})(); -function loadCATMaterialRefDocuments(ctx, materialIds, ok) { - var loaded = {}; + /* Construct the literal and distance trees */ + build_tree(s, s.l_desc); + // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); - function load(i, done) { - if (i >= materialIds.length) { - ok(); - return; + build_tree(s, s.d_desc); + // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + // s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s.opt_len + 3 + 7) >>> 3; + static_lenb = (s.static_len + 3 + 7) >>> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + // s->last_lit)); + + if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; } + + } else { + // Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ } - var materialId = materialIds[i]; - var src = materialId.id; - var colonIdx = src.lastIndexOf(":"); - if (colonIdx > 0) { - src = src.substring(colonIdx + 1); + + if ((stored_len + 4 <= opt_lenb) && (buf !== -1)) { + /* 4: two words for the lengths */ + + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block$1(s, buf, stored_len, last); + + } else if (s.strategy === Z_FIXED$1 || static_lenb === opt_lenb) { + + send_bits(s, (STATIC_TREES << 1) + (last ? 1 : 0), 3); + compress_block(s, static_ltree, static_dtree); + + } else { + send_bits(s, (DYN_TREES << 1) + (last ? 1 : 0), 3); + send_all_trees(s, s.l_desc.max_code + 1, s.d_desc.max_code + 1, max_blindex + 1); + compress_block(s, s.dyn_ltree, s.dyn_dtree); } - var hashIdx = src.lastIndexOf("#"); - if (hashIdx > 0) { - src = src.substring(0, hashIdx); + // Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); } - if (!loaded[src]) { - loadCATMaterialRefDocument(ctx, src, function () { - loaded[src] = true; - load(i + 1); - }); + // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + // s->compressed_len-7*last)); + }; + + /* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ + const _tr_tally$1 = (s, dist, lc) => + // deflate_state *s; + // unsigned dist; /* distance of matched string */ + // unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + { + //let out_length, in_length, dcode; + + s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff; + s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff; + + s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff; + s.last_lit++; + + if (dist === 0) { + /* lc is the unmatched char */ + s.dyn_ltree[lc * 2]/*.Freq*/++; } else { - load(i + 1); - } - } + s.matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + //Assert((ush)dist < (ush)MAX_DIST(s) && + // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s.dyn_ltree[(_length_code[lc] + LITERALS$1 + 1) * 2]/*.Freq*/++; + s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++; + } + + // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + + //#ifdef TRUNCATE_BLOCK + // /* Try to guess if it is profitable to stop the current block here */ + // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) { + // /* Compute an upper bound for the compressed length */ + // out_length = s.last_lit*8; + // in_length = s.strstart - s.block_start; + // + // for (dcode = 0; dcode < D_CODES; dcode++) { + // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]); + // } + // out_length >>>= 3; + // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + // // s->last_lit, in_length, out_length, + // // 100L - out_length*100L/in_length)); + // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) { + // return true; + // } + // } + //#endif - load(0); -} + return (s.last_lit === s.lit_bufsize - 1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ + }; -function loadCATMaterialRefDocument(ctx, src, ok) { // Loads CATMaterialRef.3dxml - ctx.zip.getFile(src, function (xmlDoc, json) { - parseCATMaterialRefDocument(ctx, json, ok); - }); -} + var _tr_init_1 = _tr_init$1; + var _tr_stored_block_1 = _tr_stored_block$1; + var _tr_flush_block_1 = _tr_flush_block$1; + var _tr_tally_1 = _tr_tally$1; + var _tr_align_1 = _tr_align$1; + + var trees = { + _tr_init: _tr_init_1, + _tr_stored_block: _tr_stored_block_1, + _tr_flush_block: _tr_flush_block_1, + _tr_tally: _tr_tally_1, + _tr_align: _tr_align_1 + }; -function parseCATMaterialRefDocument(ctx, node, ok) { // Parse CATMaterialRef.3dxml - // ctx.plugin.log("parseCATMaterialRefDocument"); - var children = node.children; - var child; - for (var i = 0, len = children.length; i < len; i++) { - child = children[i]; - if (child.type === "Model_3dxml") { - parseModel_3dxml(ctx, child, ok); - } - } -} + // Note: adler32 takes 12% for level 0 and 2% for level 6. + // It isn't worth it to make additional optimizations as in original. + // Small size is preferable. -function parseModel_3dxml(ctx, node, ok) { // Parse CATMaterialRef.3dxml - // ctx.plugin.log("parseModel_3dxml"); - var children = node.children; - var child; - for (var i = 0, len = children.length; i < len; i++) { - child = children[i]; - if (child.type === "CATMaterialRef") { - parseCATMaterialRef(ctx, child, ok); + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + const adler32 = (adler, buf, len, pos) => { + let s1 = (adler & 0xffff) |0, + s2 = ((adler >>> 16) & 0xffff) |0, + n = 0; + + while (len !== 0) { + // Set limit ~ twice less than 5552, to keep + // s2 in 31-bits, because we force signed ints. + // in other case %= will fail. + n = len > 2000 ? 2000 : len; + len -= n; + + do { + s1 = (s1 + buf[pos++]) |0; + s2 = (s2 + s1) |0; + } while (--n); + + s1 %= 65521; + s2 %= 65521; } - } -} -function parseCATMaterialRef(ctx, node, ok) { - var domainToReferenceMap = {}; - var children = node.children; - var numToLoad = 0; - for (var j = 0, lenj = children.length; j < lenj; j++) { - var child2 = children[j]; - switch (child2.type) { - case "MaterialDomainInstance": - var isAggregatedBy; - var isInstanceOf; - for (var k = 0, lenk = child2.children.length; k < lenk; k++) { - var child3 = child2.children[k]; - switch (child3.type) { - case "IsAggregatedBy": - isAggregatedBy = child3.children[0]; - break; - case "IsInstanceOf": - isInstanceOf = child3.children[0]; - break; - } - } - domainToReferenceMap[isInstanceOf] = isAggregatedBy; - break; + return (s1 | (s2 << 16)) |0; + }; + + + var adler32_1 = adler32; + + // Note: we can't get significant speed boost here. + // So write code to minimize size - no pregenerated tables + // and array tools dependencies. + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // Use ordinary array, since untyped makes no boost here + const makeTable = () => { + let c, table = []; + + for (var n = 0; n < 256; n++) { + c = n; + for (var k = 0; k < 8; k++) { + c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1)); + } + table[n] = c; } - } - for (var j = 0, lenj = children.length; j < lenj; j++) { - var child2 = children[j]; - switch (child2.type) { - case "MaterialDomain": - numToLoad++; - break; + + return table; + }; + + // Create table on load. Just 255 signed longs. Not a problem. + const crcTable = new Uint32Array(makeTable()); + + + const crc32 = (crc, buf, len, pos) => { + const t = crcTable; + const end = pos + len; + + crc ^= -1; + + for (let i = pos; i < end; i++) { + crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF]; } - } - // Now load them - for (var j = 0, lenj = children.length; j < lenj; j++) { - var child2 = children[j]; - switch (child2.type) { - case "MaterialDomain": - if (child2.associatedFile) { - (function () { - var childId = child2.id; - var src = stripURN(child2.associatedFile); - ctx.zip.getFile(src, function (xmlDoc, json) { - // ctx.plugin.log("Material def loaded: " + src); - ctx.materials[domainToReferenceMap[childId]] = parseMaterialDefDocument(ctx, json); - if (--numToLoad === 0) { - // console.log("All ReferenceReps loaded."); - ok(); - } - }, - function (error) { - // TODO: - }); - })(); - } - break; + return (crc ^ (-1)); // >>> 0; + }; + + + var crc32_1 = crc32; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + var messages = { + 2: 'need dictionary', /* Z_NEED_DICT 2 */ + 1: 'stream end', /* Z_STREAM_END 1 */ + 0: '', /* Z_OK 0 */ + '-1': 'file error', /* Z_ERRNO (-1) */ + '-2': 'stream error', /* Z_STREAM_ERROR (-2) */ + '-3': 'data error', /* Z_DATA_ERROR (-3) */ + '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */ + '-5': 'buffer error', /* Z_BUF_ERROR (-5) */ + '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */ + }; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + var constants$2 = { + + /* Allowed flush values; see deflate() and inflate() below for details */ + Z_NO_FLUSH: 0, + Z_PARTIAL_FLUSH: 1, + Z_SYNC_FLUSH: 2, + Z_FULL_FLUSH: 3, + Z_FINISH: 4, + Z_BLOCK: 5, + Z_TREES: 6, + + /* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + Z_OK: 0, + Z_STREAM_END: 1, + Z_NEED_DICT: 2, + Z_ERRNO: -1, + Z_STREAM_ERROR: -2, + Z_DATA_ERROR: -3, + Z_MEM_ERROR: -4, + Z_BUF_ERROR: -5, + //Z_VERSION_ERROR: -6, + + /* compression levels */ + Z_NO_COMPRESSION: 0, + Z_BEST_SPEED: 1, + Z_BEST_COMPRESSION: 9, + Z_DEFAULT_COMPRESSION: -1, + + + Z_FILTERED: 1, + Z_HUFFMAN_ONLY: 2, + Z_RLE: 3, + Z_FIXED: 4, + Z_DEFAULT_STRATEGY: 0, + + /* Possible values of the data_type field (though see inflate()) */ + Z_BINARY: 0, + Z_TEXT: 1, + //Z_ASCII: 1, // = Z_TEXT (deprecated) + Z_UNKNOWN: 2, + + /* The deflate compression method */ + Z_DEFLATED: 8 + //Z_NULL: null // Use -1 or null inline, depending on var type + }; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + const { _tr_init, _tr_stored_block, _tr_flush_block, _tr_tally, _tr_align } = trees; + + + + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + const { + Z_NO_FLUSH: Z_NO_FLUSH$2, Z_PARTIAL_FLUSH, Z_FULL_FLUSH: Z_FULL_FLUSH$1, Z_FINISH: Z_FINISH$3, Z_BLOCK: Z_BLOCK$1, + Z_OK: Z_OK$3, Z_STREAM_END: Z_STREAM_END$3, Z_STREAM_ERROR: Z_STREAM_ERROR$2, Z_DATA_ERROR: Z_DATA_ERROR$2, Z_BUF_ERROR: Z_BUF_ERROR$1, + Z_DEFAULT_COMPRESSION: Z_DEFAULT_COMPRESSION$1, + Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED, Z_DEFAULT_STRATEGY: Z_DEFAULT_STRATEGY$1, + Z_UNKNOWN, + Z_DEFLATED: Z_DEFLATED$2 + } = constants$2; + + /*============================================================================*/ + + + const MAX_MEM_LEVEL = 9; + /* Maximum value for memLevel in deflateInit2 */ + const MAX_WBITS$1 = 15; + /* 32K LZ77 window */ + const DEF_MEM_LEVEL = 8; + + + const LENGTH_CODES = 29; + /* number of length codes, not counting the special END_BLOCK code */ + const LITERALS = 256; + /* number of literal bytes 0..255 */ + const L_CODES = LITERALS + 1 + LENGTH_CODES; + /* number of Literal or Length codes, including the END_BLOCK code */ + const D_CODES = 30; + /* number of distance codes */ + const BL_CODES = 19; + /* number of codes used to transfer the bit lengths */ + const HEAP_SIZE = 2 * L_CODES + 1; + /* maximum heap size */ + const MAX_BITS = 15; + /* All codes must not exceed MAX_BITS bits */ + + const MIN_MATCH = 3; + const MAX_MATCH = 258; + const MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1); + + const PRESET_DICT = 0x20; + + const INIT_STATE = 42; + const EXTRA_STATE = 69; + const NAME_STATE = 73; + const COMMENT_STATE = 91; + const HCRC_STATE = 103; + const BUSY_STATE = 113; + const FINISH_STATE = 666; + + const BS_NEED_MORE = 1; /* block not completed, need more input or more output */ + const BS_BLOCK_DONE = 2; /* block flush performed */ + const BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */ + const BS_FINISH_DONE = 4; /* finish done, accept no more input or output */ + + const OS_CODE = 0x03; // Unix :) . Don't detect, use this default. + + const err = (strm, errorCode) => { + strm.msg = messages[errorCode]; + return errorCode; + }; + + const rank = (f) => { + return ((f) << 1) - ((f) > 4 ? 9 : 0); + }; + + const zero = (buf) => { + let len = buf.length; while (--len >= 0) { buf[len] = 0; } + }; + + + /* eslint-disable new-cap */ + let HASH_ZLIB = (s, prev, data) => ((prev << s.hash_shift) ^ data) & s.hash_mask; + // This hash causes less collisions, https://github.com/nodeca/pako/issues/135 + // But breaks binary compatibility + //let HASH_FAST = (s, prev, data) => ((prev << 8) + (prev >> 8) + (data << 4)) & s.hash_mask; + let HASH = HASH_ZLIB; + + /* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->output buffer and copying into it. + * (See also read_buf()). + */ + const flush_pending = (strm) => { + const s = strm.state; + + //_tr_flush_bits(s); + let len = s.pending; + if (len > strm.avail_out) { + len = strm.avail_out; + } + if (len === 0) { return; } + + strm.output.set(s.pending_buf.subarray(s.pending_out, s.pending_out + len), strm.next_out); + strm.next_out += len; + s.pending_out += len; + strm.total_out += len; + strm.avail_out -= len; + s.pending -= len; + if (s.pending === 0) { + s.pending_out = 0; } - } -} + }; -function parseMaterialDefDocument(ctx, node) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "Osm": - return parseMaterialDefDocumentOsm(ctx, child); + + const flush_block_only = (s, last) => { + _tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last); + s.block_start = s.strstart; + flush_pending(s.strm); + }; + + + const put_byte = (s, b) => { + s.pending_buf[s.pending++] = b; + }; + + + /* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ + const putShortMSB = (s, b) => { + + // put_byte(s, (Byte)(b >> 8)); + // put_byte(s, (Byte)(b & 0xff)); + s.pending_buf[s.pending++] = (b >>> 8) & 0xff; + s.pending_buf[s.pending++] = b & 0xff; + }; + + + /* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->input buffer and copying from it. + * (See also flush_pending()). + */ + const read_buf = (strm, buf, start, size) => { + + let len = strm.avail_in; + + if (len > size) { len = size; } + if (len === 0) { return 0; } + + strm.avail_in -= len; + + // zmemcpy(buf, strm->next_in, len); + buf.set(strm.input.subarray(strm.next_in, strm.next_in + len), start); + if (strm.state.wrap === 1) { + strm.adler = adler32_1(strm.adler, buf, len, start); } - } -} -function parseMaterialDefDocumentOsm(ctx, node) { - var children = node.children; - for (var i = 0, len = children.length; i < len; i++) { - var child = children[i]; - switch (child.type) { - case "RenderingRootFeature": - //.. + else if (strm.state.wrap === 2) { + strm.adler = crc32_1(strm.adler, buf, len, start); + } + + strm.next_in += len; + strm.total_in += len; + + return len; + }; + + + /* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ + const longest_match = (s, cur_match) => { + + let chain_length = s.max_chain_length; /* max hash chain length */ + let scan = s.strstart; /* current string */ + let match; /* matched string */ + let len; /* length of current match */ + let best_len = s.prev_length; /* best match length so far */ + let nice_match = s.nice_match; /* stop if match long enough */ + const limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ? + s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/; + + const _win = s.window; // shortcut + + const wmask = s.w_mask; + const prev = s.prev; + + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + + const strend = s.strstart + MAX_MATCH; + let scan_end1 = _win[scan + best_len - 1]; + let scan_end = _win[scan + best_len]; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s.prev_length >= s.good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if (nice_match > s.lookahead) { nice_match = s.lookahead; } + + // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + // Assert(cur_match < s->strstart, "no future"); + match = cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + + if (_win[match + best_len] !== scan_end || + _win[match + best_len - 1] !== scan_end1 || + _win[match] !== _win[scan] || + _win[++match] !== _win[scan + 1]) { + continue; + } + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2; + match++; + // Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + /*jshint noempty:false*/ + } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + _win[++scan] === _win[++match] && _win[++scan] === _win[++match] && + scan < strend); + + // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (strend - scan); + scan = strend - MAX_MATCH; + + if (len > best_len) { + s.match_start = cur_match; + best_len = len; + if (len >= nice_match) { + break; + } + scan_end1 = _win[scan + best_len - 1]; + scan_end = _win[scan + best_len]; + } + } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0); + + if (best_len <= s.lookahead) { + return best_len; + } + return s.lookahead; + }; + + + /* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ + const fill_window = (s) => { + + const _w_size = s.w_size; + let p, n, m, more, str; + + //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = s.window_size - s.lookahead - s.strstart; + + // JS ints have 32 bit, block below not needed + /* Deal with !@#$% 64K limit: */ + //if (sizeof(int) <= 2) { + // if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + // more = wsize; + // + // } else if (more == (unsigned)(-1)) { + // /* Very unlikely, but possible on 16 bit machine if + // * strstart == 0 && lookahead == 1 (input done a byte at time) + // */ + // more--; + // } + //} + + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) { + + s.window.set(s.window.subarray(_w_size, _w_size + _w_size), 0); + s.match_start -= _w_size; + s.strstart -= _w_size; + /* we now have strstart >= MAX_DIST */ + s.block_start -= _w_size; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + + n = s.hash_size; + p = n; + + do { + m = s.head[--p]; + s.head[p] = (m >= _w_size ? m - _w_size : 0); + } while (--n); + + n = _w_size; + p = n; + + do { + m = s.prev[--p]; + s.prev[p] = (m >= _w_size ? m - _w_size : 0); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += _w_size; + } + if (s.strm.avail_in === 0) { break; - case "Feature": + } - if (child.Alias === "RenderingFeature") { - // Parse the coefficients, then parse the colors, scaling those by their coefficients. - var coeffs = {}; - var materialCfg = {}; - var children2 = child.children; - var j; - var lenj; - var child2; - for (j = 0, lenj = children2.length; j < lenj; j++) { - child2 = children2[j]; - switch (child2.Name) { - case "AmbientCoef": - coeffs.ambient = parseFloat(child2.Value); - break; - case "DiffuseCoef": - coeffs.diffuse = parseFloat(child2.Value); - break; - case "EmissiveCoef": - coeffs.emissive = parseFloat(child2.Value); - break; - case "SpecularExponent": - coeffs.specular = parseFloat(child2.Value); - break; - } - } - for (j = 0, lenj = children2.length; j < lenj; j++) { - child2 = children2[j]; - switch (child2.Name) { - case "AmbientColor": - materialCfg.ambient = parseRGB(child2.Value, coeffs.ambient); - break; - case "DiffuseColor": - materialCfg.diffuse = parseRGB(child2.Value, coeffs.diffuse); - break; - case "EmissiveColor": - materialCfg.emissive = parseRGB(child2.Value, coeffs.emissive); - break; - case "SpecularColor": - materialCfg.specular = parseRGB(child2.Value, coeffs.specular); - break; - case "Transparency": - var alpha = 1.0 - parseFloat(child2.Value); // GOTCHA: Degree of transparency, not degree of opacity - if (alpha < 1.0) { - materialCfg.alpha = alpha; - materialCfg.alphaMode = "blend"; - } - break; - } + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + //Assert(more >= 2, "more < 2"); + n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more); + s.lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s.lookahead + s.insert >= MIN_MATCH) { + str = s.strstart - s.insert; + s.ins_h = s.window[str]; + + /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + 1]); + //#if MIN_MATCH != 3 + // Call update_hash() MIN_MATCH-3 more times + //#endif + while (s.insert) { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = str; + str++; + s.insert--; + if (s.lookahead + s.insert < MIN_MATCH) { + break; } + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ - var material; + } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0); - switch (ctx.materialType) { - case "MetallicMaterial": - material = new MetallicMaterial(ctx.modelNode, { - baseColor: materialCfg.diffuse, - metallic: 0.7, - roughness: 0.5, - emissive: materialCfg.emissive, - alpha: materialCfg.alpha, - alphaMode: materialCfg.alphaMode - }); - break; + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + // if (s.high_water < s.window_size) { + // const curr = s.strstart + s.lookahead; + // let init = 0; + // + // if (s.high_water < curr) { + // /* Previous high water mark below current data -- zero WIN_INIT + // * bytes or up to end of window, whichever is less. + // */ + // init = s.window_size - curr; + // if (init > WIN_INIT) + // init = WIN_INIT; + // zmemzero(s->window + curr, (unsigned)init); + // s->high_water = curr + init; + // } + // else if (s->high_water < (ulg)curr + WIN_INIT) { + // /* High water mark at or above current data, but below current data + // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + // * to end of window, whichever is less. + // */ + // init = (ulg)curr + WIN_INIT - s->high_water; + // if (init > s->window_size - s->high_water) + // init = s->window_size - s->high_water; + // zmemzero(s->window + s->high_water, (unsigned)init); + // s->high_water += init; + // } + // } + // + // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + // "not enough room for search"); + }; - case "SpecularMaterial": - material = new SpecularMaterial(ctx.modelNode, { - diffuse: materialCfg.diffuse, - specular: materialCfg.specular, - glossiness: 0.5, - emissive: materialCfg.emissive, - alpha: materialCfg.alpha, - alphaMode: materialCfg.alphaMode - }); - break; + /* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ + const deflate_stored = (s, flush) => { - default: - material = new PhongMaterial(ctx.modelNode, { - reflectivity: 0.5, - ambient: materialCfg.ambient, - diffuse: materialCfg.diffuse, - specular: materialCfg.specular, - // shininess: node.shine, - emissive: materialCfg.emissive, - alphaMode: materialCfg.alphaMode, - alpha: node.alpha - }); - } - return material; + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + let max_block_size = 0xffff; + + if (max_block_size > s.pending_buf_size - 5) { + max_block_size = s.pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s.lookahead <= 1) { + + //Assert(s->strstart < s->w_size+MAX_DIST(s) || + // s->block_start >= (long)s->w_size, "slide too late"); + // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) || + // s.block_start >= s.w_size)) { + // throw new Error("slide too late"); + // } + + fill_window(s); + if (s.lookahead === 0 && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; } - break; + + if (s.lookahead === 0) { + break; + } + /* flush the current block */ + } + //Assert(s->block_start >= 0L, "block gone"); + // if (s.block_start < 0) throw new Error("block gone"); + + s.strstart += s.lookahead; + s.lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + const max_start = s.block_start + max_block_size; + + if (s.strstart === 0 || s.strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s.lookahead = s.strstart - max_start; + s.strstart = max_start; + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + + + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } } - } -} -function parseRGB(str, coeff) { - coeff = (coeff !== undefined) ? coeff : 0.5; - var openBracketIndex = str.indexOf("["); - var closeBracketIndex = str.indexOf("]"); - str = str.substring(openBracketIndex + 1, closeBracketIndex - openBracketIndex); - str = str.split(","); - var arr = new Float32Array(str.length); - var arrIdx = 0; - for (var i = 0, len = str.length; i < len; i++) { - var value = str[i]; - value = value.trim().split(" "); - for (var j = 0, lenj = value.length; j < lenj; j++) { - if (value[j] !== "") { - arr[arrIdx++] = parseFloat(value[j]) * coeff; + s.insert = 0; + + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; } + /***/ + return BS_FINISH_DONE; } - } - return arr; -} + if (s.strstart > s.block_start) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } -//---------------------------------------------------------------------------------------------------- + return BS_NEED_MORE; + }; -/** - * Wraps zip.js to provide an in-memory ZIP archive representing the 3DXML file bundle. - * - * Allows us to pluck each file from it as XML and JSON. - * - * @constructor - */ -var ZIP = function () { + /* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ + const deflate_fast = (s, flush) => { - var reader; - var files = {}; + let hash_head; /* head of the hash chain */ + let bflush; /* set if current block must be flushed */ - /** - Loads this ZIP + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { + break; /* flush the current block */ + } + } - @param src - @param ok - @param error - */ - this.load = function (src, ok, error) { - zip.createReader(new zip.HttpReader(src), function (reader) { - reader.getEntries(function (entries) { - if (entries.length > 0) { - for (var i = 0, len = entries.length; i < len; i++) { - var entry = entries[i]; - files[entry.filename] = entry; - } + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + } + if (s.match_length >= MIN_MATCH) { + // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only + + /*** _tr_tally_dist(s, s.strstart - s.match_start, + s.match_length - MIN_MATCH, bflush); ***/ + bflush = _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) { + s.match_length--; /* string at strstart already in table */ + do { + s.strstart++; + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s.match_length !== 0); + s.strstart++; + } else + { + s.strstart += s.match_length; + s.match_length = 0; + s.ins_h = s.window[s.strstart]; + /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + 1]); + + //#if MIN_MATCH != 3 + // Call UPDATE_HASH() MIN_MATCH-3 more times + //#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ } - ok(); - }); - }, error); + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s.window[s.strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = ((s.strstart < (MIN_MATCH - 1)) ? s.strstart : MIN_MATCH - 1); + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; }; - /** - Gets a file as XML and JSON from this ZIP - @param src - @param ok - @param error - */ - this.getFile = function (src, ok, error) { - var entry = files[src]; - if (!entry) { - var errMsg = "ZIP entry not found: " + src; - console.error(errMsg); - if (error) { - error(errMsg); + /* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ + const deflate_slow = (s, flush) => { + + let hash_head; /* head of hash chain */ + let bflush; /* set if current block must be flushed */ + + let max_insert; + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s.lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0/*NIL*/; + if (s.lookahead >= MIN_MATCH) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + + /* Find the longest match, discarding those <= prev_length. + */ + s.prev_length = s.match_length; + s.prev_match = s.match_start; + s.match_length = MIN_MATCH - 1; + + if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match && + s.strstart - hash_head <= (s.w_size - MIN_LOOKAHEAD)/*MAX_DIST(s)*/) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s.match_length = longest_match(s, hash_head); + /* longest_match() sets match_start */ + + if (s.match_length <= 5 && + (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s.match_length = MIN_MATCH - 1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) { + max_insert = s.strstart + s.lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + //check_match(s, s.strstart-1, s.prev_match, s.prev_length); + + /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match, + s.prev_length - MIN_MATCH, bflush);***/ + bflush = _tr_tally(s, s.strstart - 1 - s.prev_match, s.prev_length - MIN_MATCH); + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s.lookahead -= s.prev_length - 1; + s.prev_length -= 2; + do { + if (++s.strstart <= max_insert) { + /*** INSERT_STRING(s, s.strstart, hash_head); ***/ + s.ins_h = HASH(s, s.ins_h, s.window[s.strstart + MIN_MATCH - 1]); + hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h]; + s.head[s.ins_h] = s.strstart; + /***/ + } + } while (--s.prev_length !== 0); + s.match_available = 0; + s.match_length = MIN_MATCH - 1; + s.strstart++; + + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + + } else if (s.match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); + + if (bflush) { + /*** FLUSH_BLOCK_ONLY(s, 0) ***/ + flush_block_only(s, false); + /***/ + } + s.strstart++; + s.lookahead--; + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s.match_available = 1; + s.strstart++; + s.lookahead--; } - return; } - entry.getData(new zip.TextWriter(), function (text) { + //Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s.match_available) { + //Tracevv((stderr,"%c", s->window[s->strstart-1])); + /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart - 1]); - // Parse to XML - var parser = new DOMParser(); - var xmlDoc = parser.parseFromString(text, "text/xml"); + s.match_available = 0; + } + s.insert = s.strstart < MIN_MATCH - 1 ? s.strstart : MIN_MATCH - 1; + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } - // Parse to JSON - var json = xmlToJSON(xmlDoc, {}); + return BS_BLOCK_DONE; + }; - ok(xmlDoc, json); - }); + + /* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ + const deflate_rle = (s, flush) => { + + let bflush; /* set if current block must be flushed */ + let prev; /* byte at distance one to match */ + let scan, strend; /* scan goes up to strend for length of run */ + + const _win = s.window; + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s.lookahead <= MAX_MATCH) { + fill_window(s); + if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + if (s.lookahead === 0) { break; } /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s.match_length = 0; + if (s.lookahead >= MIN_MATCH && s.strstart > 0) { + scan = s.strstart - 1; + prev = _win[scan]; + if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) { + strend = s.strstart + MAX_MATCH; + do { + /*jshint noempty:false*/ + } while (prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + prev === _win[++scan] && prev === _win[++scan] && + scan < strend); + s.match_length = MAX_MATCH - (strend - scan); + if (s.match_length > s.lookahead) { + s.match_length = s.lookahead; + } + } + //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s.match_length >= MIN_MATCH) { + //check_match(s, s.strstart, s.strstart - 1, s.match_length); + + /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/ + bflush = _tr_tally(s, 1, s.match_length - MIN_MATCH); + + s.lookahead -= s.match_length; + s.strstart += s.match_length; + s.match_length = 0; + } else { + /* No match, output a literal byte */ + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + + s.lookahead--; + s.strstart++; + } + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + } + s.insert = 0; + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; + } + /***/ + return BS_FINISH_DONE; + } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; }; - function xmlToJSON(node, attributeRenamer) { - if (node.nodeType === node.TEXT_NODE) { - var v = node.nodeValue; - if (v.match(/^\s+$/) === null) { - return v; + /* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ + const deflate_huff = (s, flush) => { + + let bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s.lookahead === 0) { + fill_window(s); + if (s.lookahead === 0) { + if (flush === Z_NO_FLUSH$2) { + return BS_NEED_MORE; + } + break; /* flush the current block */ + } } - } else if (node.nodeType === node.ELEMENT_NODE || - node.nodeType === node.DOCUMENT_NODE) { - var json = {type: node.nodeName, children: []}; - if (node.nodeType === node.ELEMENT_NODE) { - for (var j = 0; j < node.attributes.length; j++) { - var attribute = node.attributes[j]; - var nm = attributeRenamer[attribute.nodeName] || attribute.nodeName; - json[nm] = attribute.nodeValue; + + /* Output a literal byte */ + s.match_length = 0; + //Tracevv((stderr,"%c", s->window[s->strstart])); + /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/ + bflush = _tr_tally(s, 0, s.window[s.strstart]); + s.lookahead--; + s.strstart++; + if (bflush) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; } + /***/ } - for (var i = 0; i < node.childNodes.length; i++) { - var item = node.childNodes[i]; - var j = xmlToJSON(item, attributeRenamer); - if (j) json.children.push(j); + } + s.insert = 0; + if (flush === Z_FINISH$3) { + /*** FLUSH_BLOCK(s, 1); ***/ + flush_block_only(s, true); + if (s.strm.avail_out === 0) { + return BS_FINISH_STARTED; } - return json; + /***/ + return BS_FINISH_DONE; } - } + if (s.last_lit) { + /*** FLUSH_BLOCK(s, 0); ***/ + flush_block_only(s, false); + if (s.strm.avail_out === 0) { + return BS_NEED_MORE; + } + /***/ + } + return BS_BLOCK_DONE; + }; - /** - Disposes of this ZIP + /* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ + function Config(good_length, max_lazy, nice_length, max_chain, func) { + + this.good_length = good_length; + this.max_lazy = max_lazy; + this.nice_length = nice_length; + this.max_chain = max_chain; + this.func = func; + } + + const configuration_table = [ + /* good lazy nice chain */ + new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */ + new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */ + new Config(4, 5, 16, 8, deflate_fast), /* 2 */ + new Config(4, 6, 32, 32, deflate_fast), /* 3 */ + + new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */ + new Config(8, 16, 32, 32, deflate_slow), /* 5 */ + new Config(8, 16, 128, 128, deflate_slow), /* 6 */ + new Config(8, 32, 128, 256, deflate_slow), /* 7 */ + new Config(32, 128, 258, 1024, deflate_slow), /* 8 */ + new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */ + ]; + + + /* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ + const lm_init = (s) => { + + s.window_size = 2 * s.w_size; + + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + + /* Set the default configuration parameters: */ - this.destroy = function () { - reader.close(function () { - // onclose callback - }); + s.max_lazy_match = configuration_table[s.level].max_lazy; + s.good_match = configuration_table[s.level].good_length; + s.nice_match = configuration_table[s.level].nice_length; + s.max_chain_length = configuration_table[s.level].max_chain; + + s.strstart = 0; + s.block_start = 0; + s.lookahead = 0; + s.insert = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + s.ins_h = 0; }; -}; -function -loadZIP(src, ok, err) { - var zip = new ZIP(); - zip.load(src, function () { - ok(zip); - }, function (errMsg) { - err("Error loading ZIP archive: " + errMsg); - }); -} + function DeflateState() { + this.strm = null; /* pointer back to this zlib stream */ + this.status = 0; /* as the name implies */ + this.pending_buf = null; /* output still pending */ + this.pending_buf_size = 0; /* size of pending_buf */ + this.pending_out = 0; /* next pending byte to output to the stream */ + this.pending = 0; /* nb of bytes in the pending buffer */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.gzhead = null; /* gzip header information to write */ + this.gzindex = 0; /* where in extra, name, or comment */ + this.method = Z_DEFLATED$2; /* can only be DEFLATED */ + this.last_flush = -1; /* value of flush param for previous deflate call */ -function + this.w_size = 0; /* LZ77 window size (32K by default) */ + this.w_bits = 0; /* log2(w_size) (8..16) */ + this.w_mask = 0; /* w_size - 1 */ -stripURN(str) { - var subStr = "urn:3DXML:"; - return (str.indexOf(subStr) === 0) ? str.substring(subStr.length) : str; -} + this.window = null; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. + */ + this.window_size = 0; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ -function + this.prev = null; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ -getIDFromURI(str) { - var hashIdx = str.lastIndexOf("#"); - return hashIdx !== -1 ? str.substring(hashIdx + 1) : str; -} + this.head = null; /* Heads of the hash chains or NIL. */ -/** - * {@link Viewer} plugin that loads models from [3DXML](https://en.wikipedia.org/wiki/3DXML) files. - * - * [](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_TreeView) - * - * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_TreeView)] - * - * ## Overview - * - * * Currently supports 3DXML V4.2. - * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. - * * Creates an {@link Entity} for each object within the model, which will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. - * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. - * * Can optionally load a {@link MetaModel} to classify the objects within the model, from which you can create a tree view using the {@link TreeViewPlugin}. - *
    - * Note that the name of this plugin is intentionally munged to "XML3D" because a JavaScript class name cannot begin with a numeral. - * - * An 3DXML model is a zip archive that bundles multiple XML files and assets. Internally, the XML3DLoaderPlugin uses the - * [zip.js](https://gildas-lormeau.github.io/zip.js/) library to unzip them before loading. The zip.js library uses - * [Web workers](https://www.w3.org/TR/workers/) for fast unzipping, so XML3DLoaderPlugin requires that we configure it - * with a ````workerScriptsPath```` property specifying the directory where zip.js keeps its Web worker script. See - * the example for how to do that. - * - * ## Usage - * - * In the example below, we'll use an XML3DLoaderPlugin to load a 3DXML model. When the model has loaded, - * we'll use the {@link CameraFlightAnimation} to fly the {@link Camera} to look at boundary of the model. We'll - * then get the model's {@link Entity} from the {@link Scene} and highlight the whole model. - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_Widget)] - * - * ````javascript - * // Create a xeokit Viewer - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * // Add an XML3DLoaderPlugin to the Viewer - * var plugin = new XML3DLoaderPlugin(viewer, { - * id: "XML3DLoader", // Default value - * workerScriptsPath : "../../src/plugins/XML3DLoader/zipjs/" // Path to zip.js workers dir - * }); - * - * // Load the 3DXML model - * var model = plugin.load({ // Model is an Entity - * id: "myModel", - * src: "./models/xml3d/3dpreview.3dxml", - * scale: [0.1, 0.1, 0.1], - * rotate: [90, 0, 0], - * translate: [100,0,0], - * edges: true - * }); - * - * // When the model has loaded, fit it to view - * model.on("loaded", function() { - * viewer.cameraFlight.flyTo(model); - * }); - * - * // Update properties of the model via the entity - * model.highlighted = true; - * - * // Find the model Entity by ID - * model = viewer.scene.models["myModel"]; - * - * // Destroy the model - * model.destroy(); - * ```` - * ## Loading MetaModels - * - * We have the option to load a {@link MetaModel} that contains a hierarchy of {@link MetaObject}s that classifes the objects within - * our 3DXML model. - * - * This is useful for building a tree view to navigate the objects, using {@link TreeViewPlugin}. - * - * Let's load the model again, this time creating a MetaModel: - * - * ````javascript - * var model = plugin.load({ - * id: "myModel", - * src: "./models/xml3d/3dpreview.3dxml", - * scale: [0.1, 0.1, 0.1], - * rotate: [90, 0, 0], - * translate: [100,0,0], - * edges: true, - * - * createMetaModel: true // <<-------- Create a MetaModel - * }); - * ```` - * - * The MetaModel can then be found on the {@link Viewer}'s {@link MetaScene}, using the model's ID: - * - * ````javascript - * const metaModel = viewer.metaScene.metaModels["myModel"]; - * ```` - * - * Now we can use {@link TreeViewPlugin} to create a tree view to navigate our model's objects: - * - * ````javascript - * import {TreeViewPlugin} from "xeokit-sdk.es.js""xeokit-sdk.es.js"; - * - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("myTreeViewContainer") - * }); - * - * const treeView = new TreeViewPlugin(viewer, { - * containerElement: document.getElementById("treeViewContainer"), - * autoExpandDepth: 3, // Initially expand tree three storeys deep - * hierarchy: "containment", - * autoAddModels: false - * }); - * - * model.on("loaded", () => { - * treeView.addModel(model.id); - * }); - * ```` - * - * Note that only the TreeViewPlugin "containment" hierarchy makes sense for an XML3D model. A "types" hierarchy - * does not make sense because XML3DLoaderPlugin will set each {@link MetaObject#type} to "Default", and "storeys" - * does not make sense because that requires some of the MetaObject#type values to be "IfcBuildingStorey". - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_TreeView)] - * - * ## Material Type - * - * Although 3DXML only supports Phong materials, XML3DLoaderPlugin is able to convert them to physically-based materials. - * - * The plugin supports three material types: - * - * | Material Type | Material Components Loaded | Description | Example | - * |:--------:|:----:|:-----:|:-----:| - * | "PhongMaterial" (default) | {@link PhongMaterial} | Non-physically-correct Blinn-Phong shading model | [Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Phong) | - * | "MetallicMaterial" | {@link MetallicMaterial} | Physically-accurate specular-glossiness shading model | [Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Metallic) | - * | "SpecularMaterial" | {@link SpecularMaterial} | Physically-accurate metallic-roughness shading model | [Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Specular) | - * - *
    - * Let's load our model again, this time converting the 3DXML Blinn-Phong materials to {@link SpecularMaterial}s: - * - * ````javascript - * var model = plugin.load({ // Model is an Entity - * id: "myModel", - * src: "./models/xml3d/3dpreview.3dxml", - * materialtype: "SpecularMaterial": true" - * }); - * ```` - * - * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Specular)] - * - * @class XML3DLoaderPlugin - */ + this.ins_h = 0; /* hash index of string to be inserted */ + this.hash_size = 0; /* number of elements in hash table */ + this.hash_bits = 0; /* log2(hash_size) */ + this.hash_mask = 0; /* hash_size-1 */ -class XML3DLoaderPlugin extends Plugin { + this.hash_shift = 0; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ - /** - * @constructor - * @param {Viewer} viewer The Viewer. - * @param {Object} cfg Plugin configuration. - * @param {String} [cfg.id="XML3DLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. - * @param {String} cfg.workerScriptsPath Path to the directory that contains the - * bundled [zip.js](https://gildas-lormeau.github.io/zip.js/) archive, which is a dependency of this plugin. This directory - * contains the script that is used by zip.js to instantiate Web workers, which assist with unzipping the 3DXML, which is a ZIP archive. - * @param {String} [cfg.materialType="PhongMaterial"] What type of materials to create while loading: "MetallicMaterial" to create {@link MetallicMaterial}s, "SpecularMaterial" to create {@link SpecularMaterial}s or "PhongMaterial" to create {@link PhongMaterial}s. As it loads XML3D's Phong materials, the XMLLoaderPlugin will do its best approximate conversion of those to the specified workflow. - * @param {Boolean} [cfg.createMetaModel=false] When true, will create a {@link MetaModel} for the model in {@link MetaScene#metaModels}. + this.block_start = 0; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. */ - constructor(viewer, cfg = {}) { - super("XML3DLoader", viewer, cfg); + this.match_length = 0; /* length of best match */ + this.prev_match = 0; /* previous match */ + this.match_available = 0; /* set if previous match exists */ + this.strstart = 0; /* start of string to insert */ + this.match_start = 0; /* start of matching string */ + this.lookahead = 0; /* number of valid bytes ahead in window */ - if (!cfg.workerScriptsPath) { - this.error("Config expected: workerScriptsPath"); - return - } + this.prev_length = 0; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ - this._workerScriptsPath = cfg.workerScriptsPath; + this.max_chain_length = 0; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ - /** - * @private - */ - this._loader = new XML3DSceneGraphLoader(this, cfg); + this.max_lazy_match = 0; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ + // That's alias to max_lazy_match, don't use directly + //this.max_insert_length = 0; + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ - /** - * Supported 3DXML schema versions - * @property supportedSchemas - * @type {string[]} - */ - this.supportedSchemas = this._loader.supportedSchemas; - } + this.level = 0; /* compression level (1..9) */ + this.strategy = 0; /* favor or force Huffman coding*/ - /** - * Loads a 3DXML model from a file into this XML3DLoaderPlugin's {@link Viewer}. - * - * Creates a tree of {@link Entity}s within the Viewer's {@link Scene} that represents the model. - * - * @param {*} params Loading parameters. - * @param {String} params.id ID to assign to the model's root {@link Entity}, unique among all components in the Viewer's {@link Scene}. - * @param {String} [params.src] Path to a 3DXML file. - * @param {Boolean} [params.edges=false] Whether or not xeokit renders the {@link Entity} with edges emphasized. - * @param {Number[]} [params.position=[0,0,0]] The model's World-space 3D position. - * @param {Number[]} [params.scale=[1,1,1]] The model's World-space scale. - * @param {Number[]} [params.rotation=[0,0,0]] The model's World-space rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. - * @param {Boolean} [params.backfaces=false] When true, allows visible backfaces, wherever specified in the 3DXML. When false, ignores backfaces. - * @param {Number} [params.edgeThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. - * @param {String} [params.materialType="PhongMaterial"] What type of materials to create while loading: "MetallicMaterial" to create {@link MetallicMaterial}s, "SpecularMaterial" to create {@link SpecularMaterial}s or "PhongMaterial" to create {@link PhongMaterial}s. As it loads XML3D's Phong materials, the XMLLoaderPlugin will do its best approximate conversion of those to the specified workflow. - * @param {Boolean} [params.createMetaModel=false] When true, will create a {@link MetaModel} for the model in {@link MetaScene#metaModels}. - * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} + this.good_match = 0; + /* Use a faster search when the previous match is longer than this */ + + this.nice_match = 0; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + + /* Didn't use ct_data typedef below to suppress compiler warning */ + + // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + // Use flat array of DOUBLE size, with interleaved fata, + // because JS does not support effective + this.dyn_ltree = new Uint16Array(HEAP_SIZE * 2); + this.dyn_dtree = new Uint16Array((2 * D_CODES + 1) * 2); + this.bl_tree = new Uint16Array((2 * BL_CODES + 1) * 2); + zero(this.dyn_ltree); + zero(this.dyn_dtree); + zero(this.bl_tree); + + this.l_desc = null; /* desc. for literal tree */ + this.d_desc = null; /* desc. for distance tree */ + this.bl_desc = null; /* desc. for bit length tree */ + + //ush bl_count[MAX_BITS+1]; + this.bl_count = new Uint16Array(MAX_BITS + 1); + /* number of codes at each bit length for an optimal tree */ + + //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + this.heap = new Uint16Array(2 * L_CODES + 1); /* heap used to build the Huffman trees */ + zero(this.heap); + + this.heap_len = 0; /* number of elements in the heap */ + this.heap_max = 0; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. */ - load(params = {}) { - params.workerScriptsPath = this._workerScriptsPath; + this.depth = new Uint16Array(2 * L_CODES + 1); //uch depth[2*L_CODES+1]; + zero(this.depth); + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ - if (params.id && this.viewer.scene.components[params.id]) { - this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); - delete params.id; + this.l_buf = 0; /* buffer index for literals or lengths */ + + this.lit_bufsize = 0; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + this.last_lit = 0; /* running index in l_buf */ + + this.d_buf = 0; + /* Buffer index for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + this.opt_len = 0; /* bit length of current block with optimal trees */ + this.static_len = 0; /* bit length of current block with static trees */ + this.matches = 0; /* number of string matches in current block */ + this.insert = 0; /* bytes at end of window left to insert */ + + + this.bi_buf = 0; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + this.bi_valid = 0; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + // Used for window memory init. We safely ignore it for JS. That makes + // sense only for pointers and memory check tools. + //this.high_water = 0; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + } + + + const deflateResetKeep = (strm) => { + + if (!strm || !strm.state) { + return err(strm, Z_STREAM_ERROR$2); } - const modelNode = new Node$1(this.viewer.scene, utils.apply(params, { - isModel: true - })); + strm.total_in = strm.total_out = 0; + strm.data_type = Z_UNKNOWN; - const src = params.src; + const s = strm.state; + s.pending = 0; + s.pending_out = 0; - if (!src) { - this.error("load() param expected: src"); - return modelNode; // Return new empty model + if (s.wrap < 0) { + s.wrap = -s.wrap; + /* was made negative by deflate(..., Z_FINISH); */ } + s.status = (s.wrap ? INIT_STATE : BUSY_STATE); + strm.adler = (s.wrap === 2) ? + 0 // crc32(0, Z_NULL, 0) + : + 1; // adler32(0, Z_NULL, 0) + s.last_flush = Z_NO_FLUSH$2; + _tr_init(s); + return Z_OK$3; + }; - this._loader.load(this, modelNode, src, params); - return modelNode; - } -} + const deflateReset = (strm) => { -var __defProp = Object.defineProperty; -var __getOwnPropSymbols = Object.getOwnPropertySymbols; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __propIsEnum = Object.prototype.propertyIsEnumerable; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; -var __spreadValues = (a, b) => { - for (var prop in b || (b = {})) - if (__hasOwnProp.call(b, prop)) - __defNormalProp(a, prop, b[prop]); - if (__getOwnPropSymbols) - for (var prop of __getOwnPropSymbols(b)) { - if (__propIsEnum.call(b, prop)) - __defNormalProp(a, prop, b[prop]); - } - return a; -}; -var __require = (x) => { - if (typeof require !== "undefined") - return require(x); - throw new Error('Dynamic require of "' + x + '" is not supported'); -}; -var __commonJS = (cb, mod) => function __require2() { - return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; -var __async = (__this, __arguments, generator) => { - return new Promise((resolve, reject) => { - var fulfilled = (value) => { - try { - step(generator.next(value)); - } catch (e) { - reject(e); - } + const ret = deflateResetKeep(strm); + if (ret === Z_OK$3) { + lm_init(strm.state); + } + return ret; }; - var rejected = (value) => { - try { - step(generator.throw(value)); - } catch (e) { - reject(e); - } + + + const deflateSetHeader = (strm, head) => { + + if (!strm || !strm.state) { return Z_STREAM_ERROR$2; } + if (strm.state.wrap !== 2) { return Z_STREAM_ERROR$2; } + strm.state.gzhead = head; + return Z_OK$3; }; - var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); - step((generator = generator.apply(__this, __arguments)).next()); - }); -}; -// (disabled):crypto -var require_crypto = __commonJS({ - "(disabled):crypto"() { - } -}); -// dist/web-ifc-mt.js -var require_web_ifc_mt = __commonJS({ - "dist/web-ifc-mt.js"(exports, module) { - var WebIFCWasm2 = function() { - var _scriptDir = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : void 0; - if (typeof __filename !== "undefined") - _scriptDir = _scriptDir || __filename; - return function(WebIFCWasm3) { - WebIFCWasm3 = WebIFCWasm3 || {}; - function GROWABLE_HEAP_I8() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAP8; + const deflateInit2 = (strm, level, method, windowBits, memLevel, strategy) => { + + if (!strm) { // === Z_NULL + return Z_STREAM_ERROR$2; } - function GROWABLE_HEAP_U8() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAPU8; + let wrap = 1; + + if (level === Z_DEFAULT_COMPRESSION$1) { + level = 6; } - function GROWABLE_HEAP_I16() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAP16; + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; } - function GROWABLE_HEAP_U16() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAPU16; + + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; } - function GROWABLE_HEAP_I32() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAP32; + + + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED$2 || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return err(strm, Z_STREAM_ERROR$2); } - function GROWABLE_HEAP_U32() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAPU32; + + + if (windowBits === 8) { + windowBits = 9; } - function GROWABLE_HEAP_F32() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAPF32; + /* until 256-byte window bug fixed */ + + const s = new DeflateState(); + + strm.state = s; + s.strm = strm; + + s.wrap = wrap; + s.gzhead = null; + s.w_bits = windowBits; + s.w_size = 1 << s.w_bits; + s.w_mask = s.w_size - 1; + + s.hash_bits = memLevel + 7; + s.hash_size = 1 << s.hash_bits; + s.hash_mask = s.hash_size - 1; + s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH); + + s.window = new Uint8Array(s.w_size * 2); + s.head = new Uint16Array(s.hash_size); + s.prev = new Uint16Array(s.w_size); + + // Don't need mem init magic for JS. + //s.high_water = 0; /* nothing written to s->window yet */ + + s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + s.pending_buf_size = s.lit_bufsize * 4; + + //overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + //s->pending_buf = (uchf *) overlay; + s.pending_buf = new Uint8Array(s.pending_buf_size); + + // It is offset from `s.pending_buf` (size is `s.lit_bufsize * 2`) + //s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s.d_buf = 1 * s.lit_bufsize; + + //s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + s.l_buf = (1 + 2) * s.lit_bufsize; + + s.level = level; + s.strategy = strategy; + s.method = method; + + return deflateReset(strm); + }; + + const deflateInit = (strm, level) => { + + return deflateInit2(strm, level, Z_DEFLATED$2, MAX_WBITS$1, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY$1); + }; + + + const deflate$2 = (strm, flush) => { + + let beg, val; // for gzip header write only + + if (!strm || !strm.state || + flush > Z_BLOCK$1 || flush < 0) { + return strm ? err(strm, Z_STREAM_ERROR$2) : Z_STREAM_ERROR$2; } - function GROWABLE_HEAP_F64() { - if (wasmMemory.buffer != buffer) { - updateGlobalBufferAndViews(wasmMemory.buffer); - } - return HEAPF64; + + const s = strm.state; + + if (!strm.output || + (!strm.input && strm.avail_in !== 0) || + (s.status === FINISH_STATE && flush !== Z_FINISH$3)) { + return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR$1 : Z_STREAM_ERROR$2); } - var Module = typeof WebIFCWasm3 !== "undefined" ? WebIFCWasm3 : {}; - var readyPromiseResolve, readyPromiseReject; - Module["ready"] = new Promise(function(resolve, reject) { - readyPromiseResolve = resolve; - readyPromiseReject = reject; - }); - var moduleOverrides = {}; - var key; - for (key in Module) { - if (Module.hasOwnProperty(key)) { - moduleOverrides[key] = Module[key]; - } - } - var thisProgram = "./this.program"; - var quit_ = function(status, toThrow) { - throw toThrow; - }; - var ENVIRONMENT_IS_WEB = false; - var ENVIRONMENT_IS_WORKER = false; - var ENVIRONMENT_IS_NODE = false; - var ENVIRONMENT_IS_SHELL = false; - ENVIRONMENT_IS_WEB = typeof window === "object"; - ENVIRONMENT_IS_WORKER = typeof importScripts === "function"; - ENVIRONMENT_IS_NODE = typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string"; - ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; - var ENVIRONMENT_IS_PTHREAD = Module["ENVIRONMENT_IS_PTHREAD"] || false; - if (ENVIRONMENT_IS_PTHREAD) { - buffer = Module["buffer"]; - } - var scriptDirectory = ""; - function locateFile(path) { - if (Module["locateFile"]) { - return Module["locateFile"](path, scriptDirectory); - } - return scriptDirectory + path; - } - var read_, readBinary; - var nodeFS; - var nodePath; - if (ENVIRONMENT_IS_NODE) { - if (ENVIRONMENT_IS_WORKER) { - scriptDirectory = __require("path").dirname(scriptDirectory) + "/"; - } else { - scriptDirectory = __dirname + "/"; - } - read_ = function shell_read(filename, binary) { - if (!nodeFS) - nodeFS = __require("fs"); - if (!nodePath) - nodePath = __require("path"); - filename = nodePath["normalize"](filename); - return nodeFS["readFileSync"](filename, binary ? null : "utf8"); - }; - readBinary = function readBinary2(filename) { - var ret = read_(filename, true); - if (!ret.buffer) { - ret = new Uint8Array(ret); + + s.strm = strm; /* just in case */ + const old_flush = s.last_flush; + s.last_flush = flush; + + /* Write the header */ + if (s.status === INIT_STATE) { + + if (s.wrap === 2) { // GZIP header + strm.adler = 0; //crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (!s.gzhead) { // s->gzhead == Z_NULL + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s.status = BUSY_STATE; + } + else { + put_byte(s, (s.gzhead.text ? 1 : 0) + + (s.gzhead.hcrc ? 2 : 0) + + (!s.gzhead.extra ? 0 : 4) + + (!s.gzhead.name ? 0 : 8) + + (!s.gzhead.comment ? 0 : 16) + ); + put_byte(s, s.gzhead.time & 0xff); + put_byte(s, (s.gzhead.time >> 8) & 0xff); + put_byte(s, (s.gzhead.time >> 16) & 0xff); + put_byte(s, (s.gzhead.time >> 24) & 0xff); + put_byte(s, s.level === 9 ? 2 : + (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ? + 4 : 0)); + put_byte(s, s.gzhead.os & 0xff); + if (s.gzhead.extra && s.gzhead.extra.length) { + put_byte(s, s.gzhead.extra.length & 0xff); + put_byte(s, (s.gzhead.extra.length >> 8) & 0xff); + } + if (s.gzhead.hcrc) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending, 0); + } + s.gzindex = 0; + s.status = EXTRA_STATE; + } } - assert(ret.buffer); - return ret; - }; - if (process["argv"].length > 1) { - thisProgram = process["argv"][1].replace(/\\/g, "/"); - } - process["argv"].slice(2); - process["on"]("uncaughtException", function(ex) { - if (!(ex instanceof ExitStatus)) { - throw ex; + else // DEFLATE header + { + let header = (Z_DEFLATED$2 + ((s.w_bits - 8) << 4)) << 8; + let level_flags = -1; + + if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) { + level_flags = 0; + } else if (s.level < 6) { + level_flags = 1; + } else if (s.level === 6) { + level_flags = 2; + } else { + level_flags = 3; + } + header |= (level_flags << 6); + if (s.strstart !== 0) { header |= PRESET_DICT; } + header += 31 - (header % 31); + + s.status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s.strstart !== 0) { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); + } + strm.adler = 1; // adler32(0L, Z_NULL, 0); } - }); - process["on"]("unhandledRejection", abort); - quit_ = function(status) { - process["exit"](status); - }; - Module["inspect"] = function() { - return "[Emscripten Module object]"; - }; - var nodeWorkerThreads; - try { - nodeWorkerThreads = __require("worker_threads"); - } catch (e) { - console.error('The "worker_threads" module is not supported in this node.js build - perhaps a newer version is needed?'); - throw e; - } - global.Worker = nodeWorkerThreads.Worker; - } else if (ENVIRONMENT_IS_SHELL) { - if (typeof read != "undefined") { - read_ = function shell_read(f) { - return read(f); - }; - } - readBinary = function readBinary2(f) { - var data; - if (typeof readbuffer === "function") { - return new Uint8Array(readbuffer(f)); + } + + //#ifdef GZIP + if (s.status === EXTRA_STATE) { + if (s.gzhead.extra/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + + while (s.gzindex < (s.gzhead.extra.length & 0xffff)) { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + break; + } + } + put_byte(s, s.gzhead.extra[s.gzindex] & 0xff); + s.gzindex++; + } + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (s.gzindex === s.gzhead.extra.length) { + s.gzindex = 0; + s.status = NAME_STATE; + } } - data = read(f, "binary"); - assert(typeof data === "object"); - return data; - }; - if (typeof scriptArgs != "undefined") { - scriptArgs; - } - if (typeof quit === "function") { - quit_ = function(status) { - quit(status); - }; - } - if (typeof print !== "undefined") { - if (typeof console === "undefined") - console = {}; - console.log = print; - console.warn = console.error = typeof printErr !== "undefined" ? printErr : print; - } - } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { - if (ENVIRONMENT_IS_WORKER) { - scriptDirectory = self.location.href; - } else if (typeof document !== "undefined" && document.currentScript) { - scriptDirectory = document.currentScript.src; - } - if (_scriptDir) { - scriptDirectory = _scriptDir; - } - if (scriptDirectory.indexOf("blob:") !== 0) { - scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf("/") + 1); - } else { - scriptDirectory = ""; - } - if (ENVIRONMENT_IS_NODE) { - read_ = function shell_read(filename, binary) { - if (!nodeFS) - nodeFS = __require("fs"); - if (!nodePath) - nodePath = __require("path"); - filename = nodePath["normalize"](filename); - return nodeFS["readFileSync"](filename, binary ? null : "utf8"); - }; - readBinary = function readBinary2(filename) { - var ret = read_(filename, true); - if (!ret.buffer) { - ret = new Uint8Array(ret); - } - assert(ret.buffer); - return ret; - }; - } else { - read_ = function shell_read(url) { - var xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); - xhr.send(null); - return xhr.responseText; - }; - if (ENVIRONMENT_IS_WORKER) { - readBinary = function readBinary2(url) { - var xhr = new XMLHttpRequest(); - xhr.open("GET", url, false); - xhr.responseType = "arraybuffer"; - xhr.send(null); - return new Uint8Array(xhr.response); - }; + else { + s.status = NAME_STATE; } - } - } else ; - if (ENVIRONMENT_IS_NODE) { - if (typeof performance === "undefined") { - global.performance = __require("perf_hooks").performance; - } - } - var out = Module["print"] || console.log.bind(console); - var err = Module["printErr"] || console.warn.bind(console); - for (key in moduleOverrides) { - if (moduleOverrides.hasOwnProperty(key)) { - Module[key] = moduleOverrides[key]; - } - } - moduleOverrides = null; - if (Module["arguments"]) - ; - if (Module["thisProgram"]) - thisProgram = Module["thisProgram"]; - if (Module["quit"]) - quit_ = Module["quit"]; - var STACK_ALIGN = 16; - function alignMemory(size, factor) { - if (!factor) - factor = STACK_ALIGN; - return Math.ceil(size / factor) * factor; } - function warnOnce(text) { - if (!warnOnce.shown) - warnOnce.shown = {}; - if (!warnOnce.shown[text]) { - warnOnce.shown[text] = 1; - err(text); - } - } - var wasmBinary; - if (Module["wasmBinary"]) - wasmBinary = Module["wasmBinary"]; - var noExitRuntime; - if (Module["noExitRuntime"]) - noExitRuntime = Module["noExitRuntime"]; - if (typeof WebAssembly !== "object") { - abort("no native wasm support detected"); - } - var wasmMemory; - var wasmModule; - var threadInfoStruct = 0; - var ABORT = false; - function assert(condition, text) { - if (!condition) { - abort("Assertion failed: " + text); - } + if (s.status === NAME_STATE) { + if (s.gzhead.name/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.name.length) { + val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.gzindex = 0; + s.status = COMMENT_STATE; + } + } + else { + s.status = COMMENT_STATE; + } } - function UTF8ArrayToString(heap, idx, maxBytesToRead) { - idx >>>= 0; - var endIdx = idx + maxBytesToRead; - var str = ""; - while (!(idx >= endIdx)) { - var u0 = heap[idx++ >>> 0]; - if (!u0) - return str; - if (!(u0 & 128)) { - str += String.fromCharCode(u0); - continue; + if (s.status === COMMENT_STATE) { + if (s.gzhead.comment/* != Z_NULL*/) { + beg = s.pending; /* start of bytes to update crc */ + //int val; + + do { + if (s.pending === s.pending_buf_size) { + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + flush_pending(strm); + beg = s.pending; + if (s.pending === s.pending_buf_size) { + val = 1; + break; + } + } + // JS specific: little magic to add zero terminator to end of string + if (s.gzindex < s.gzhead.comment.length) { + val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff; + } else { + val = 0; + } + put_byte(s, val); + } while (val !== 0); + + if (s.gzhead.hcrc && s.pending > beg) { + strm.adler = crc32_1(strm.adler, s.pending_buf, s.pending - beg, beg); + } + if (val === 0) { + s.status = HCRC_STATE; + } } - var u1 = heap[idx++ >>> 0] & 63; - if ((u0 & 224) == 192) { - str += String.fromCharCode((u0 & 31) << 6 | u1); - continue; + else { + s.status = HCRC_STATE; } - var u2 = heap[idx++ >>> 0] & 63; - if ((u0 & 240) == 224) { - u0 = (u0 & 15) << 12 | u1 << 6 | u2; - } else { - u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heap[idx++ >>> 0] & 63; + } + if (s.status === HCRC_STATE) { + if (s.gzhead.hcrc) { + if (s.pending + 2 > s.pending_buf_size) { + flush_pending(strm); + } + if (s.pending + 2 <= s.pending_buf_size) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + strm.adler = 0; //crc32(0L, Z_NULL, 0); + s.status = BUSY_STATE; + } } - if (u0 < 65536) { - str += String.fromCharCode(u0); - } else { - var ch = u0 - 65536; - str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); + else { + s.status = BUSY_STATE; } - } - return str; } - function UTF8ToString(ptr, maxBytesToRead) { - ptr >>>= 0; - return ptr ? UTF8ArrayToString(GROWABLE_HEAP_U8(), ptr, maxBytesToRead) : ""; + //#endif + + /* Flush as much pending output as possible */ + if (s.pending !== 0) { + flush_pending(strm); + if (strm.avail_out === 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s.last_flush = -1; + return Z_OK$3; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) && + flush !== Z_FINISH$3) { + return err(strm, Z_BUF_ERROR$1); } - function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { - outIdx >>>= 0; - if (!(maxBytesToWrite > 0)) - return 0; - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; - for (var i = 0; i < str.length; ++i) { - var u = str.charCodeAt(i); - if (u >= 55296 && u <= 57343) { - var u1 = str.charCodeAt(++i); - u = 65536 + ((u & 1023) << 10) | u1 & 1023; + + /* User must not provide more input after the first FINISH: */ + if (s.status === FINISH_STATE && strm.avail_in !== 0) { + return err(strm, Z_BUF_ERROR$1); + } + + /* Start a new block or continue the current one. + */ + if (strm.avail_in !== 0 || s.lookahead !== 0 || + (flush !== Z_NO_FLUSH$2 && s.status !== FINISH_STATE)) { + let bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) : + (s.strategy === Z_RLE ? deflate_rle(s, flush) : + configuration_table[s.level].func(s, flush)); + + if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) { + s.status = FINISH_STATE; } - if (u <= 127) { - if (outIdx >= endIdx) - break; - heap[outIdx++ >>> 0] = u; - } else if (u <= 2047) { - if (outIdx + 1 >= endIdx) - break; - heap[outIdx++ >>> 0] = 192 | u >> 6; - heap[outIdx++ >>> 0] = 128 | u & 63; - } else if (u <= 65535) { - if (outIdx + 2 >= endIdx) - break; - heap[outIdx++ >>> 0] = 224 | u >> 12; - heap[outIdx++ >>> 0] = 128 | u >> 6 & 63; - heap[outIdx++ >>> 0] = 128 | u & 63; - } else { - if (outIdx + 3 >= endIdx) - break; - heap[outIdx++ >>> 0] = 240 | u >> 18; - heap[outIdx++ >>> 0] = 128 | u >> 12 & 63; - heap[outIdx++ >>> 0] = 128 | u >> 6 & 63; - heap[outIdx++ >>> 0] = 128 | u & 63; + if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) { + if (strm.avail_out === 0) { + s.last_flush = -1; + /* avoid BUF_ERROR next call, see above */ + } + return Z_OK$3; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate === BS_BLOCK_DONE) { + if (flush === Z_PARTIAL_FLUSH) { + _tr_align(s); + } + else if (flush !== Z_BLOCK$1) { /* FULL_FLUSH or SYNC_FLUSH */ + + _tr_stored_block(s, 0, 0, false); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush === Z_FULL_FLUSH$1) { + /*** CLEAR_HASH(s); ***/ /* forget history */ + zero(s.head); // Fill with NIL (= 0); + + if (s.lookahead === 0) { + s.strstart = 0; + s.block_start = 0; + s.insert = 0; + } + } + } + flush_pending(strm); + if (strm.avail_out === 0) { + s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK$3; + } } - } - heap[outIdx >>> 0] = 0; - return outIdx - startIdx; } - function stringToUTF8(str, outPtr, maxBytesToWrite) { - return stringToUTF8Array(str, GROWABLE_HEAP_U8(), outPtr, maxBytesToWrite); + //Assert(strm->avail_out > 0, "bug2"); + //if (strm.avail_out <= 0) { throw new Error("bug2");} + + if (flush !== Z_FINISH$3) { return Z_OK$3; } + if (s.wrap <= 0) { return Z_STREAM_END$3; } + + /* Write the trailer */ + if (s.wrap === 2) { + put_byte(s, strm.adler & 0xff); + put_byte(s, (strm.adler >> 8) & 0xff); + put_byte(s, (strm.adler >> 16) & 0xff); + put_byte(s, (strm.adler >> 24) & 0xff); + put_byte(s, strm.total_in & 0xff); + put_byte(s, (strm.total_in >> 8) & 0xff); + put_byte(s, (strm.total_in >> 16) & 0xff); + put_byte(s, (strm.total_in >> 24) & 0xff); } - function lengthBytesUTF8(str) { - var len = 0; - for (var i = 0; i < str.length; ++i) { - var u = str.charCodeAt(i); - if (u >= 55296 && u <= 57343) - u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023; - if (u <= 127) - ++len; - else if (u <= 2047) - len += 2; - else if (u <= 65535) - len += 3; - else - len += 4; - } - return len; + else + { + putShortMSB(s, strm.adler >>> 16); + putShortMSB(s, strm.adler & 0xffff); } - function UTF16ToString(ptr, maxBytesToRead) { - var str = ""; - for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { - var codeUnit = GROWABLE_HEAP_I16()[ptr + i * 2 >> 1]; - if (codeUnit == 0) - break; - str += String.fromCharCode(codeUnit); - } - return str; + + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s.wrap > 0) { s.wrap = -s.wrap; } + /* write the trailer only once! */ + return s.pending !== 0 ? Z_OK$3 : Z_STREAM_END$3; + }; + + + const deflateEnd = (strm) => { + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR$2; } - function stringToUTF16(str, outPtr, maxBytesToWrite) { - if (maxBytesToWrite === void 0) { - maxBytesToWrite = 2147483647; - } - if (maxBytesToWrite < 2) - return 0; - maxBytesToWrite -= 2; - var startPtr = outPtr; - var numCharsToWrite = maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length; - for (var i = 0; i < numCharsToWrite; ++i) { - var codeUnit = str.charCodeAt(i); - GROWABLE_HEAP_I16()[outPtr >> 1] = codeUnit; - outPtr += 2; - } - GROWABLE_HEAP_I16()[outPtr >> 1] = 0; - return outPtr - startPtr; + + const status = strm.state.status; + if (status !== INIT_STATE && + status !== EXTRA_STATE && + status !== NAME_STATE && + status !== COMMENT_STATE && + status !== HCRC_STATE && + status !== BUSY_STATE && + status !== FINISH_STATE + ) { + return err(strm, Z_STREAM_ERROR$2); } - function lengthBytesUTF16(str) { - return str.length * 2; + + strm.state = null; + + return status === BUSY_STATE ? err(strm, Z_DATA_ERROR$2) : Z_OK$3; + }; + + + /* ========================================================================= + * Initializes the compression dictionary from the given byte + * sequence without producing any compressed output. + */ + const deflateSetDictionary = (strm, dictionary) => { + + let dictLength = dictionary.length; + + if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) { + return Z_STREAM_ERROR$2; } - function UTF32ToString(ptr, maxBytesToRead) { - var i = 0; - var str = ""; - while (!(i >= maxBytesToRead / 4)) { - var utf32 = GROWABLE_HEAP_I32()[ptr + i * 4 >> 2]; - if (utf32 == 0) - break; - ++i; - if (utf32 >= 65536) { - var ch = utf32 - 65536; - str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); - } else { - str += String.fromCharCode(utf32); - } - } - return str; + + const s = strm.state; + const wrap = s.wrap; + + if (wrap === 2 || (wrap === 1 && s.status !== INIT_STATE) || s.lookahead) { + return Z_STREAM_ERROR$2; } - function stringToUTF32(str, outPtr, maxBytesToWrite) { - outPtr >>>= 0; - if (maxBytesToWrite === void 0) { - maxBytesToWrite = 2147483647; - } - if (maxBytesToWrite < 4) - return 0; - var startPtr = outPtr; - var endPtr = startPtr + maxBytesToWrite - 4; - for (var i = 0; i < str.length; ++i) { - var codeUnit = str.charCodeAt(i); - if (codeUnit >= 55296 && codeUnit <= 57343) { - var trailSurrogate = str.charCodeAt(++i); - codeUnit = 65536 + ((codeUnit & 1023) << 10) | trailSurrogate & 1023; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap === 1) { + /* adler32(strm->adler, dictionary, dictLength); */ + strm.adler = adler32_1(strm.adler, dictionary, dictLength, 0); + } + + s.wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s.w_size) { + if (wrap === 0) { /* already empty otherwise */ + /*** CLEAR_HASH(s); ***/ + zero(s.head); // Fill with NIL (= 0); + s.strstart = 0; + s.block_start = 0; + s.insert = 0; } - GROWABLE_HEAP_I32()[outPtr >> 2] = codeUnit; - outPtr += 4; - if (outPtr + 4 > endPtr) - break; - } - GROWABLE_HEAP_I32()[outPtr >> 2] = 0; - return outPtr - startPtr; + /* use the tail */ + // dictionary = dictionary.slice(dictLength - s.w_size); + let tmpDict = new Uint8Array(s.w_size); + tmpDict.set(dictionary.subarray(dictLength - s.w_size, dictLength), 0); + dictionary = tmpDict; + dictLength = s.w_size; } - function lengthBytesUTF32(str) { - var len = 0; - for (var i = 0; i < str.length; ++i) { - var codeUnit = str.charCodeAt(i); - if (codeUnit >= 55296 && codeUnit <= 57343) - ++i; - len += 4; - } - return len; + /* insert dictionary into window and hash */ + const avail = strm.avail_in; + const next = strm.next_in; + const input = strm.input; + strm.avail_in = dictLength; + strm.next_in = 0; + strm.input = dictionary; + fill_window(s); + while (s.lookahead >= MIN_MATCH) { + let str = s.strstart; + let n = s.lookahead - (MIN_MATCH - 1); + do { + /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */ + s.ins_h = HASH(s, s.ins_h, s.window[str + MIN_MATCH - 1]); + + s.prev[str & s.w_mask] = s.head[s.ins_h]; + + s.head[s.ins_h] = str; + str++; + } while (--n); + s.strstart = str; + s.lookahead = MIN_MATCH - 1; + fill_window(s); } - function writeArrayToMemory(array, buffer2) { - GROWABLE_HEAP_I8().set(array, buffer2); + s.strstart += s.lookahead; + s.block_start = s.strstart; + s.insert = s.lookahead; + s.lookahead = 0; + s.match_length = s.prev_length = MIN_MATCH - 1; + s.match_available = 0; + strm.next_in = next; + strm.input = input; + strm.avail_in = avail; + s.wrap = wrap; + return Z_OK$3; + }; + + + var deflateInit_1 = deflateInit; + var deflateInit2_1 = deflateInit2; + var deflateReset_1 = deflateReset; + var deflateResetKeep_1 = deflateResetKeep; + var deflateSetHeader_1 = deflateSetHeader; + var deflate_2$1 = deflate$2; + var deflateEnd_1 = deflateEnd; + var deflateSetDictionary_1 = deflateSetDictionary; + var deflateInfo = 'pako deflate (from Nodeca project)'; + + /* Not implemented + module.exports.deflateBound = deflateBound; + module.exports.deflateCopy = deflateCopy; + module.exports.deflateParams = deflateParams; + module.exports.deflatePending = deflatePending; + module.exports.deflatePrime = deflatePrime; + module.exports.deflateTune = deflateTune; + */ + + var deflate_1$2 = { + deflateInit: deflateInit_1, + deflateInit2: deflateInit2_1, + deflateReset: deflateReset_1, + deflateResetKeep: deflateResetKeep_1, + deflateSetHeader: deflateSetHeader_1, + deflate: deflate_2$1, + deflateEnd: deflateEnd_1, + deflateSetDictionary: deflateSetDictionary_1, + deflateInfo: deflateInfo + }; + + const _has = (obj, key) => { + return Object.prototype.hasOwnProperty.call(obj, key); + }; + + var assign = function (obj /*from1, from2, from3, ...*/) { + const sources = Array.prototype.slice.call(arguments, 1); + while (sources.length) { + const source = sources.shift(); + if (!source) { continue; } + + if (typeof source !== 'object') { + throw new TypeError(source + 'must be non-object'); + } + + for (const p in source) { + if (_has(source, p)) { + obj[p] = source[p]; + } + } } - function writeAsciiToMemory(str, buffer2, dontAddNull) { - for (var i = 0; i < str.length; ++i) { - GROWABLE_HEAP_I8()[buffer2++ >> 0] = str.charCodeAt(i); - } - if (!dontAddNull) - GROWABLE_HEAP_I8()[buffer2 >> 0] = 0; + + return obj; + }; + + + // Join array of chunks to single array. + var flattenChunks = (chunks) => { + // calculate data length + let len = 0; + + for (let i = 0, l = chunks.length; i < l; i++) { + len += chunks[i].length; } - function alignUp(x, multiple) { - if (x % multiple > 0) { - x += multiple - x % multiple; - } - return x; + + // join chunks + const result = new Uint8Array(len); + + for (let i = 0, pos = 0, l = chunks.length; i < l; i++) { + let chunk = chunks[i]; + result.set(chunk, pos); + pos += chunk.length; } - var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; - function updateGlobalBufferAndViews(buf) { - buffer = buf; - Module["HEAP8"] = HEAP8 = new Int8Array(buf); - Module["HEAP16"] = HEAP16 = new Int16Array(buf); - Module["HEAP32"] = HEAP32 = new Int32Array(buf); - Module["HEAPU8"] = HEAPU8 = new Uint8Array(buf); - Module["HEAPU16"] = HEAPU16 = new Uint16Array(buf); - Module["HEAPU32"] = HEAPU32 = new Uint32Array(buf); - Module["HEAPF32"] = HEAPF32 = new Float32Array(buf); - Module["HEAPF64"] = HEAPF64 = new Float64Array(buf); + + return result; + }; + + var common = { + assign: assign, + flattenChunks: flattenChunks + }; + + // String encode/decode helpers + + + // Quick check if we can use fast array to bin string conversion + // + // - apply(Array) can fail on Android 2.2 + // - apply(Uint8Array) can fail on iOS 5.1 Safari + // + let STR_APPLY_UIA_OK = true; + + try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch (__) { STR_APPLY_UIA_OK = false; } + + + // Table with utf8 lengths (calculated by first byte of sequence) + // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS, + // because max possible codepoint is 0x10ffff + const _utf8len = new Uint8Array(256); + for (let q = 0; q < 256; q++) { + _utf8len[q] = (q >= 252 ? 6 : q >= 248 ? 5 : q >= 240 ? 4 : q >= 224 ? 3 : q >= 192 ? 2 : 1); + } + _utf8len[254] = _utf8len[254] = 1; // Invalid sequence start + + + // convert string to array (typed, when possible) + var string2buf = (str) => { + if (typeof TextEncoder === 'function' && TextEncoder.prototype.encode) { + return new TextEncoder().encode(str); } - var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216; - if (ENVIRONMENT_IS_PTHREAD) { - wasmMemory = Module["wasmMemory"]; - buffer = Module["buffer"]; - } else { - if (Module["wasmMemory"]) { - wasmMemory = Module["wasmMemory"]; - } else { - wasmMemory = new WebAssembly.Memory({ "initial": INITIAL_MEMORY / 65536, "maximum": 4294967296 / 65536, "shared": true }); - if (!(wasmMemory.buffer instanceof SharedArrayBuffer)) { - err("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"); - if (ENVIRONMENT_IS_NODE) { - console.log("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and also use a recent version)"); - } - throw Error("bad memory"); + + let buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0; + + // count binary size + for (m_pos = 0; m_pos < str_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { + c2 = str.charCodeAt(m_pos + 1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } } - } + buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4; } - if (wasmMemory) { - buffer = wasmMemory.buffer; + + // allocate buffer + buf = new Uint8Array(buf_len); + + // convert + for (i = 0, m_pos = 0; i < buf_len; m_pos++) { + c = str.charCodeAt(m_pos); + if ((c & 0xfc00) === 0xd800 && (m_pos + 1 < str_len)) { + c2 = str.charCodeAt(m_pos + 1); + if ((c2 & 0xfc00) === 0xdc00) { + c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00); + m_pos++; + } + } + if (c < 0x80) { + /* one byte */ + buf[i++] = c; + } else if (c < 0x800) { + /* two bytes */ + buf[i++] = 0xC0 | (c >>> 6); + buf[i++] = 0x80 | (c & 0x3f); + } else if (c < 0x10000) { + /* three bytes */ + buf[i++] = 0xE0 | (c >>> 12); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } else { + /* four bytes */ + buf[i++] = 0xf0 | (c >>> 18); + buf[i++] = 0x80 | (c >>> 12 & 0x3f); + buf[i++] = 0x80 | (c >>> 6 & 0x3f); + buf[i++] = 0x80 | (c & 0x3f); + } } - INITIAL_MEMORY = buffer.byteLength; - updateGlobalBufferAndViews(buffer); - var wasmTable; - var __ATPRERUN__ = []; - var __ATINIT__ = []; - var __ATMAIN__ = []; - var __ATPOSTRUN__ = []; - function preRun() { - if (ENVIRONMENT_IS_PTHREAD) - return; - if (Module["preRun"]) { - if (typeof Module["preRun"] == "function") - Module["preRun"] = [Module["preRun"]]; - while (Module["preRun"].length) { - addOnPreRun(Module["preRun"].shift()); + + return buf; + }; + + // Helper + const buf2binstring = (buf, len) => { + // On Chrome, the arguments in a function call that are allowed is `65534`. + // If the length of the buffer is smaller than that, we can use this optimization, + // otherwise we will take a slower path. + if (len < 65534) { + if (buf.subarray && STR_APPLY_UIA_OK) { + return String.fromCharCode.apply(null, buf.length === len ? buf : buf.subarray(0, len)); } - } - callRuntimeCallbacks(__ATPRERUN__); } - function initRuntime() { - if (!Module["noFSInit"] && !FS.init.initialized) - FS.init(); - callRuntimeCallbacks(__ATINIT__); + + let result = ''; + for (let i = 0; i < len; i++) { + result += String.fromCharCode(buf[i]); } - function preMain() { - if (ENVIRONMENT_IS_PTHREAD) - return; - FS.ignorePermissions = false; - callRuntimeCallbacks(__ATMAIN__); + return result; + }; + + + // convert array to string + var buf2string = (buf, max) => { + const len = max || buf.length; + + if (typeof TextDecoder === 'function' && TextDecoder.prototype.decode) { + return new TextDecoder().decode(buf.subarray(0, max)); } - function postRun() { - if (ENVIRONMENT_IS_PTHREAD) - return; - if (Module["postRun"]) { - if (typeof Module["postRun"] == "function") - Module["postRun"] = [Module["postRun"]]; - while (Module["postRun"].length) { - addOnPostRun(Module["postRun"].shift()); + + let i, out; + + // Reserve max possible length (2 words per char) + // NB: by unknown reasons, Array is significantly faster for + // String.fromCharCode.apply than Uint16Array. + const utf16buf = new Array(len * 2); + + for (out = 0, i = 0; i < len;) { + let c = buf[i++]; + // quick process ascii + if (c < 0x80) { utf16buf[out++] = c; continue; } + + let c_len = _utf8len[c]; + // skip 5 & 6 byte codes + if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len - 1; continue; } + + // apply mask on first byte + c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07; + // join the rest + while (c_len > 1 && i < len) { + c = (c << 6) | (buf[i++] & 0x3f); + c_len--; + } + + // terminated by end of string? + if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; } + + if (c < 0x10000) { + utf16buf[out++] = c; + } else { + c -= 0x10000; + utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff); + utf16buf[out++] = 0xdc00 | (c & 0x3ff); } - } - callRuntimeCallbacks(__ATPOSTRUN__); } - function addOnPreRun(cb) { - __ATPRERUN__.unshift(cb); + + return buf2binstring(utf16buf, out); + }; + + + // Calculate max possible position in utf8 buffer, + // that will not break sequence. If that's not possible + // - (very small limits) return max size as is. + // + // buf[] - utf8 bytes array + // max - length limit (mandatory); + var utf8border = (buf, max) => { + + max = max || buf.length; + if (max > buf.length) { max = buf.length; } + + // go back from last position, until start of sequence found + let pos = max - 1; + while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; } + + // Very small and broken sequence, + // return max, because we should return something anyway. + if (pos < 0) { return max; } + + // If we came to start of buffer - that means buffer is too small, + // return max too. + if (pos === 0) { return max; } + + return (pos + _utf8len[buf[pos]] > max) ? pos : max; + }; + + var strings = { + string2buf: string2buf, + buf2string: buf2string, + utf8border: utf8border + }; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + function ZStream() { + /* next input byte */ + this.input = null; // JS specific, because we have no pointers + this.next_in = 0; + /* number of bytes available at input */ + this.avail_in = 0; + /* total number of input bytes read so far */ + this.total_in = 0; + /* next output byte should be put there */ + this.output = null; // JS specific, because we have no pointers + this.next_out = 0; + /* remaining free space at output */ + this.avail_out = 0; + /* total number of bytes output so far */ + this.total_out = 0; + /* last error message, NULL if no error */ + this.msg = ''/*Z_NULL*/; + /* not visible by applications */ + this.state = null; + /* best guess about the data type: binary or text */ + this.data_type = 2/*Z_UNKNOWN*/; + /* adler32 value of the uncompressed data */ + this.adler = 0; + } + + var zstream = ZStream; + + const toString$1 = Object.prototype.toString; + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + const { + Z_NO_FLUSH: Z_NO_FLUSH$1, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH: Z_FINISH$2, + Z_OK: Z_OK$2, Z_STREAM_END: Z_STREAM_END$2, + Z_DEFAULT_COMPRESSION, + Z_DEFAULT_STRATEGY, + Z_DEFLATED: Z_DEFLATED$1 + } = constants$2; + + /* ===========================================================================*/ + + + /** + * class Deflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[deflate]], + * [[deflateRaw]] and [[gzip]]. + **/ + + /* internal + * Deflate.chunks -> Array + * + * Chunks of output data, if [[Deflate#onData]] not overridden. + **/ + + /** + * Deflate.result -> Uint8Array + * + * Compressed result, generated by default [[Deflate#onData]] + * and [[Deflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Deflate#push]] with `Z_FINISH` / `true` param). + **/ + + /** + * Deflate.err -> Number + * + * Error code after deflate finished. 0 (Z_OK) on success. + * You will not need it in real life, because deflate errors + * are possible only on wrong options or bad `onData` / `onEnd` + * custom handlers. + **/ + + /** + * Deflate.msg -> String + * + * Error message, if [[Deflate.err]] != 0 + **/ + + + /** + * new Deflate(options) + * - options (Object): zlib deflate options. + * + * Creates new deflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `level` + * - `windowBits` + * - `memLevel` + * - `strategy` + * - `dictionary` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw deflate + * - `gzip` (Boolean) - create gzip wrapper + * - `header` (Object) - custom header for gzip + * - `text` (Boolean) - true if compressed data believed to be text + * - `time` (Number) - modification time, unix timestamp + * - `os` (Number) - operation system code + * - `extra` (Array) - array of bytes with extra data (max 65536) + * - `name` (String) - file name (binary string) + * - `comment` (String) - comment (binary string) + * - `hcrc` (Boolean) - true if header crc should be added + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * , chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9]) + * , chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * const deflate = new pako.Deflate({ level: 3}); + * + * deflate.push(chunk1, false); + * deflate.push(chunk2, true); // true -> last chunk + * + * if (deflate.err) { throw new Error(deflate.err); } + * + * console.log(deflate.result); + * ``` + **/ + function Deflate$1(options) { + this.options = common.assign({ + level: Z_DEFAULT_COMPRESSION, + method: Z_DEFLATED$1, + chunkSize: 16384, + windowBits: 15, + memLevel: 8, + strategy: Z_DEFAULT_STRATEGY + }, options || {}); + + let opt = this.options; + + if (opt.raw && (opt.windowBits > 0)) { + opt.windowBits = -opt.windowBits; } - function addOnPostRun(cb) { - __ATPOSTRUN__.unshift(cb); + + else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) { + opt.windowBits += 16; } - var runDependencies = 0; - var dependenciesFulfilled = null; - function addRunDependency(id) { - assert(!ENVIRONMENT_IS_PTHREAD, "addRunDependency cannot be used in a pthread worker"); - runDependencies++; - if (Module["monitorRunDependencies"]) { - Module["monitorRunDependencies"](runDependencies); - } + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + let status = deflate_1$2.deflateInit2( + this.strm, + opt.level, + opt.method, + opt.windowBits, + opt.memLevel, + opt.strategy + ); + + if (status !== Z_OK$2) { + throw new Error(messages[status]); } - function removeRunDependency(id) { - runDependencies--; - if (Module["monitorRunDependencies"]) { - Module["monitorRunDependencies"](runDependencies); - } - if (runDependencies == 0) { - if (dependenciesFulfilled) { - var callback = dependenciesFulfilled; - dependenciesFulfilled = null; - callback(); + + if (opt.header) { + deflate_1$2.deflateSetHeader(this.strm, opt.header); + } + + if (opt.dictionary) { + let dict; + // Convert data if needed + if (typeof opt.dictionary === 'string') { + // If we need to compress text, change encoding to utf8. + dict = strings.string2buf(opt.dictionary); + } else if (toString$1.call(opt.dictionary) === '[object ArrayBuffer]') { + dict = new Uint8Array(opt.dictionary); + } else { + dict = opt.dictionary; } - } + + status = deflate_1$2.deflateSetDictionary(this.strm, dict); + + if (status !== Z_OK$2) { + throw new Error(messages[status]); + } + + this._dict_set = true; } - Module["preloadedImages"] = {}; - Module["preloadedAudios"] = {}; - function abort(what) { - if (Module["onAbort"]) { - Module["onAbort"](what); - } - if (ENVIRONMENT_IS_PTHREAD) - console.error("Pthread aborting at " + new Error().stack); - what += ""; - err(what); - ABORT = true; - what = "abort(" + what + "). Build with -s ASSERTIONS=1 for more info."; - var e = new WebAssembly.RuntimeError(what); - readyPromiseReject(e); - throw e; + } + + /** + * Deflate#push(data[, flush_mode]) -> Boolean + * - data (Uint8Array|ArrayBuffer|String): input data. Strings will be + * converted to utf8 byte sequence. + * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes. + * See constants. Skipped or `false` means Z_NO_FLUSH, `true` means Z_FINISH. + * + * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with + * new compressed chunks. Returns `true` on success. The last data block must + * have `flush_mode` Z_FINISH (or `true`). That will flush internal pending + * buffers and call [[Deflate#onEnd]]. + * + * On fail call [[Deflate#onEnd]] with error code and return false. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ + Deflate$1.prototype.push = function (data, flush_mode) { + const strm = this.strm; + const chunkSize = this.options.chunkSize; + let status, _flush_mode; + + if (this.ended) { return false; } + + if (flush_mode === ~~flush_mode) _flush_mode = flush_mode; + else _flush_mode = flush_mode === true ? Z_FINISH$2 : Z_NO_FLUSH$1; + + // Convert data if needed + if (typeof data === 'string') { + // If we need to compress text, change encoding to utf8. + strm.input = strings.string2buf(data); + } else if (toString$1.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; } - function hasPrefix(str, prefix) { - return String.prototype.startsWith ? str.startsWith(prefix) : str.indexOf(prefix) === 0; + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + for (;;) { + if (strm.avail_out === 0) { + strm.output = new Uint8Array(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; + } + + // Make sure avail_out > 6 to avoid repeating markers + if ((_flush_mode === Z_SYNC_FLUSH || _flush_mode === Z_FULL_FLUSH) && strm.avail_out <= 6) { + this.onData(strm.output.subarray(0, strm.next_out)); + strm.avail_out = 0; + continue; + } + + status = deflate_1$2.deflate(strm, _flush_mode); + + // Ended => flush and finish + if (status === Z_STREAM_END$2) { + if (strm.next_out > 0) { + this.onData(strm.output.subarray(0, strm.next_out)); + } + status = deflate_1$2.deflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return status === Z_OK$2; + } + + // Flush if out buffer full + if (strm.avail_out === 0) { + this.onData(strm.output); + continue; + } + + // Flush if requested and has data + if (_flush_mode > 0 && strm.next_out > 0) { + this.onData(strm.output.subarray(0, strm.next_out)); + strm.avail_out = 0; + continue; + } + + if (strm.avail_in === 0) break; } - var dataURIPrefix = "data:application/octet-stream;base64,"; - function isDataURI(filename) { - return hasPrefix(filename, dataURIPrefix); + + return true; + }; + + + /** + * Deflate#onData(chunk) -> Void + * - chunk (Uint8Array): output data. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ + Deflate$1.prototype.onData = function (chunk) { + this.chunks.push(chunk); + }; + + + /** + * Deflate#onEnd(status) -> Void + * - status (Number): deflate status. 0 (Z_OK) on success, + * other if not. + * + * Called once after you tell deflate that the input stream is + * complete (Z_FINISH). By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ + Deflate$1.prototype.onEnd = function (status) { + // On success - join + if (status === Z_OK$2) { + this.result = common.flattenChunks(this.chunks); } - var fileURIPrefix = "file://"; - function isFileURI(filename) { - return hasPrefix(filename, fileURIPrefix); + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; + }; + + + /** + * deflate(data[, options]) -> Uint8Array + * - data (Uint8Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * Compress `data` with deflate algorithm and `options`. + * + * Supported options are: + * + * - level + * - windowBits + * - memLevel + * - strategy + * - dictionary + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * const data = new Uint8Array([1,2,3,4,5,6,7,8,9]); + * + * console.log(pako.deflate(data)); + * ``` + **/ + function deflate$1(input, options) { + const deflator = new Deflate$1(options); + + deflator.push(input, true); + + // That will never happens, if you don't cheat with options :) + if (deflator.err) { throw deflator.msg || messages[deflator.err]; } + + return deflator.result; + } + + + /** + * deflateRaw(data[, options]) -> Uint8Array + * - data (Uint8Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ + function deflateRaw$1(input, options) { + options = options || {}; + options.raw = true; + return deflate$1(input, options); + } + + + /** + * gzip(data[, options]) -> Uint8Array + * - data (Uint8Array|String): input data to compress. + * - options (Object): zlib deflate options. + * + * The same as [[deflate]], but create gzip wrapper instead of + * deflate one. + **/ + function gzip$1(input, options) { + options = options || {}; + options.gzip = true; + return deflate$1(input, options); + } + + + var Deflate_1$1 = Deflate$1; + var deflate_2 = deflate$1; + var deflateRaw_1$1 = deflateRaw$1; + var gzip_1$1 = gzip$1; + var constants$1 = constants$2; + + var deflate_1$1 = { + Deflate: Deflate_1$1, + deflate: deflate_2, + deflateRaw: deflateRaw_1$1, + gzip: gzip_1$1, + constants: constants$1 + }; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + // See state defs from inflate.js + const BAD$1 = 30; /* got a data error -- remain here until reset */ + const TYPE$1 = 12; /* i: waiting for type bits, including last-flag bit */ + + /* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state.mode === LEN + strm.avail_in >= 6 + strm.avail_out >= 258 + start >= strm.avail_out + state.bits < 8 + + On return, state.mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm.avail_out >= 258 for each loop to avoid checking for + output space. + */ + var inffast = function inflate_fast(strm, start) { + let _in; /* local strm.input */ + let last; /* have enough input while in < last */ + let _out; /* local strm.output */ + let beg; /* inflate()'s initial strm.output */ + let end; /* while out < end, enough space available */ + //#ifdef INFLATE_STRICT + let dmax; /* maximum distance from zlib header */ + //#endif + let wsize; /* window size or zero if not using window */ + let whave; /* valid bytes in the window */ + let wnext; /* window write index */ + // Use `s_window` instead `window`, avoid conflict with instrumentation tools + let s_window; /* allocated sliding window, if wsize != 0 */ + let hold; /* local strm.hold */ + let bits; /* local strm.bits */ + let lcode; /* local strm.lencode */ + let dcode; /* local strm.distcode */ + let lmask; /* mask for first level of length codes */ + let dmask; /* mask for first level of distance codes */ + let here; /* retrieved table entry */ + let op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + let len; /* match length, unused bytes */ + let dist; /* match distance */ + let from; /* where to copy match from */ + let from_source; + + + let input, output; // JS specific, because we have no pointers + + /* copy state to local variables */ + const state = strm.state; + //here = state.here; + _in = strm.next_in; + input = strm.input; + last = _in + (strm.avail_in - 5); + _out = strm.next_out; + output = strm.output; + beg = _out - (start - strm.avail_out); + end = _out + (strm.avail_out - 257); + //#ifdef INFLATE_STRICT + dmax = state.dmax; + //#endif + wsize = state.wsize; + whave = state.whave; + wnext = state.wnext; + s_window = state.window; + hold = state.hold; + bits = state.bits; + lcode = state.lencode; + dcode = state.distcode; + lmask = (1 << state.lenbits) - 1; + dmask = (1 << state.distbits) - 1; + + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + top: + do { + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + + here = lcode[hold & lmask]; + + dolen: + for (;;) { // Goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + if (op === 0) { /* literal */ + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + output[_out++] = here & 0xffff/*here.val*/; + } + else if (op & 16) { /* length base */ + len = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + len += hold & ((1 << op) - 1); + hold >>>= op; + bits -= op; + } + //Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += input[_in++] << bits; + bits += 8; + hold += input[_in++] << bits; + bits += 8; + } + here = dcode[hold & dmask]; + + dodist: + for (;;) { // goto emulation + op = here >>> 24/*here.bits*/; + hold >>>= op; + bits -= op; + op = (here >>> 16) & 0xff/*here.op*/; + + if (op & 16) { /* distance base */ + dist = here & 0xffff/*here.val*/; + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + if (bits < op) { + hold += input[_in++] << bits; + bits += 8; + } + } + dist += hold & ((1 << op) - 1); + //#ifdef INFLATE_STRICT + if (dist > dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD$1; + break top; + } + //#endif + hold >>>= op; + bits -= op; + //Tracevv((stderr, "inflate: distance %u\n", dist)); + op = _out - beg; /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD$1; + break top; + } + + // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + // if (len <= op - whave) { + // do { + // output[_out++] = 0; + // } while (--len); + // continue top; + // } + // len -= op - whave; + // do { + // output[_out++] = 0; + // } while (--op > whave); + // if (op === 0) { + // from = _out - dist; + // do { + // output[_out++] = output[from++]; + // } while (--len); + // continue top; + // } + //#endif + } + from = 0; // window index + from_source = s_window; + if (wnext === 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = 0; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + output[_out++] = s_window[from++]; + } while (--op); + from = _out - dist; /* rest from output */ + from_source = output; + } + } + while (len > 2) { + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + output[_out++] = from_source[from++]; + len -= 3; + } + if (len) { + output[_out++] = from_source[from++]; + if (len > 1) { + output[_out++] = from_source[from++]; + } + } + } + else { + from = _out - dist; /* copy direct from output */ + do { /* minimum length is three */ + output[_out++] = output[from++]; + output[_out++] = output[from++]; + output[_out++] = output[from++]; + len -= 3; + } while (len > 2); + if (len) { + output[_out++] = output[from++]; + if (len > 1) { + output[_out++] = output[from++]; + } + } + } + } + else if ((op & 64) === 0) { /* 2nd level distance code */ + here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dodist; + } + else { + strm.msg = 'invalid distance code'; + state.mode = BAD$1; + break top; + } + + break; // need to emulate goto via "continue" + } + } + else if ((op & 64) === 0) { /* 2nd level length code */ + here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))]; + continue dolen; + } + else if (op & 32) { /* end-of-block */ + //Tracevv((stderr, "inflate: end of block\n")); + state.mode = TYPE$1; + break top; + } + else { + strm.msg = 'invalid literal/length code'; + state.mode = BAD$1; + break top; + } + + break; // need to emulate goto via "continue" + } + } while (_in < last && _out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + _in -= len; + bits -= len << 3; + hold &= (1 << bits) - 1; + + /* update state and return */ + strm.next_in = _in; + strm.next_out = _out; + strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last)); + strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end)); + state.hold = hold; + state.bits = bits; + return; + }; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + const MAXBITS = 15; + const ENOUGH_LENS$1 = 852; + const ENOUGH_DISTS$1 = 592; + //const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + + const CODES$1 = 0; + const LENS$1 = 1; + const DISTS$1 = 2; + + const lbase = new Uint16Array([ /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 + ]); + + const lext = new Uint8Array([ /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78 + ]); + + const dbase = new Uint16Array([ /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0 + ]); + + const dext = new Uint8Array([ /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64 + ]); + + const inflate_table = (type, lens, lens_index, codes, table, table_index, work, opts) => + { + const bits = opts.bits; + //here = opts.here; /* table entry for duplication */ + + let len = 0; /* a code's length in bits */ + let sym = 0; /* index of code symbols */ + let min = 0, max = 0; /* minimum and maximum code lengths */ + let root = 0; /* number of index bits for root table */ + let curr = 0; /* number of index bits for current table */ + let drop = 0; /* code bits to drop for sub-table */ + let left = 0; /* number of prefix codes available */ + let used = 0; /* code entries in table used */ + let huff = 0; /* Huffman code */ + let incr; /* for incrementing code, index */ + let fill; /* index for replicating entries */ + let low; /* low bits for current root entry */ + let mask; /* mask for low root bits */ + let next; /* next available space in table */ + let base = null; /* base value table to use */ + let base_index = 0; + // let shoextra; /* extra bits table to use */ + let end; /* use base and extra for symbol > end */ + const count = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* number of codes of each length */ + const offs = new Uint16Array(MAXBITS + 1); //[MAXBITS+1]; /* offsets in table for each length */ + let extra = null; + let extra_index = 0; + + let here_bits, here_op, here_val; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) { + count[len] = 0; + } + for (sym = 0; sym < codes; sym++) { + count[lens[lens_index + sym]]++; + } + + /* bound code lengths, force root to be within code lengths */ + root = bits; + for (max = MAXBITS; max >= 1; max--) { + if (count[max] !== 0) { break; } + } + if (root > max) { + root = max; + } + if (max === 0) { /* no symbols to code at all */ + //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */ + //table.bits[opts.table_index] = 1; //here.bits = (var char)1; + //table.val[opts.table_index++] = 0; //here.val = (var short)0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + + //table.op[opts.table_index] = 64; + //table.bits[opts.table_index] = 1; + //table.val[opts.table_index++] = 0; + table[table_index++] = (1 << 24) | (64 << 16) | 0; + + opts.bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) { + if (count[min] !== 0) { break; } + } + if (root < min) { + root = min; + } + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) { + return -1; + } /* over-subscribed */ } - var wasmBinaryFile = "web-ifc-mt.wasm"; - if (!isDataURI(wasmBinaryFile)) { - wasmBinaryFile = locateFile(wasmBinaryFile); + if (left > 0 && (type === CODES$1 || max !== 1)) { + return -1; /* incomplete set */ } - function getBinary() { - try { - if (wasmBinary) { - return new Uint8Array(wasmBinary); - } - if (readBinary) { - return readBinary(wasmBinaryFile); - } else { - throw "both async and sync fetching of the wasm failed"; + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) { + offs[len + 1] = offs[len] + count[len]; + } + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) { + if (lens[lens_index + sym] !== 0) { + work[offs[lens[lens_index + sym]]++] = sym; } - } catch (err2) { - abort(err2); - } } - function getBinaryPromise() { - if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === "function" && !isFileURI(wasmBinaryFile)) { - return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { - if (!response["ok"]) { - throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; - } - return response["arrayBuffer"](); - }).catch(function() { - return getBinary(); - }); - } - return Promise.resolve().then(getBinary); + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + // poor man optimization - use if-else instead of switch, + // to avoid deopts in old v8 + if (type === CODES$1) { + base = extra = work; /* dummy value--not used */ + end = 19; + + } else if (type === LENS$1) { + base = lbase; + base_index -= 257; + extra = lext; + extra_index -= 257; + end = 256; + + } else { /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize opts for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = table_index; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = -1; /* trigger new sub-table when len > root */ + used = 1 << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type === LENS$1 && used > ENOUGH_LENS$1) || + (type === DISTS$1 && used > ENOUGH_DISTS$1)) { + return 1; } - function createWasm() { - var info = { "a": asmLibraryArg }; - function receiveInstance(instance, module2) { - var exports3 = instance.exports; - Module["asm"] = exports3; - wasmTable = Module["asm"]["pa"]; - wasmModule = module2; - if (!ENVIRONMENT_IS_PTHREAD) { - var numWorkersToLoad = PThread.unusedWorkers.length; - PThread.unusedWorkers.forEach(function(w) { - PThread.loadWasmModuleToWorker(w, function() { - if (!--numWorkersToLoad) - removeRunDependency(); - }); - }); - } - } - if (!ENVIRONMENT_IS_PTHREAD) { - addRunDependency(); - } - function receiveInstantiatedSource(output) { - receiveInstance(output["instance"], output["module"]); - } - function instantiateArrayBuffer(receiver) { - return getBinaryPromise().then(function(binary) { - return WebAssembly.instantiate(binary, info); - }).then(receiver, function(reason) { - err("failed to asynchronously prepare wasm: " + reason); - abort(reason); - }); - } - function instantiateAsync() { - if (!wasmBinary && typeof WebAssembly.instantiateStreaming === "function" && !isDataURI(wasmBinaryFile) && !isFileURI(wasmBinaryFile) && typeof fetch === "function") { - return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { - var result = WebAssembly.instantiateStreaming(response, info); - return result.then(receiveInstantiatedSource, function(reason) { - err("wasm streaming compile failed: " + reason); - err("falling back to ArrayBuffer instantiation"); - return instantiateArrayBuffer(receiveInstantiatedSource); - }); - }); - } else { - return instantiateArrayBuffer(receiveInstantiatedSource); + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here_bits = len - drop; + if (work[sym] < end) { + here_op = 0; + here_val = work[sym]; } - } - if (Module["instantiateWasm"]) { - try { - var exports2 = Module["instantiateWasm"](info, receiveInstance); - return exports2; - } catch (e) { - err("Module.instantiateWasm callback failed with error: " + e); - return false; + else if (work[sym] > end) { + here_op = extra[extra_index + work[sym]]; + here_val = base[base_index + work[sym]]; } - } - instantiateAsync().catch(readyPromiseReject); - return {}; - } - var tempDouble; - var tempI64; - var ASM_CONSTS = { 41793: function($0, $1) { - setTimeout(function() { - _do_emscripten_dispatch_to_thread($0, $1); - }, 0); - }, 41871: function() { - throw "Canceled!"; - } }; - function initPthreadsJS() { - PThread.initRuntime(); - } - function callRuntimeCallbacks(callbacks) { - while (callbacks.length > 0) { - var callback = callbacks.shift(); - if (typeof callback == "function") { - callback(Module); - continue; + else { + here_op = 32 + 64; /* end of block */ + here_val = 0; } - var func = callback.func; - if (typeof func === "number") { - if (callback.arg === void 0) { - wasmTable.get(func)(); - } else { - wasmTable.get(func)(callback.arg); - } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1 << (len - drop); + fill = 1 << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0; + } while (fill !== 0); + + /* backwards increment the len-bit code huff */ + incr = 1 << (len - 1); + while (huff & incr) { + incr >>= 1; + } + if (incr !== 0) { + huff &= incr - 1; + huff += incr; } else { - func(callback.arg === void 0 ? null : callback.arg); + huff = 0; + } + + /* go to next symbol, update count, len */ + sym++; + if (--count[len] === 0) { + if (len === max) { break; } + len = lens[lens_index + work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) !== low) { + /* if first time, transition to sub-tables */ + if (drop === 0) { + drop = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = 1 << curr; + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) { break; } + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1 << curr; + if ((type === LENS$1 && used > ENOUGH_LENS$1) || + (type === DISTS$1 && used > ENOUGH_DISTS$1)) { + return 1; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + /*table.op[low] = curr; + table.bits[low] = root; + table.val[low] = next - opts.table_index;*/ + table[low] = (root << 24) | (curr << 16) | (next - table_index) |0; } - } } - function dynCallLegacy(sig, ptr, args) { - if (args && args.length) { - return Module["dynCall_" + sig].apply(null, [ptr].concat(args)); - } - return Module["dynCall_" + sig].call(null, ptr); + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff !== 0) { + //table.op[next + huff] = 64; /* invalid code marker */ + //table.bits[next + huff] = len - drop; + //table.val[next + huff] = 0; + table[next + huff] = ((len - drop) << 24) | (64 << 16) |0; } - function dynCall(sig, ptr, args) { - if (sig.indexOf("j") != -1) { - return dynCallLegacy(sig, ptr, args); - } - return wasmTable.get(ptr).apply(null, args); + + /* set return parameters */ + //opts.table_index += used; + opts.bits = root; + return 0; + }; + + + var inftrees = inflate_table; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + + + + + + const CODES = 0; + const LENS = 1; + const DISTS = 2; + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + const { + Z_FINISH: Z_FINISH$1, Z_BLOCK, Z_TREES, + Z_OK: Z_OK$1, Z_STREAM_END: Z_STREAM_END$1, Z_NEED_DICT: Z_NEED_DICT$1, Z_STREAM_ERROR: Z_STREAM_ERROR$1, Z_DATA_ERROR: Z_DATA_ERROR$1, Z_MEM_ERROR: Z_MEM_ERROR$1, Z_BUF_ERROR, + Z_DEFLATED + } = constants$2; + + + /* STATES ====================================================================*/ + /* ===========================================================================*/ + + + const HEAD = 1; /* i: waiting for magic header */ + const FLAGS = 2; /* i: waiting for method and flags (gzip) */ + const TIME = 3; /* i: waiting for modification time (gzip) */ + const OS = 4; /* i: waiting for extra flags and operating system (gzip) */ + const EXLEN = 5; /* i: waiting for extra length (gzip) */ + const EXTRA = 6; /* i: waiting for extra bytes (gzip) */ + const NAME = 7; /* i: waiting for end of file name (gzip) */ + const COMMENT = 8; /* i: waiting for end of comment (gzip) */ + const HCRC = 9; /* i: waiting for header crc (gzip) */ + const DICTID = 10; /* i: waiting for dictionary check value */ + const DICT = 11; /* waiting for inflateSetDictionary() call */ + const TYPE = 12; /* i: waiting for type bits, including last-flag bit */ + const TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */ + const STORED = 14; /* i: waiting for stored size (length and complement) */ + const COPY_ = 15; /* i/o: same as COPY below, but only first time in */ + const COPY = 16; /* i/o: waiting for input or output to copy stored block */ + const TABLE = 17; /* i: waiting for dynamic block table lengths */ + const LENLENS = 18; /* i: waiting for code length code lengths */ + const CODELENS = 19; /* i: waiting for length/lit and distance code lengths */ + const LEN_ = 20; /* i: same as LEN below, but only first time in */ + const LEN = 21; /* i: waiting for length/lit/eob code */ + const LENEXT = 22; /* i: waiting for length extra bits */ + const DIST = 23; /* i: waiting for distance code */ + const DISTEXT = 24; /* i: waiting for distance extra bits */ + const MATCH = 25; /* o: waiting for output space to copy string */ + const LIT = 26; /* o: waiting for output space to write literal */ + const CHECK = 27; /* i: waiting for 32-bit check value */ + const LENGTH = 28; /* i: waiting for 32-bit length (gzip) */ + const DONE = 29; /* finished check, done -- remain here until reset */ + const BAD = 30; /* got a data error -- remain here until reset */ + const MEM = 31; /* got an inflate() memory error -- remain here until reset */ + const SYNC = 32; /* looking for synchronization bytes to restart inflate() */ + + /* ===========================================================================*/ + + + + const ENOUGH_LENS = 852; + const ENOUGH_DISTS = 592; + //const ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS); + + const MAX_WBITS = 15; + /* 32K LZ77 window */ + const DEF_WBITS = MAX_WBITS; + + + const zswap32 = (q) => { + + return (((q >>> 24) & 0xff) + + ((q >>> 8) & 0xff00) + + ((q & 0xff00) << 8) + + ((q & 0xff) << 24)); + }; + + + function InflateState() { + this.mode = 0; /* current inflate mode */ + this.last = false; /* true if processing last block */ + this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */ + this.havedict = false; /* true if dictionary provided */ + this.flags = 0; /* gzip header method and flags (0 if zlib) */ + this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */ + this.check = 0; /* protected copy of check value */ + this.total = 0; /* protected copy of output count */ + // TODO: may be {} + this.head = null; /* where to save gzip header information */ + + /* sliding window */ + this.wbits = 0; /* log base 2 of requested window size */ + this.wsize = 0; /* window size or zero if not using window */ + this.whave = 0; /* valid bytes in the window */ + this.wnext = 0; /* window write index */ + this.window = null; /* allocated sliding window, if needed */ + + /* bit accumulator */ + this.hold = 0; /* input bit accumulator */ + this.bits = 0; /* number of bits in "in" */ + + /* for string and stored block copying */ + this.length = 0; /* literal or length of data to copy */ + this.offset = 0; /* distance back to copy string from */ + + /* for table and code decoding */ + this.extra = 0; /* extra bits needed */ + + /* fixed and dynamic code tables */ + this.lencode = null; /* starting table for length/literal codes */ + this.distcode = null; /* starting table for distance codes */ + this.lenbits = 0; /* index bits for lencode */ + this.distbits = 0; /* index bits for distcode */ + + /* dynamic table building */ + this.ncode = 0; /* number of code length code lengths */ + this.nlen = 0; /* number of length code lengths */ + this.ndist = 0; /* number of distance code lengths */ + this.have = 0; /* number of code lengths in lens[] */ + this.next = null; /* next available space in codes[] */ + + this.lens = new Uint16Array(320); /* temporary storage for code lengths */ + this.work = new Uint16Array(288); /* work area for code table building */ + + /* + because we don't have pointers in js, we use lencode and distcode directly + as buffers so we don't need codes + */ + //this.codes = new Int32Array(ENOUGH); /* space for code tables */ + this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */ + this.distdyn = null; /* dynamic table for distance codes (JS specific) */ + this.sane = 0; /* if false, allow invalid distance too far */ + this.back = 0; /* bits back of last unprocessed length/lit */ + this.was = 0; /* initial length of match */ + } + + + const inflateResetKeep = (strm) => { + + if (!strm || !strm.state) { return Z_STREAM_ERROR$1; } + const state = strm.state; + strm.total_in = strm.total_out = state.total = 0; + strm.msg = ''; /*Z_NULL*/ + if (state.wrap) { /* to support ill-conceived Java test suite */ + strm.adler = state.wrap & 1; + } + state.mode = HEAD; + state.last = 0; + state.havedict = 0; + state.dmax = 32768; + state.head = null/*Z_NULL*/; + state.hold = 0; + state.bits = 0; + //state.lencode = state.distcode = state.next = state.codes; + state.lencode = state.lendyn = new Int32Array(ENOUGH_LENS); + state.distcode = state.distdyn = new Int32Array(ENOUGH_DISTS); + + state.sane = 1; + state.back = -1; + //Tracev((stderr, "inflate: reset\n")); + return Z_OK$1; + }; + + + const inflateReset = (strm) => { + + if (!strm || !strm.state) { return Z_STREAM_ERROR$1; } + const state = strm.state; + state.wsize = 0; + state.whave = 0; + state.wnext = 0; + return inflateResetKeep(strm); + + }; + + + const inflateReset2 = (strm, windowBits) => { + let wrap; + + /* get the state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR$1; } + const state = strm.state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; } - Module["dynCall"] = dynCall; - var __pthread_ptr = 0; - var __pthread_is_main_runtime_thread = 0; - var __pthread_is_main_browser_thread = 0; - function registerPthreadPtr(pthreadPtr, isMainBrowserThread, isMainRuntimeThread) { - pthreadPtr = pthreadPtr | 0; - isMainBrowserThread = isMainBrowserThread | 0; - isMainRuntimeThread = isMainRuntimeThread | 0; - __pthread_ptr = pthreadPtr; - __pthread_is_main_browser_thread = isMainBrowserThread; - __pthread_is_main_runtime_thread = isMainRuntimeThread; - } - Module["registerPthreadPtr"] = registerPthreadPtr; - var ERRNO_CODES = { EPERM: 63, ENOENT: 44, ESRCH: 71, EINTR: 27, EIO: 29, ENXIO: 60, E2BIG: 1, ENOEXEC: 45, EBADF: 8, ECHILD: 12, EAGAIN: 6, EWOULDBLOCK: 6, ENOMEM: 48, EACCES: 2, EFAULT: 21, ENOTBLK: 105, EBUSY: 10, EEXIST: 20, EXDEV: 75, ENODEV: 43, ENOTDIR: 54, EISDIR: 31, EINVAL: 28, ENFILE: 41, EMFILE: 33, ENOTTY: 59, ETXTBSY: 74, EFBIG: 22, ENOSPC: 51, ESPIPE: 70, EROFS: 69, EMLINK: 34, EPIPE: 64, EDOM: 18, ERANGE: 68, ENOMSG: 49, EIDRM: 24, ECHRNG: 106, EL2NSYNC: 156, EL3HLT: 107, EL3RST: 108, ELNRNG: 109, EUNATCH: 110, ENOCSI: 111, EL2HLT: 112, EDEADLK: 16, ENOLCK: 46, EBADE: 113, EBADR: 114, EXFULL: 115, ENOANO: 104, EBADRQC: 103, EBADSLT: 102, EDEADLOCK: 16, EBFONT: 101, ENOSTR: 100, ENODATA: 116, ETIME: 117, ENOSR: 118, ENONET: 119, ENOPKG: 120, EREMOTE: 121, ENOLINK: 47, EADV: 122, ESRMNT: 123, ECOMM: 124, EPROTO: 65, EMULTIHOP: 36, EDOTDOT: 125, EBADMSG: 9, ENOTUNIQ: 126, EBADFD: 127, EREMCHG: 128, ELIBACC: 129, ELIBBAD: 130, ELIBSCN: 131, ELIBMAX: 132, ELIBEXEC: 133, ENOSYS: 52, ENOTEMPTY: 55, ENAMETOOLONG: 37, ELOOP: 32, EOPNOTSUPP: 138, EPFNOSUPPORT: 139, ECONNRESET: 15, ENOBUFS: 42, EAFNOSUPPORT: 5, EPROTOTYPE: 67, ENOTSOCK: 57, ENOPROTOOPT: 50, ESHUTDOWN: 140, ECONNREFUSED: 14, EADDRINUSE: 3, ECONNABORTED: 13, ENETUNREACH: 40, ENETDOWN: 38, ETIMEDOUT: 73, EHOSTDOWN: 142, EHOSTUNREACH: 23, EINPROGRESS: 26, EALREADY: 7, EDESTADDRREQ: 17, EMSGSIZE: 35, EPROTONOSUPPORT: 66, ESOCKTNOSUPPORT: 137, EADDRNOTAVAIL: 4, ENETRESET: 39, EISCONN: 30, ENOTCONN: 53, ETOOMANYREFS: 141, EUSERS: 136, EDQUOT: 19, ESTALE: 72, ENOTSUP: 138, ENOMEDIUM: 148, EILSEQ: 25, EOVERFLOW: 61, ECANCELED: 11, ENOTRECOVERABLE: 56, EOWNERDEAD: 62, ESTRPIPE: 135 }; - function _emscripten_futex_wake(addr, count) { - if (addr <= 0 || addr > GROWABLE_HEAP_I8().length || addr & true || count < 0) - return -28; - if (count == 0) - return 0; - if (count >= 2147483647) - count = Infinity; - var mainThreadWaitAddress = Atomics.load(GROWABLE_HEAP_I32(), PThread.mainThreadFutex >> 2); - var mainThreadWoken = 0; - if (mainThreadWaitAddress == addr) { - var loadedAddr = Atomics.compareExchange(GROWABLE_HEAP_I32(), PThread.mainThreadFutex >> 2, mainThreadWaitAddress, 0); - if (loadedAddr == mainThreadWaitAddress) { - --count; - mainThreadWoken = 1; - if (count <= 0) - return 1; + else { + wrap = (windowBits >> 4) + 1; + if (windowBits < 48) { + windowBits &= 15; } - } - var ret = Atomics.notify(GROWABLE_HEAP_I32(), addr >> 2, count); - if (ret >= 0) - return ret + mainThreadWoken; - throw "Atomics.notify returned an unexpected value " + ret; } - Module["_emscripten_futex_wake"] = _emscripten_futex_wake; - function killThread(pthread_ptr) { - if (ENVIRONMENT_IS_PTHREAD) - throw "Internal Error! killThread() can only ever be called from main application thread!"; - if (!pthread_ptr) - throw "Internal Error! Null pthread_ptr in killThread!"; - GROWABLE_HEAP_I32()[pthread_ptr + 12 >> 2] = 0; - var pthread = PThread.pthreads[pthread_ptr]; - pthread.worker.terminate(); - PThread.freeThreadData(pthread); - PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(pthread.worker), 1); - pthread.worker.pthread = void 0; + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) { + return Z_STREAM_ERROR$1; } - function cancelThread(pthread_ptr) { - if (ENVIRONMENT_IS_PTHREAD) - throw "Internal Error! cancelThread() can only ever be called from main application thread!"; - if (!pthread_ptr) - throw "Internal Error! Null pthread_ptr in cancelThread!"; - var pthread = PThread.pthreads[pthread_ptr]; - pthread.worker.postMessage({ "cmd": "cancel" }); + if (state.window !== null && state.wbits !== windowBits) { + state.window = null; } - function cleanupThread(pthread_ptr) { - if (ENVIRONMENT_IS_PTHREAD) - throw "Internal Error! cleanupThread() can only ever be called from main application thread!"; - if (!pthread_ptr) - throw "Internal Error! Null pthread_ptr in cleanupThread!"; - GROWABLE_HEAP_I32()[pthread_ptr + 12 >> 2] = 0; - var pthread = PThread.pthreads[pthread_ptr]; - if (pthread) { - var worker = pthread.worker; - PThread.returnWorkerToPool(worker); - } + + /* update state and reset the rest of it */ + state.wrap = wrap; + state.wbits = windowBits; + return inflateReset(strm); + }; + + + const inflateInit2 = (strm, windowBits) => { + + if (!strm) { return Z_STREAM_ERROR$1; } + //strm.msg = Z_NULL; /* in case we return an error */ + + const state = new InflateState(); + + //if (state === Z_NULL) return Z_MEM_ERROR; + //Tracev((stderr, "inflate: allocated\n")); + strm.state = state; + state.window = null/*Z_NULL*/; + const ret = inflateReset2(strm, windowBits); + if (ret !== Z_OK$1) { + strm.state = null/*Z_NULL*/; } - var PThread = { MAIN_THREAD_ID: 1, mainThreadInfo: { schedPolicy: 0, schedPrio: 0 }, unusedWorkers: [], runningWorkers: [], initMainThreadBlock: function() { - var pthreadPoolSize = navigator.hardwareConcurrency; - for (var i = 0; i < pthreadPoolSize; ++i) { - PThread.allocateUnusedWorker(); - } - }, initRuntime: function() { - PThread.mainThreadBlock = _malloc(232); - for (var i = 0; i < 232 / 4; ++i) - GROWABLE_HEAP_U32()[PThread.mainThreadBlock / 4 + i] = 0; - GROWABLE_HEAP_I32()[PThread.mainThreadBlock + 12 >> 2] = PThread.mainThreadBlock; - var headPtr = PThread.mainThreadBlock + 156; - GROWABLE_HEAP_I32()[headPtr >> 2] = headPtr; - var tlsMemory = _malloc(512); - for (var i = 0; i < 128; ++i) - GROWABLE_HEAP_U32()[tlsMemory / 4 + i] = 0; - Atomics.store(GROWABLE_HEAP_U32(), PThread.mainThreadBlock + 104 >> 2, tlsMemory); - Atomics.store(GROWABLE_HEAP_U32(), PThread.mainThreadBlock + 40 >> 2, PThread.mainThreadBlock); - Atomics.store(GROWABLE_HEAP_U32(), PThread.mainThreadBlock + 44 >> 2, 42); - PThread.initShared(); - registerPthreadPtr(PThread.mainThreadBlock, !ENVIRONMENT_IS_WORKER, 1); - _emscripten_register_main_browser_thread_id(PThread.mainThreadBlock); - }, initWorker: function() { - PThread.initShared(); - readyPromiseResolve(Module); - }, initShared: function() { - PThread.mainThreadFutex = _main_thread_futex; - }, pthreads: {}, threadExitHandlers: [], setThreadStatus: function() { - }, runExitHandlers: function() { - while (PThread.threadExitHandlers.length > 0) { - PThread.threadExitHandlers.pop()(); - } - if (ENVIRONMENT_IS_PTHREAD && threadInfoStruct) - ___pthread_tsd_run_dtors(); - }, threadExit: function(exitCode) { - var tb = _pthread_self(); - if (tb) { - Atomics.store(GROWABLE_HEAP_U32(), tb + 4 >> 2, exitCode); - Atomics.store(GROWABLE_HEAP_U32(), tb + 0 >> 2, 1); - Atomics.store(GROWABLE_HEAP_U32(), tb + 60 >> 2, 1); - Atomics.store(GROWABLE_HEAP_U32(), tb + 64 >> 2, 0); - PThread.runExitHandlers(); - _emscripten_futex_wake(tb + 0, 2147483647); - registerPthreadPtr(0, 0, 0); - threadInfoStruct = 0; - if (ENVIRONMENT_IS_PTHREAD) { - postMessage({ "cmd": "exit" }); - } - } - }, threadCancel: function() { - PThread.runExitHandlers(); - Atomics.store(GROWABLE_HEAP_U32(), threadInfoStruct + 4 >> 2, -1); - Atomics.store(GROWABLE_HEAP_U32(), threadInfoStruct + 0 >> 2, 1); - _emscripten_futex_wake(threadInfoStruct + 0, 2147483647); - threadInfoStruct = 0; - registerPthreadPtr(0, 0, 0); - postMessage({ "cmd": "cancelDone" }); - }, terminateAllThreads: function() { - for (var t in PThread.pthreads) { - var pthread = PThread.pthreads[t]; - if (pthread && pthread.worker) { - PThread.returnWorkerToPool(pthread.worker); - } - } - PThread.pthreads = {}; - for (var i = 0; i < PThread.unusedWorkers.length; ++i) { - var worker = PThread.unusedWorkers[i]; - worker.terminate(); - } - PThread.unusedWorkers = []; - for (var i = 0; i < PThread.runningWorkers.length; ++i) { - var worker = PThread.runningWorkers[i]; - var pthread = worker.pthread; - PThread.freeThreadData(pthread); - worker.terminate(); - } - PThread.runningWorkers = []; - }, freeThreadData: function(pthread) { - if (!pthread) - return; - if (pthread.threadInfoStruct) { - var tlsMemory = GROWABLE_HEAP_I32()[pthread.threadInfoStruct + 104 >> 2]; - GROWABLE_HEAP_I32()[pthread.threadInfoStruct + 104 >> 2] = 0; - _free(tlsMemory); - _free(pthread.threadInfoStruct); - } - pthread.threadInfoStruct = 0; - if (pthread.allocatedOwnStack && pthread.stackBase) - _free(pthread.stackBase); - pthread.stackBase = 0; - if (pthread.worker) - pthread.worker.pthread = null; - }, returnWorkerToPool: function(worker) { - delete PThread.pthreads[worker.pthread.thread]; - PThread.unusedWorkers.push(worker); - PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker), 1); - PThread.freeThreadData(worker.pthread); - worker.pthread = void 0; - }, receiveObjectTransfer: function(data) { - }, loadWasmModuleToWorker: function(worker, onFinishedLoading) { - worker.onmessage = function(e) { - var d = e["data"]; - var cmd = d["cmd"]; - if (worker.pthread) - PThread.currentProxiedOperationCallerThread = worker.pthread.threadInfoStruct; - if (d["targetThread"] && d["targetThread"] != _pthread_self()) { - var thread = PThread.pthreads[d.targetThread]; - if (thread) { - thread.worker.postMessage(e.data, d["transferList"]); - } else { - console.error('Internal error! Worker sent a message "' + cmd + '" to target pthread ' + d["targetThread"] + ", but that thread no longer exists!"); - } - PThread.currentProxiedOperationCallerThread = void 0; - return; + return ret; + }; + + + const inflateInit = (strm) => { + + return inflateInit2(strm, DEF_WBITS); + }; + + + /* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ + let virgin = true; + + let lenfix, distfix; // We have no pointers in JS, so keep tables separate + + + const fixedtables = (state) => { + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + lenfix = new Int32Array(512); + distfix = new Int32Array(32); + + /* literal/length table */ + let sym = 0; + while (sym < 144) { state.lens[sym++] = 8; } + while (sym < 256) { state.lens[sym++] = 9; } + while (sym < 280) { state.lens[sym++] = 7; } + while (sym < 288) { state.lens[sym++] = 8; } + + inftrees(LENS, state.lens, 0, 288, lenfix, 0, state.work, { bits: 9 }); + + /* distance table */ + sym = 0; + while (sym < 32) { state.lens[sym++] = 5; } + + inftrees(DISTS, state.lens, 0, 32, distfix, 0, state.work, { bits: 5 }); + + /* do this just once */ + virgin = false; + } + + state.lencode = lenfix; + state.lenbits = 9; + state.distcode = distfix; + state.distbits = 5; + }; + + + /* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ + const updatewindow = (strm, src, end, copy) => { + + let dist; + const state = strm.state; + + /* if it hasn't been done already, allocate space for the window */ + if (state.window === null) { + state.wsize = 1 << state.wbits; + state.wnext = 0; + state.whave = 0; + + state.window = new Uint8Array(state.wsize); + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state.wsize) { + state.window.set(src.subarray(end - state.wsize, end), 0); + state.wnext = 0; + state.whave = state.wsize; + } + else { + dist = state.wsize - state.wnext; + if (dist > copy) { + dist = copy; + } + //zmemcpy(state->window + state->wnext, end - copy, dist); + state.window.set(src.subarray(end - copy, end - copy + dist), state.wnext); + copy -= dist; + if (copy) { + //zmemcpy(state->window, end - copy, copy); + state.window.set(src.subarray(end - copy, end), 0); + state.wnext = copy; + state.whave = state.wsize; } - if (cmd === "processQueuedMainThreadWork") { - _emscripten_main_thread_process_queued_calls(); - } else if (cmd === "spawnThread") { - spawnThread(e.data); - } else if (cmd === "cleanupThread") { - cleanupThread(d["thread"]); - } else if (cmd === "killThread") { - killThread(d["thread"]); - } else if (cmd === "cancelThread") { - cancelThread(d["thread"]); - } else if (cmd === "loaded") { - worker.loaded = true; - if (onFinishedLoading) - onFinishedLoading(worker); - if (worker.runPthread) { - worker.runPthread(); - delete worker.runPthread; - } - } else if (cmd === "print") { - out("Thread " + d["threadId"] + ": " + d["text"]); - } else if (cmd === "printErr") { - err("Thread " + d["threadId"] + ": " + d["text"]); - } else if (cmd === "alert") { - alert("Thread " + d["threadId"] + ": " + d["text"]); - } else if (cmd === "exit") { - var detached = worker.pthread && Atomics.load(GROWABLE_HEAP_U32(), worker.pthread.thread + 68 >> 2); - if (detached) { - PThread.returnWorkerToPool(worker); - } - } else if (cmd === "cancelDone") { - PThread.returnWorkerToPool(worker); - } else if (cmd === "objectTransfer") { - PThread.receiveObjectTransfer(e.data); - } else if (e.data.target === "setimmediate") { - worker.postMessage(e.data); - } else { - err("worker sent an unknown command " + cmd); + else { + state.wnext += dist; + if (state.wnext === state.wsize) { state.wnext = 0; } + if (state.whave < state.wsize) { state.whave += dist; } } - PThread.currentProxiedOperationCallerThread = void 0; - }; - worker.onerror = function(e) { - err("pthread sent an error! " + e.filename + ":" + e.lineno + ": " + e.message); - }; - if (ENVIRONMENT_IS_NODE) { - worker.on("message", function(data) { - worker.onmessage({ data }); - }); - worker.on("error", function(data) { - worker.onerror(data); - }); - worker.on("exit", function(data) { - }); - } - worker.postMessage({ "cmd": "load", "urlOrBlob": Module["mainScriptUrlOrBlob"] || _scriptDir, "wasmMemory": wasmMemory, "wasmModule": wasmModule }); - }, allocateUnusedWorker: function() { - var pthreadMainJs = locateFile("web-ifc-mt.worker.js"); - PThread.unusedWorkers.push(new Worker(pthreadMainJs)); - }, getNewWorker: function() { - if (PThread.unusedWorkers.length == 0) { - PThread.allocateUnusedWorker(); - PThread.loadWasmModuleToWorker(PThread.unusedWorkers[0]); - } - if (PThread.unusedWorkers.length > 0) - return PThread.unusedWorkers.pop(); - else - return null; - }, busySpinWait: function(msecs) { - var t = performance.now() + msecs; - while (performance.now() < t) { - } - } }; - function establishStackSpace(stackTop, stackMax) { - _emscripten_stack_set_limits(stackTop, stackMax); - stackRestore(stackTop); } - Module["establishStackSpace"] = establishStackSpace; - function getNoExitRuntime() { - return noExitRuntime; + return 0; + }; + + + const inflate$2 = (strm, flush) => { + + let state; + let input, output; // input/output buffers + let next; /* next input INDEX */ + let put; /* next output INDEX */ + let have, left; /* available input and output */ + let hold; /* bit buffer */ + let bits; /* bits in bit buffer */ + let _in, _out; /* save starting available input and output */ + let copy; /* number of stored or match bytes to copy */ + let from; /* where to copy match bytes from */ + let from_source; + let here = 0; /* current decoding table entry */ + let here_bits, here_op, here_val; // paked "here" denormalized (JS specific) + //let last; /* parent table entry */ + let last_bits, last_op, last_val; // paked "last" denormalized (JS specific) + let len; /* length to copy for repeats, bits to drop */ + let ret; /* return code */ + const hbuf = new Uint8Array(4); /* buffer for gzip header crc calculation */ + let opts; + + let n; // temporary variable for NEED_BITS + + const order = /* permutation of code lengths */ + new Uint8Array([ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ]); + + + if (!strm || !strm.state || !strm.output || + (!strm.input && strm.avail_in !== 0)) { + return Z_STREAM_ERROR$1; } - Module["getNoExitRuntime"] = getNoExitRuntime; - function ___assert_fail(condition, filename, line, func) { - abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function"]); + + state = strm.state; + if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */ + + + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + _in = have; + _out = left; + ret = Z_OK$1; + + inf_leave: // goto emulation + for (;;) { + switch (state.mode) { + case HEAD: + if (state.wrap === 0) { + state.mode = TYPEDO; + break; + } + //=== NEEDBITS(16); + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */ + state.check = 0/*crc32(0L, Z_NULL, 0)*/; + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); + //===// + + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = FLAGS; + break; + } + state.flags = 0; /* expect zlib header */ + if (state.head) { + state.head.done = false; + } + if (!(state.wrap & 1) || /* check if zlib header allowed */ + (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) { + strm.msg = 'incorrect header check'; + state.mode = BAD; + break; + } + if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + len = (hold & 0x0f)/*BITS(4)*/ + 8; + if (state.wbits === 0) { + state.wbits = len; + } + else if (len > state.wbits) { + strm.msg = 'invalid window size'; + state.mode = BAD; + break; + } + + // !!! pako patch. Force use `options.windowBits` if passed. + // Required to always use max window size by default. + state.dmax = 1 << state.wbits; + //state.dmax = 1 << len; + + //Tracev((stderr, "inflate: zlib header ok\n")); + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = hold & 0x200 ? DICTID : TYPE; + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + break; + case FLAGS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.flags = hold; + if ((state.flags & 0xff) !== Z_DEFLATED) { + strm.msg = 'unknown compression method'; + state.mode = BAD; + break; + } + if (state.flags & 0xe000) { + strm.msg = 'unknown header flags set'; + state.mode = BAD; + break; + } + if (state.head) { + state.head.text = ((hold >> 8) & 1); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = TIME; + /* falls through */ + case TIME: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.time = hold; + } + if (state.flags & 0x0200) { + //=== CRC4(state.check, hold) + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + hbuf[2] = (hold >>> 16) & 0xff; + hbuf[3] = (hold >>> 24) & 0xff; + state.check = crc32_1(state.check, hbuf, 4, 0); + //=== + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = OS; + /* falls through */ + case OS: + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (state.head) { + state.head.xflags = (hold & 0xff); + state.head.os = (hold >> 8); + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = EXLEN; + /* falls through */ + case EXLEN: + if (state.flags & 0x0400) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length = hold; + if (state.head) { + state.head.extra_len = hold; + } + if (state.flags & 0x0200) { + //=== CRC2(state.check, hold); + hbuf[0] = hold & 0xff; + hbuf[1] = (hold >>> 8) & 0xff; + state.check = crc32_1(state.check, hbuf, 2, 0); + //===// + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + else if (state.head) { + state.head.extra = null/*Z_NULL*/; + } + state.mode = EXTRA; + /* falls through */ + case EXTRA: + if (state.flags & 0x0400) { + copy = state.length; + if (copy > have) { copy = have; } + if (copy) { + if (state.head) { + len = state.head.extra_len - state.length; + if (!state.head.extra) { + // Use untyped array for more convenient processing later + state.head.extra = new Uint8Array(state.head.extra_len); + } + state.head.extra.set( + input.subarray( + next, + // extra field is limited to 65536 bytes + // - no need for additional size check + next + copy + ), + /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/ + len + ); + //zmemcpy(state.head.extra + len, next, + // len + copy > state.head.extra_max ? + // state.head.extra_max - len : copy); + } + if (state.flags & 0x0200) { + state.check = crc32_1(state.check, input, copy, next); + } + have -= copy; + next += copy; + state.length -= copy; + } + if (state.length) { break inf_leave; } + } + state.length = 0; + state.mode = NAME; + /* falls through */ + case NAME: + if (state.flags & 0x0800) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + // TODO: 2 or 1 bytes? + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.name_max*/)) { + state.head.name += String.fromCharCode(len); + } + } while (len && copy < have); + + if (state.flags & 0x0200) { + state.check = crc32_1(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.name = null; + } + state.length = 0; + state.mode = COMMENT; + /* falls through */ + case COMMENT: + if (state.flags & 0x1000) { + if (have === 0) { break inf_leave; } + copy = 0; + do { + len = input[next + copy++]; + /* use constant limit because in js we should not preallocate memory */ + if (state.head && len && + (state.length < 65536 /*state.head.comm_max*/)) { + state.head.comment += String.fromCharCode(len); + } + } while (len && copy < have); + if (state.flags & 0x0200) { + state.check = crc32_1(state.check, input, copy, next); + } + have -= copy; + next += copy; + if (len) { break inf_leave; } + } + else if (state.head) { + state.head.comment = null; + } + state.mode = HCRC; + /* falls through */ + case HCRC: + if (state.flags & 0x0200) { + //=== NEEDBITS(16); */ + while (bits < 16) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.check & 0xffff)) { + strm.msg = 'header crc mismatch'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + } + if (state.head) { + state.head.hcrc = ((state.flags >> 9) & 1); + state.head.done = true; + } + strm.adler = state.check = 0; + state.mode = TYPE; + break; + case DICTID: + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + strm.adler = state.check = zswap32(hold); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = DICT; + /* falls through */ + case DICT: + if (state.havedict === 0) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + return Z_NEED_DICT$1; + } + strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/; + state.mode = TYPE; + /* falls through */ + case TYPE: + if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; } + /* falls through */ + case TYPEDO: + if (state.last) { + //--- BYTEBITS() ---// + hold >>>= bits & 7; + bits -= bits & 7; + //---// + state.mode = CHECK; + break; + } + //=== NEEDBITS(3); */ + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.last = (hold & 0x01)/*BITS(1)*/; + //--- DROPBITS(1) ---// + hold >>>= 1; + bits -= 1; + //---// + + switch ((hold & 0x03)/*BITS(2)*/) { + case 0: /* stored block */ + //Tracev((stderr, "inflate: stored block%s\n", + // state.last ? " (last)" : "")); + state.mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + //Tracev((stderr, "inflate: fixed codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = LEN_; /* decode codes */ + if (flush === Z_TREES) { + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break inf_leave; + } + break; + case 2: /* dynamic block */ + //Tracev((stderr, "inflate: dynamic codes block%s\n", + // state.last ? " (last)" : "")); + state.mode = TABLE; + break; + case 3: + strm.msg = 'invalid block type'; + state.mode = BAD; + } + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + break; + case STORED: + //--- BYTEBITS() ---// /* go to byte boundary */ + hold >>>= bits & 7; + bits -= bits & 7; + //---// + //=== NEEDBITS(32); */ + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) { + strm.msg = 'invalid stored block lengths'; + state.mode = BAD; + break; + } + state.length = hold & 0xffff; + //Tracev((stderr, "inflate: stored length %u\n", + // state.length)); + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + state.mode = COPY_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case COPY_: + state.mode = COPY; + /* falls through */ + case COPY: + copy = state.length; + if (copy) { + if (copy > have) { copy = have; } + if (copy > left) { copy = left; } + if (copy === 0) { break inf_leave; } + //--- zmemcpy(put, next, copy); --- + output.set(input.subarray(next, next + copy), put); + //---// + have -= copy; + next += copy; + left -= copy; + put += copy; + state.length -= copy; + break; + } + //Tracev((stderr, "inflate: stored end\n")); + state.mode = TYPE; + break; + case TABLE: + //=== NEEDBITS(14); */ + while (bits < 14) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1; + //--- DROPBITS(5) ---// + hold >>>= 5; + bits -= 5; + //---// + state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4; + //--- DROPBITS(4) ---// + hold >>>= 4; + bits -= 4; + //---// + //#ifndef PKZIP_BUG_WORKAROUND + if (state.nlen > 286 || state.ndist > 30) { + strm.msg = 'too many length or distance symbols'; + state.mode = BAD; + break; + } + //#endif + //Tracev((stderr, "inflate: table sizes ok\n")); + state.have = 0; + state.mode = LENLENS; + /* falls through */ + case LENLENS: + while (state.have < state.ncode) { + //=== NEEDBITS(3); + while (bits < 3) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.lens[order[state.have++]] = (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + while (state.have < 19) { + state.lens[order[state.have++]] = 0; + } + // We have separate tables & no pointers. 2 commented lines below not needed. + //state.next = state.codes; + //state.lencode = state.next; + // Switch to use dynamic table + state.lencode = state.lendyn; + state.lenbits = 7; + + opts = { bits: state.lenbits }; + ret = inftrees(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts); + state.lenbits = opts.bits; + + if (ret) { + strm.msg = 'invalid code lengths set'; + state.mode = BAD; + break; + } + //Tracev((stderr, "inflate: code lengths ok\n")); + state.have = 0; + state.mode = CODELENS; + /* falls through */ + case CODELENS: + while (state.have < state.nlen + state.ndist) { + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_val < 16) { + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.lens[state.have++] = here_val; + } + else { + if (here_val === 16) { + //=== NEEDBITS(here.bits + 2); + n = here_bits + 2; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + if (state.have === 0) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + len = state.lens[state.have - 1]; + copy = 3 + (hold & 0x03);//BITS(2); + //--- DROPBITS(2) ---// + hold >>>= 2; + bits -= 2; + //---// + } + else if (here_val === 17) { + //=== NEEDBITS(here.bits + 3); + n = here_bits + 3; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 3 + (hold & 0x07);//BITS(3); + //--- DROPBITS(3) ---// + hold >>>= 3; + bits -= 3; + //---// + } + else { + //=== NEEDBITS(here.bits + 7); + n = here_bits + 7; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + len = 0; + copy = 11 + (hold & 0x7f);//BITS(7); + //--- DROPBITS(7) ---// + hold >>>= 7; + bits -= 7; + //---// + } + if (state.have + copy > state.nlen + state.ndist) { + strm.msg = 'invalid bit length repeat'; + state.mode = BAD; + break; + } + while (copy--) { + state.lens[state.have++] = len; + } + } + } + + /* handle error breaks in while */ + if (state.mode === BAD) { break; } + + /* check for end-of-block code (better have one) */ + if (state.lens[256] === 0) { + strm.msg = 'invalid code -- missing end-of-block'; + state.mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state.lenbits = 9; + + opts = { bits: state.lenbits }; + ret = inftrees(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.lenbits = opts.bits; + // state.lencode = state.next; + + if (ret) { + strm.msg = 'invalid literal/lengths set'; + state.mode = BAD; + break; + } + + state.distbits = 6; + //state.distcode.copy(state.codes); + // Switch to use dynamic table + state.distcode = state.distdyn; + opts = { bits: state.distbits }; + ret = inftrees(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts); + // We have separate tables & no pointers. 2 commented lines below not needed. + // state.next_index = opts.table_index; + state.distbits = opts.bits; + // state.distcode = state.next; + + if (ret) { + strm.msg = 'invalid distances set'; + state.mode = BAD; + break; + } + //Tracev((stderr, 'inflate: codes ok\n')); + state.mode = LEN_; + if (flush === Z_TREES) { break inf_leave; } + /* falls through */ + case LEN_: + state.mode = LEN; + /* falls through */ + case LEN: + if (have >= 6 && left >= 258) { + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + inffast(strm, _out); + //--- LOAD() --- + put = strm.next_out; + output = strm.output; + left = strm.avail_out; + next = strm.next_in; + input = strm.input; + have = strm.avail_in; + hold = state.hold; + bits = state.bits; + //--- + + if (state.mode === TYPE) { + state.back = -1; + } + break; + } + state.back = 0; + for (;;) { + here = state.lencode[hold & ((1 << state.lenbits) - 1)]; /*BITS(state.lenbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if (here_bits <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if (here_op && (here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.lencode[last_val + + ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + state.length = here_val; + if (here_op === 0) { + //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + // "inflate: literal '%c'\n" : + // "inflate: literal 0x%02x\n", here.val)); + state.mode = LIT; + break; + } + if (here_op & 32) { + //Tracevv((stderr, "inflate: end of block\n")); + state.back = -1; + state.mode = TYPE; + break; + } + if (here_op & 64) { + strm.msg = 'invalid literal/length code'; + state.mode = BAD; + break; + } + state.extra = here_op & 15; + state.mode = LENEXT; + /* falls through */ + case LENEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.length += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //Tracevv((stderr, "inflate: length %u\n", state.length)); + state.was = state.length; + state.mode = DIST; + /* falls through */ + case DIST: + for (;;) { + here = state.distcode[hold & ((1 << state.distbits) - 1)];/*BITS(state.distbits)*/ + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + if ((here_op & 0xf0) === 0) { + last_bits = here_bits; + last_op = here_op; + last_val = here_val; + for (;;) { + here = state.distcode[last_val + + ((hold & ((1 << (last_bits + last_op)) - 1))/*BITS(last.bits + last.op)*/ >> last_bits)]; + here_bits = here >>> 24; + here_op = (here >>> 16) & 0xff; + here_val = here & 0xffff; + + if ((last_bits + here_bits) <= bits) { break; } + //--- PULLBYTE() ---// + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + //---// + } + //--- DROPBITS(last.bits) ---// + hold >>>= last_bits; + bits -= last_bits; + //---// + state.back += last_bits; + } + //--- DROPBITS(here.bits) ---// + hold >>>= here_bits; + bits -= here_bits; + //---// + state.back += here_bits; + if (here_op & 64) { + strm.msg = 'invalid distance code'; + state.mode = BAD; + break; + } + state.offset = here_val; + state.extra = (here_op) & 15; + state.mode = DISTEXT; + /* falls through */ + case DISTEXT: + if (state.extra) { + //=== NEEDBITS(state.extra); + n = state.extra; + while (bits < n) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + state.offset += hold & ((1 << state.extra) - 1)/*BITS(state.extra)*/; + //--- DROPBITS(state.extra) ---// + hold >>>= state.extra; + bits -= state.extra; + //---// + state.back += state.extra; + } + //#ifdef INFLATE_STRICT + if (state.offset > state.dmax) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } + //#endif + //Tracevv((stderr, "inflate: distance %u\n", state.offset)); + state.mode = MATCH; + /* falls through */ + case MATCH: + if (left === 0) { break inf_leave; } + copy = _out - left; + if (state.offset > copy) { /* copy from window */ + copy = state.offset - copy; + if (copy > state.whave) { + if (state.sane) { + strm.msg = 'invalid distance too far back'; + state.mode = BAD; + break; + } + // (!) This block is disabled in zlib defaults, + // don't enable it for binary compatibility + //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + // Trace((stderr, "inflate.c too far\n")); + // copy -= state.whave; + // if (copy > state.length) { copy = state.length; } + // if (copy > left) { copy = left; } + // left -= copy; + // state.length -= copy; + // do { + // output[put++] = 0; + // } while (--copy); + // if (state.length === 0) { state.mode = LEN; } + // break; + //#endif + } + if (copy > state.wnext) { + copy -= state.wnext; + from = state.wsize - copy; + } + else { + from = state.wnext - copy; + } + if (copy > state.length) { copy = state.length; } + from_source = state.window; + } + else { /* copy from output */ + from_source = output; + from = put - state.offset; + copy = state.length; + } + if (copy > left) { copy = left; } + left -= copy; + state.length -= copy; + do { + output[put++] = from_source[from++]; + } while (--copy); + if (state.length === 0) { state.mode = LEN; } + break; + case LIT: + if (left === 0) { break inf_leave; } + output[put++] = state.length; + left--; + state.mode = LEN; + break; + case CHECK: + if (state.wrap) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + // Use '|' instead of '+' to make sure that result is signed + hold |= input[next++] << bits; + bits += 8; + } + //===// + _out -= left; + strm.total_out += _out; + state.total += _out; + if (_out) { + strm.adler = state.check = + /*UPDATE(state.check, put - _out, _out);*/ + (state.flags ? crc32_1(state.check, output, _out, put - _out) : adler32_1(state.check, output, _out, put - _out)); + + } + _out = left; + // NB: crc32 stored as signed 32-bit int, zswap32 returns signed too + if ((state.flags ? hold : zswap32(hold)) !== state.check) { + strm.msg = 'incorrect data check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: check matches trailer\n")); + } + state.mode = LENGTH; + /* falls through */ + case LENGTH: + if (state.wrap && state.flags) { + //=== NEEDBITS(32); + while (bits < 32) { + if (have === 0) { break inf_leave; } + have--; + hold += input[next++] << bits; + bits += 8; + } + //===// + if (hold !== (state.total & 0xffffffff)) { + strm.msg = 'incorrect length check'; + state.mode = BAD; + break; + } + //=== INITBITS(); + hold = 0; + bits = 0; + //===// + //Tracev((stderr, "inflate: length matches trailer\n")); + } + state.mode = DONE; + /* falls through */ + case DONE: + ret = Z_STREAM_END$1; + break inf_leave; + case BAD: + ret = Z_DATA_ERROR$1; + break inf_leave; + case MEM: + return Z_MEM_ERROR$1; + case SYNC: + /* falls through */ + default: + return Z_STREAM_ERROR$1; + } + } + + // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave" + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + //--- RESTORE() --- + strm.next_out = put; + strm.avail_out = left; + strm.next_in = next; + strm.avail_in = have; + state.hold = hold; + state.bits = bits; + //--- + + if (state.wsize || (_out !== strm.avail_out && state.mode < BAD && + (state.mode < CHECK || flush !== Z_FINISH$1))) { + if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) ; + } + _in -= strm.avail_in; + _out -= strm.avail_out; + strm.total_in += _in; + strm.total_out += _out; + state.total += _out; + if (state.wrap && _out) { + strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/ + (state.flags ? crc32_1(state.check, output, _out, strm.next_out - _out) : adler32_1(state.check, output, _out, strm.next_out - _out)); + } + strm.data_type = state.bits + (state.last ? 64 : 0) + + (state.mode === TYPE ? 128 : 0) + + (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0); + if (((_in === 0 && _out === 0) || flush === Z_FINISH$1) && ret === Z_OK$1) { + ret = Z_BUF_ERROR; + } + return ret; + }; + + + const inflateEnd = (strm) => { + + if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) { + return Z_STREAM_ERROR$1; } - var _emscripten_get_now; - if (ENVIRONMENT_IS_NODE) { - _emscripten_get_now = function() { - var t = process["hrtime"](); - return t[0] * 1e3 + t[1] / 1e6; - }; - } else if (ENVIRONMENT_IS_PTHREAD) { - _emscripten_get_now = function() { - return performance.now() - Module["__performance_now_clock_drift"]; - }; - } else if (typeof dateNow !== "undefined") { - _emscripten_get_now = dateNow; - } else - _emscripten_get_now = function() { - return performance.now(); - }; - var _emscripten_get_now_is_monotonic = true; - function setErrNo(value) { - GROWABLE_HEAP_I32()[___errno_location() >> 2] = value; - return value; + + let state = strm.state; + if (state.window) { + state.window = null; } - function _clock_gettime(clk_id, tp) { - var now; - if (clk_id === 0) { - now = Date.now(); - } else if ((clk_id === 1 || clk_id === 4) && _emscripten_get_now_is_monotonic) { - now = _emscripten_get_now(); - } else { - setErrNo(28); - return -1; - } - GROWABLE_HEAP_I32()[tp >> 2] = now / 1e3 | 0; - GROWABLE_HEAP_I32()[tp + 4 >> 2] = now % 1e3 * 1e3 * 1e3 | 0; - return 0; + strm.state = null; + return Z_OK$1; + }; + + + const inflateGetHeader = (strm, head) => { + + /* check state */ + if (!strm || !strm.state) { return Z_STREAM_ERROR$1; } + const state = strm.state; + if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR$1; } + + /* save header structure */ + state.head = head; + head.done = false; + return Z_OK$1; + }; + + + const inflateSetDictionary = (strm, dictionary) => { + const dictLength = dictionary.length; + + let state; + let dictid; + let ret; + + /* check state */ + if (!strm /* == Z_NULL */ || !strm.state /* == Z_NULL */) { return Z_STREAM_ERROR$1; } + state = strm.state; + + if (state.wrap !== 0 && state.mode !== DICT) { + return Z_STREAM_ERROR$1; } - var ExceptionInfoAttrs = { DESTRUCTOR_OFFSET: 0, REFCOUNT_OFFSET: 4, TYPE_OFFSET: 8, CAUGHT_OFFSET: 12, RETHROWN_OFFSET: 13, SIZE: 16 }; - function ___cxa_allocate_exception(size) { - return _malloc(size + ExceptionInfoAttrs.SIZE) + ExceptionInfoAttrs.SIZE; + + /* check for correct dictionary identifier */ + if (state.mode === DICT) { + dictid = 1; /* adler32(0, null, 0)*/ + /* dictid = adler32(dictid, dictionary, dictLength); */ + dictid = adler32_1(dictid, dictionary, dictLength, 0); + if (dictid !== state.check) { + return Z_DATA_ERROR$1; + } } - function _atexit(func, arg) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(1, 1, func, arg); + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary, dictLength, dictLength); + if (ret) { + state.mode = MEM; + return Z_MEM_ERROR$1; } - function ExceptionInfo(excPtr) { - this.excPtr = excPtr; - this.ptr = excPtr - ExceptionInfoAttrs.SIZE; - this.set_type = function(type) { - GROWABLE_HEAP_I32()[this.ptr + ExceptionInfoAttrs.TYPE_OFFSET >> 2] = type; - }; - this.get_type = function() { - return GROWABLE_HEAP_I32()[this.ptr + ExceptionInfoAttrs.TYPE_OFFSET >> 2]; - }; - this.set_destructor = function(destructor) { - GROWABLE_HEAP_I32()[this.ptr + ExceptionInfoAttrs.DESTRUCTOR_OFFSET >> 2] = destructor; - }; - this.get_destructor = function() { - return GROWABLE_HEAP_I32()[this.ptr + ExceptionInfoAttrs.DESTRUCTOR_OFFSET >> 2]; - }; - this.set_refcount = function(refcount) { - GROWABLE_HEAP_I32()[this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >> 2] = refcount; - }; - this.set_caught = function(caught) { - caught = caught ? 1 : 0; - GROWABLE_HEAP_I8()[this.ptr + ExceptionInfoAttrs.CAUGHT_OFFSET >> 0] = caught; - }; - this.get_caught = function() { - return GROWABLE_HEAP_I8()[this.ptr + ExceptionInfoAttrs.CAUGHT_OFFSET >> 0] != 0; - }; - this.set_rethrown = function(rethrown) { - rethrown = rethrown ? 1 : 0; - GROWABLE_HEAP_I8()[this.ptr + ExceptionInfoAttrs.RETHROWN_OFFSET >> 0] = rethrown; - }; - this.get_rethrown = function() { - return GROWABLE_HEAP_I8()[this.ptr + ExceptionInfoAttrs.RETHROWN_OFFSET >> 0] != 0; - }; - this.init = function(type, destructor) { - this.set_type(type); - this.set_destructor(destructor); - this.set_refcount(0); - this.set_caught(false); - this.set_rethrown(false); - }; - this.add_ref = function() { - Atomics.add(GROWABLE_HEAP_I32(), this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >> 2, 1); - }; - this.release_ref = function() { - var prev = Atomics.sub(GROWABLE_HEAP_I32(), this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >> 2, 1); - return prev === 1; - }; + state.havedict = 1; + // Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK$1; + }; + + + var inflateReset_1 = inflateReset; + var inflateReset2_1 = inflateReset2; + var inflateResetKeep_1 = inflateResetKeep; + var inflateInit_1 = inflateInit; + var inflateInit2_1 = inflateInit2; + var inflate_2$1 = inflate$2; + var inflateEnd_1 = inflateEnd; + var inflateGetHeader_1 = inflateGetHeader; + var inflateSetDictionary_1 = inflateSetDictionary; + var inflateInfo = 'pako inflate (from Nodeca project)'; + + /* Not implemented + module.exports.inflateCopy = inflateCopy; + module.exports.inflateGetDictionary = inflateGetDictionary; + module.exports.inflateMark = inflateMark; + module.exports.inflatePrime = inflatePrime; + module.exports.inflateSync = inflateSync; + module.exports.inflateSyncPoint = inflateSyncPoint; + module.exports.inflateUndermine = inflateUndermine; + */ + + var inflate_1$2 = { + inflateReset: inflateReset_1, + inflateReset2: inflateReset2_1, + inflateResetKeep: inflateResetKeep_1, + inflateInit: inflateInit_1, + inflateInit2: inflateInit2_1, + inflate: inflate_2$1, + inflateEnd: inflateEnd_1, + inflateGetHeader: inflateGetHeader_1, + inflateSetDictionary: inflateSetDictionary_1, + inflateInfo: inflateInfo + }; + + // (C) 1995-2013 Jean-loup Gailly and Mark Adler + // (C) 2014-2017 Vitaly Puzrin and Andrey Tupitsin + // + // This software is provided 'as-is', without any express or implied + // warranty. In no event will the authors be held liable for any damages + // arising from the use of this software. + // + // Permission is granted to anyone to use this software for any purpose, + // including commercial applications, and to alter it and redistribute it + // freely, subject to the following restrictions: + // + // 1. The origin of this software must not be misrepresented; you must not + // claim that you wrote the original software. If you use this software + // in a product, an acknowledgment in the product documentation would be + // appreciated but is not required. + // 2. Altered source versions must be plainly marked as such, and must not be + // misrepresented as being the original software. + // 3. This notice may not be removed or altered from any source distribution. + + function GZheader() { + /* true if compressed data believed to be text */ + this.text = 0; + /* modification time */ + this.time = 0; + /* extra flags (not used when writing a gzip file) */ + this.xflags = 0; + /* operating system */ + this.os = 0; + /* pointer to extra field or Z_NULL if none */ + this.extra = null; + /* extra field length (valid if extra != Z_NULL) */ + this.extra_len = 0; // Actually, we don't need it in JS, + // but leave for few code modifications + + // + // Setup limits is not necessary because in js we should not preallocate memory + // for inflate use constant limit in 65536 bytes + // + + /* space at extra (only when reading header) */ + // this.extra_max = 0; + /* pointer to zero-terminated file name or Z_NULL */ + this.name = ''; + /* space at name (only when reading header) */ + // this.name_max = 0; + /* pointer to zero-terminated comment or Z_NULL */ + this.comment = ''; + /* space at comment (only when reading header) */ + // this.comm_max = 0; + /* true if there was or will be a header crc */ + this.hcrc = 0; + /* true when done reading gzip header (not used when writing a gzip file) */ + this.done = false; + } + + var gzheader = GZheader; + + const toString = Object.prototype.toString; + + /* Public constants ==========================================================*/ + /* ===========================================================================*/ + + const { + Z_NO_FLUSH, Z_FINISH, + Z_OK, Z_STREAM_END, Z_NEED_DICT, Z_STREAM_ERROR, Z_DATA_ERROR, Z_MEM_ERROR + } = constants$2; + + /* ===========================================================================*/ + + + /** + * class Inflate + * + * Generic JS-style wrapper for zlib calls. If you don't need + * streaming behaviour - use more simple functions: [[inflate]] + * and [[inflateRaw]]. + **/ + + /* internal + * inflate.chunks -> Array + * + * Chunks of output data, if [[Inflate#onData]] not overridden. + **/ + + /** + * Inflate.result -> Uint8Array|String + * + * Uncompressed result, generated by default [[Inflate#onData]] + * and [[Inflate#onEnd]] handlers. Filled after you push last chunk + * (call [[Inflate#push]] with `Z_FINISH` / `true` param). + **/ + + /** + * Inflate.err -> Number + * + * Error code after inflate finished. 0 (Z_OK) on success. + * Should be checked if broken data possible. + **/ + + /** + * Inflate.msg -> String + * + * Error message, if [[Inflate.err]] != 0 + **/ + + + /** + * new Inflate(options) + * - options (Object): zlib inflate options. + * + * Creates new inflator instance with specified params. Throws exception + * on bad params. Supported options: + * + * - `windowBits` + * - `dictionary` + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information on these. + * + * Additional options, for internal needs: + * + * - `chunkSize` - size of generated data chunks (16K by default) + * - `raw` (Boolean) - do raw inflate + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * By default, when no options set, autodetect deflate/gzip data format via + * wrapper header. + * + * ##### Example: + * + * ```javascript + * const pako = require('pako') + * const chunk1 = new Uint8Array([1,2,3,4,5,6,7,8,9]) + * const chunk2 = new Uint8Array([10,11,12,13,14,15,16,17,18,19]); + * + * const inflate = new pako.Inflate({ level: 3}); + * + * inflate.push(chunk1, false); + * inflate.push(chunk2, true); // true -> last chunk + * + * if (inflate.err) { throw new Error(inflate.err); } + * + * console.log(inflate.result); + * ``` + **/ + function Inflate$1(options) { + this.options = common.assign({ + chunkSize: 1024 * 64, + windowBits: 15, + to: '' + }, options || {}); + + const opt = this.options; + + // Force window size for `raw` data, if not set directly, + // because we have no header for autodetect. + if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) { + opt.windowBits = -opt.windowBits; + if (opt.windowBits === 0) { opt.windowBits = -15; } } - function ___cxa_throw(ptr, type, destructor) { - var info = new ExceptionInfo(ptr); - info.init(type, destructor); - throw ptr; + + // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate + if ((opt.windowBits >= 0) && (opt.windowBits < 16) && + !(options && options.windowBits)) { + opt.windowBits += 32; } - var PATH = { splitPath: function(filename) { - var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; - return splitPathRe.exec(filename).slice(1); - }, normalizeArray: function(parts, allowAboveRoot) { - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === ".") { - parts.splice(i, 1); - } else if (last === "..") { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - if (allowAboveRoot) { - for (; up; up--) { - parts.unshift(".."); - } - } - return parts; - }, normalize: function(path) { - var isAbsolute = path.charAt(0) === "/", trailingSlash = path.substr(-1) === "/"; - path = PATH.normalizeArray(path.split("/").filter(function(p) { - return !!p; - }), !isAbsolute).join("/"); - if (!path && !isAbsolute) { - path = "."; - } - if (path && trailingSlash) { - path += "/"; - } - return (isAbsolute ? "/" : "") + path; - }, dirname: function(path) { - var result = PATH.splitPath(path), root = result[0], dir = result[1]; - if (!root && !dir) { - return "."; - } - if (dir) { - dir = dir.substr(0, dir.length - 1); - } - return root + dir; - }, basename: function(path) { - if (path === "/") - return "/"; - path = PATH.normalize(path); - path = path.replace(/\/$/, ""); - var lastSlash = path.lastIndexOf("/"); - if (lastSlash === -1) - return path; - return path.substr(lastSlash + 1); - }, extname: function(path) { - return PATH.splitPath(path)[3]; - }, join: function() { - var paths = Array.prototype.slice.call(arguments, 0); - return PATH.normalize(paths.join("/")); - }, join2: function(l, r) { - return PATH.normalize(l + "/" + r); - } }; - function getRandomDevice() { - if (typeof crypto === "object" && typeof crypto["getRandomValues"] === "function") { - var randomBuffer = new Uint8Array(1); - return function() { - crypto.getRandomValues(randomBuffer); - return randomBuffer[0]; - }; - } else if (ENVIRONMENT_IS_NODE) { - try { - var crypto_module = require_crypto(); - return function() { - return crypto_module["randomBytes"](1)[0]; - }; - } catch (e) { + + // Gzip header has no info about windows size, we can do autodetect only + // for deflate. So, if window size not set, force it to max when gzip possible + if ((opt.windowBits > 15) && (opt.windowBits < 48)) { + // bit 3 (16) -> gzipped data + // bit 4 (32) -> autodetect gzip/deflate + if ((opt.windowBits & 15) === 0) { + opt.windowBits |= 15; } - } - return function() { - abort("randomDevice"); - }; } - var PATH_FS = { resolve: function() { - var resolvedPath = "", resolvedAbsolute = false; - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = i >= 0 ? arguments[i] : FS.cwd(); - if (typeof path !== "string") { - throw new TypeError("Arguments to path.resolve must be strings"); - } else if (!path) { - return ""; + + this.err = 0; // error code, if happens (0 = Z_OK) + this.msg = ''; // error message + this.ended = false; // used to avoid multiple onEnd() calls + this.chunks = []; // chunks of compressed data + + this.strm = new zstream(); + this.strm.avail_out = 0; + + let status = inflate_1$2.inflateInit2( + this.strm, + opt.windowBits + ); + + if (status !== Z_OK) { + throw new Error(messages[status]); + } + + this.header = new gzheader(); + + inflate_1$2.inflateGetHeader(this.strm, this.header); + + // Setup dictionary + if (opt.dictionary) { + // Convert data if needed + if (typeof opt.dictionary === 'string') { + opt.dictionary = strings.string2buf(opt.dictionary); + } else if (toString.call(opt.dictionary) === '[object ArrayBuffer]') { + opt.dictionary = new Uint8Array(opt.dictionary); } - resolvedPath = path + "/" + resolvedPath; - resolvedAbsolute = path.charAt(0) === "/"; - } - resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(function(p) { - return !!p; - }), !resolvedAbsolute).join("/"); - return (resolvedAbsolute ? "/" : "") + resolvedPath || "."; - }, relative: function(from, to) { - from = PATH_FS.resolve(from).substr(1); - to = PATH_FS.resolve(to).substr(1); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== "") - break; + if (opt.raw) { //In raw mode we need to set the dictionary early + status = inflate_1$2.inflateSetDictionary(this.strm, opt.dictionary); + if (status !== Z_OK) { + throw new Error(messages[status]); + } } - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== "") - break; + } + } + + /** + * Inflate#push(data[, flush_mode]) -> Boolean + * - data (Uint8Array|ArrayBuffer): input data + * - flush_mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE + * flush modes. See constants. Skipped or `false` means Z_NO_FLUSH, + * `true` means Z_FINISH. + * + * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with + * new output chunks. Returns `true` on success. If end of stream detected, + * [[Inflate#onEnd]] will be called. + * + * `flush_mode` is not needed for normal operation, because end of stream + * detected automatically. You may try to use it for advanced things, but + * this functionality was not tested. + * + * On fail call [[Inflate#onEnd]] with error code and return false. + * + * ##### Example + * + * ```javascript + * push(chunk, false); // push one of data chunks + * ... + * push(chunk, true); // push last chunk + * ``` + **/ + Inflate$1.prototype.push = function (data, flush_mode) { + const strm = this.strm; + const chunkSize = this.options.chunkSize; + const dictionary = this.options.dictionary; + let status, _flush_mode, last_avail_out; + + if (this.ended) return false; + + if (flush_mode === ~~flush_mode) _flush_mode = flush_mode; + else _flush_mode = flush_mode === true ? Z_FINISH : Z_NO_FLUSH; + + // Convert data if needed + if (toString.call(data) === '[object ArrayBuffer]') { + strm.input = new Uint8Array(data); + } else { + strm.input = data; + } + + strm.next_in = 0; + strm.avail_in = strm.input.length; + + for (;;) { + if (strm.avail_out === 0) { + strm.output = new Uint8Array(chunkSize); + strm.next_out = 0; + strm.avail_out = chunkSize; } - if (start > end) - return []; - return arr.slice(start, end - start + 1); - } - var fromParts = trim(from.split("/")); - var toParts = trim(to.split("/")); - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; + + status = inflate_1$2.inflate(strm, _flush_mode); + + if (status === Z_NEED_DICT && dictionary) { + status = inflate_1$2.inflateSetDictionary(strm, dictionary); + + if (status === Z_OK) { + status = inflate_1$2.inflate(strm, _flush_mode); + } else if (status === Z_DATA_ERROR) { + // Replace code with more verbose + status = Z_NEED_DICT; + } } - } - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push(".."); - } - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join("/"); - } }; - var TTY = { ttys: [], init: function() { - }, shutdown: function() { - }, register: function(dev, ops) { - TTY.ttys[dev] = { input: [], output: [], ops }; - FS.registerDevice(dev, TTY.stream_ops); - }, stream_ops: { open: function(stream) { - var tty = TTY.ttys[stream.node.rdev]; - if (!tty) { - throw new FS.ErrnoError(43); - } - stream.tty = tty; - stream.seekable = false; - }, close: function(stream) { - stream.tty.ops.flush(stream.tty); - }, flush: function(stream) { - stream.tty.ops.flush(stream.tty); - }, read: function(stream, buffer2, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.get_char) { - throw new FS.ErrnoError(60); - } - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = stream.tty.ops.get_char(stream.tty); - } catch (e) { - throw new FS.ErrnoError(29); + + // Skip snyc markers if more data follows and not raw mode + while (strm.avail_in > 0 && + status === Z_STREAM_END && + strm.state.wrap > 0 && + data[strm.next_in] !== 0) + { + inflate_1$2.inflateReset(strm); + status = inflate_1$2.inflate(strm, _flush_mode); } - if (result === void 0 && bytesRead === 0) { - throw new FS.ErrnoError(6); + + switch (status) { + case Z_STREAM_ERROR: + case Z_DATA_ERROR: + case Z_NEED_DICT: + case Z_MEM_ERROR: + this.onEnd(status); + this.ended = true; + return false; } - if (result === null || result === void 0) - break; - bytesRead++; - buffer2[offset + i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, write: function(stream, buffer2, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.put_char) { - throw new FS.ErrnoError(60); - } - try { - for (var i = 0; i < length; i++) { - stream.tty.ops.put_char(stream.tty, buffer2[offset + i]); + + // Remember real `avail_out` value, because we may patch out buffer content + // to align utf8 strings boundaries. + last_avail_out = strm.avail_out; + + if (strm.next_out) { + if (strm.avail_out === 0 || status === Z_STREAM_END) { + + if (this.options.to === 'string') { + + let next_out_utf8 = strings.utf8border(strm.output, strm.next_out); + + let tail = strm.next_out - next_out_utf8; + let utf8str = strings.buf2string(strm.output, next_out_utf8); + + // move tail & realign counters + strm.next_out = tail; + strm.avail_out = chunkSize - tail; + if (tail) strm.output.set(strm.output.subarray(next_out_utf8, next_out_utf8 + tail), 0); + + this.onData(utf8str); + + } else { + this.onData(strm.output.length === strm.next_out ? strm.output : strm.output.subarray(0, strm.next_out)); + } + } } - } catch (e) { - throw new FS.ErrnoError(29); - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - } }, default_tty_ops: { get_char: function(tty) { - if (!tty.input.length) { - var result = null; - if (ENVIRONMENT_IS_NODE) { - var BUFSIZE = 256; - var buf = Buffer.alloc ? Buffer.alloc(BUFSIZE) : new Buffer(BUFSIZE); - var bytesRead = 0; - try { - bytesRead = nodeFS.readSync(process.stdin.fd, buf, 0, BUFSIZE, null); - } catch (e) { - if (e.toString().indexOf("EOF") != -1) - bytesRead = 0; - else - throw e; - } - if (bytesRead > 0) { - result = buf.slice(0, bytesRead).toString("utf-8"); - } else { - result = null; - } - } else if (typeof window != "undefined" && typeof window.prompt == "function") { - result = window.prompt("Input: "); - if (result !== null) { - result += "\n"; - } - } else if (typeof readline == "function") { - result = readline(); - if (result !== null) { - result += "\n"; - } + + // Must repeat iteration if out buffer is full + if (status === Z_OK && last_avail_out === 0) continue; + + // Finalize if end of stream reached. + if (status === Z_STREAM_END) { + status = inflate_1$2.inflateEnd(this.strm); + this.onEnd(status); + this.ended = true; + return true; } - if (!result) { - return null; + + if (strm.avail_in === 0) break; + } + + return true; + }; + + + /** + * Inflate#onData(chunk) -> Void + * - chunk (Uint8Array|String): output data. When string output requested, + * each chunk will be string. + * + * By default, stores data blocks in `chunks[]` property and glue + * those in `onEnd`. Override this handler, if you need another behaviour. + **/ + Inflate$1.prototype.onData = function (chunk) { + this.chunks.push(chunk); + }; + + + /** + * Inflate#onEnd(status) -> Void + * - status (Number): inflate status. 0 (Z_OK) on success, + * other if not. + * + * Called either after you tell inflate that the input stream is + * complete (Z_FINISH). By default - join collected chunks, + * free memory and fill `results` / `err` properties. + **/ + Inflate$1.prototype.onEnd = function (status) { + // On success - join + if (status === Z_OK) { + if (this.options.to === 'string') { + this.result = this.chunks.join(''); + } else { + this.result = common.flattenChunks(this.chunks); } - tty.input = intArrayFromString(result, true); - } - return tty.input.shift(); - }, put_char: function(tty, val) { - if (val === null || val === 10) { - out(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } else { - if (val != 0) - tty.output.push(val); - } - }, flush: function(tty) { - if (tty.output && tty.output.length > 0) { - out(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } - } }, default_tty1_ops: { put_char: function(tty, val) { - if (val === null || val === 10) { - err(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } else { - if (val != 0) - tty.output.push(val); - } - }, flush: function(tty) { - if (tty.output && tty.output.length > 0) { - err(UTF8ArrayToString(tty.output, 0)); - tty.output = []; - } - } } }; - function mmapAlloc(size) { - var alignedSize = alignMemory(size, 16384); - var ptr = _malloc(alignedSize); - while (size < alignedSize) - GROWABLE_HEAP_I8()[ptr + size++] = 0; - return ptr; } - var MEMFS = { ops_table: null, mount: function(mount) { - return MEMFS.createNode(null, "/", 16384 | 511, 0); - }, createNode: function(parent, name2, mode, dev) { - if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { - throw new FS.ErrnoError(63); - } - if (!MEMFS.ops_table) { - MEMFS.ops_table = { dir: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr, lookup: MEMFS.node_ops.lookup, mknod: MEMFS.node_ops.mknod, rename: MEMFS.node_ops.rename, unlink: MEMFS.node_ops.unlink, rmdir: MEMFS.node_ops.rmdir, readdir: MEMFS.node_ops.readdir, symlink: MEMFS.node_ops.symlink }, stream: { llseek: MEMFS.stream_ops.llseek } }, file: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr }, stream: { llseek: MEMFS.stream_ops.llseek, read: MEMFS.stream_ops.read, write: MEMFS.stream_ops.write, allocate: MEMFS.stream_ops.allocate, mmap: MEMFS.stream_ops.mmap, msync: MEMFS.stream_ops.msync } }, link: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr, readlink: MEMFS.node_ops.readlink }, stream: {} }, chrdev: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr }, stream: FS.chrdev_stream_ops } }; - } - var node = FS.createNode(parent, name2, mode, dev); - if (FS.isDir(node.mode)) { - node.node_ops = MEMFS.ops_table.dir.node; - node.stream_ops = MEMFS.ops_table.dir.stream; - node.contents = {}; - } else if (FS.isFile(node.mode)) { - node.node_ops = MEMFS.ops_table.file.node; - node.stream_ops = MEMFS.ops_table.file.stream; - node.usedBytes = 0; - node.contents = null; - } else if (FS.isLink(node.mode)) { - node.node_ops = MEMFS.ops_table.link.node; - node.stream_ops = MEMFS.ops_table.link.stream; - } else if (FS.isChrdev(node.mode)) { - node.node_ops = MEMFS.ops_table.chrdev.node; - node.stream_ops = MEMFS.ops_table.chrdev.stream; - } - node.timestamp = Date.now(); - if (parent) { - parent.contents[name2] = node; - } - return node; - }, getFileDataAsRegularArray: function(node) { - if (node.contents && node.contents.subarray) { - var arr = []; - for (var i = 0; i < node.usedBytes; ++i) - arr.push(node.contents[i]); - return arr; - } - return node.contents; - }, getFileDataAsTypedArray: function(node) { - if (!node.contents) - return new Uint8Array(0); - if (node.contents.subarray) - return node.contents.subarray(0, node.usedBytes); - return new Uint8Array(node.contents); - }, expandFileStorage: function(node, newCapacity) { - newCapacity >>>= 0; - var prevCapacity = node.contents ? node.contents.length : 0; - if (prevCapacity >= newCapacity) - return; - var CAPACITY_DOUBLING_MAX = 1024 * 1024; - newCapacity = Math.max(newCapacity, prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125) >>> 0); - if (prevCapacity != 0) - newCapacity = Math.max(newCapacity, 256); - var oldContents = node.contents; - node.contents = new Uint8Array(newCapacity); - if (node.usedBytes > 0) - node.contents.set(oldContents.subarray(0, node.usedBytes), 0); - return; - }, resizeFileStorage: function(node, newSize) { - newSize >>>= 0; - if (node.usedBytes == newSize) - return; - if (newSize == 0) { - node.contents = null; - node.usedBytes = 0; - return; - } - if (!node.contents || node.contents.subarray) { - var oldContents = node.contents; - node.contents = new Uint8Array(newSize); - if (oldContents) { - node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); - } - node.usedBytes = newSize; - return; - } - if (!node.contents) - node.contents = []; - if (node.contents.length > newSize) - node.contents.length = newSize; - else - while (node.contents.length < newSize) - node.contents.push(0); - node.usedBytes = newSize; - }, node_ops: { getattr: function(node) { - var attr = {}; - attr.dev = FS.isChrdev(node.mode) ? node.id : 1; - attr.ino = node.id; - attr.mode = node.mode; - attr.nlink = 1; - attr.uid = 0; - attr.gid = 0; - attr.rdev = node.rdev; - if (FS.isDir(node.mode)) { - attr.size = 4096; - } else if (FS.isFile(node.mode)) { - attr.size = node.usedBytes; - } else if (FS.isLink(node.mode)) { - attr.size = node.link.length; - } else { - attr.size = 0; - } - attr.atime = new Date(node.timestamp); - attr.mtime = new Date(node.timestamp); - attr.ctime = new Date(node.timestamp); - attr.blksize = 4096; - attr.blocks = Math.ceil(attr.size / attr.blksize); - return attr; - }, setattr: function(node, attr) { - if (attr.mode !== void 0) { - node.mode = attr.mode; - } - if (attr.timestamp !== void 0) { - node.timestamp = attr.timestamp; - } - if (attr.size !== void 0) { - MEMFS.resizeFileStorage(node, attr.size); - } - }, lookup: function(parent, name2) { - throw FS.genericErrors[44]; - }, mknod: function(parent, name2, mode, dev) { - return MEMFS.createNode(parent, name2, mode, dev); - }, rename: function(old_node, new_dir, new_name) { - if (FS.isDir(old_node.mode)) { - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) { - } - if (new_node) { - for (var i in new_node.contents) { - throw new FS.ErrnoError(55); - } - } - } - delete old_node.parent.contents[old_node.name]; - old_node.name = new_name; - new_dir.contents[new_name] = old_node; - old_node.parent = new_dir; - }, unlink: function(parent, name2) { - delete parent.contents[name2]; - }, rmdir: function(parent, name2) { - var node = FS.lookupNode(parent, name2); - for (var i in node.contents) { - throw new FS.ErrnoError(55); - } - delete parent.contents[name2]; - }, readdir: function(node) { - var entries = [".", ".."]; - for (var key2 in node.contents) { - if (!node.contents.hasOwnProperty(key2)) { - continue; - } - entries.push(key2); - } - return entries; - }, symlink: function(parent, newname, oldpath) { - var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); - node.link = oldpath; - return node; - }, readlink: function(node) { - if (!FS.isLink(node.mode)) { - throw new FS.ErrnoError(28); - } - return node.link; - } }, stream_ops: { read: function(stream, buffer2, offset, length, position) { - var contents = stream.node.contents; - if (position >= stream.node.usedBytes) - return 0; - var size = Math.min(stream.node.usedBytes - position, length); - if (size > 8 && contents.subarray) { - buffer2.set(contents.subarray(position, position + size), offset); - } else { - for (var i = 0; i < size; i++) - buffer2[offset + i] = contents[position + i]; - } - return size; - }, write: function(stream, buffer2, offset, length, position, canOwn) { - if (buffer2.buffer === GROWABLE_HEAP_I8().buffer) { - canOwn = false; - } - if (!length) - return 0; - var node = stream.node; - node.timestamp = Date.now(); - if (buffer2.subarray && (!node.contents || node.contents.subarray)) { - if (canOwn) { - node.contents = buffer2.subarray(offset, offset + length); - node.usedBytes = length; - return length; - } else if (node.usedBytes === 0 && position === 0) { - node.contents = buffer2.slice(offset, offset + length); - node.usedBytes = length; - return length; - } else if (position + length <= node.usedBytes) { - node.contents.set(buffer2.subarray(offset, offset + length), position); - return length; - } - } - MEMFS.expandFileStorage(node, position + length); - if (node.contents.subarray && buffer2.subarray) { - node.contents.set(buffer2.subarray(offset, offset + length), position); - } else { - for (var i = 0; i < length; i++) { - node.contents[position + i] = buffer2[offset + i]; - } - } - node.usedBytes = Math.max(node.usedBytes, position + length); - return length; - }, llseek: function(stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - position += stream.node.usedBytes; + this.chunks = []; + this.err = status; + this.msg = this.strm.msg; + }; + + + /** + * inflate(data[, options]) -> Uint8Array|String + * - data (Uint8Array): input data to decompress. + * - options (Object): zlib inflate options. + * + * Decompress `data` with inflate/ungzip and `options`. Autodetect + * format via wrapper header by default. That's why we don't provide + * separate `ungzip` method. + * + * Supported options are: + * + * - windowBits + * + * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced) + * for more information. + * + * Sugar (options): + * + * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify + * negative windowBits implicitly. + * - `to` (String) - if equal to 'string', then result will be converted + * from utf8 to utf16 (javascript) string. When string output requested, + * chunk length can differ from `chunkSize`, depending on content. + * + * + * ##### Example: + * + * ```javascript + * const pako = require('pako'); + * const input = pako.deflate(new Uint8Array([1,2,3,4,5,6,7,8,9])); + * let output; + * + * try { + * output = pako.inflate(input); + * } catch (err) { + * console.log(err); + * } + * ``` + **/ + function inflate$1(input, options) { + const inflator = new Inflate$1(options); + + inflator.push(input); + + // That will never happens, if you don't cheat with options :) + if (inflator.err) throw inflator.msg || messages[inflator.err]; + + return inflator.result; + } + + + /** + * inflateRaw(data[, options]) -> Uint8Array|String + * - data (Uint8Array): input data to decompress. + * - options (Object): zlib inflate options. + * + * The same as [[inflate]], but creates raw data, without wrapper + * (header and adler32 crc). + **/ + function inflateRaw$1(input, options) { + options = options || {}; + options.raw = true; + return inflate$1(input, options); + } + + + /** + * ungzip(data[, options]) -> Uint8Array|String + * - data (Uint8Array): input data to decompress. + * - options (Object): zlib inflate options. + * + * Just shortcut to [[inflate]], because it autodetects format + * by header.content. Done for convenience. + **/ + + + var Inflate_1$1 = Inflate$1; + var inflate_2 = inflate$1; + var inflateRaw_1$1 = inflateRaw$1; + var ungzip$1 = inflate$1; + var constants = constants$2; + + var inflate_1$1 = { + Inflate: Inflate_1$1, + inflate: inflate_2, + inflateRaw: inflateRaw_1$1, + ungzip: ungzip$1, + constants: constants + }; + + const { Deflate, deflate, deflateRaw, gzip } = deflate_1$1; + + const { Inflate, inflate, inflateRaw, ungzip } = inflate_1$1; + + + + var Deflate_1 = Deflate; + var deflate_1 = deflate; + var deflateRaw_1 = deflateRaw; + var gzip_1 = gzip; + var Inflate_1 = Inflate; + var inflate_1 = inflate; + var inflateRaw_1 = inflateRaw; + var ungzip_1 = ungzip; + var constants_1 = constants$2; + + var pako = { + Deflate: Deflate_1, + deflate: deflate_1, + deflateRaw: deflateRaw_1, + gzip: gzip_1, + Inflate: Inflate_1, + inflate: inflate_1, + inflateRaw: inflateRaw_1, + ungzip: ungzip_1, + constants: constants_1 + }; + + exports.Deflate = Deflate_1; + exports.Inflate = Inflate_1; + exports.constants = constants_1; + exports['default'] = pako; + exports.deflate = deflate_1; + exports.deflateRaw = deflateRaw_1; + exports.gzip = gzip_1; + exports.inflate = inflate_1; + exports.inflateRaw = inflateRaw_1; + exports.ungzip = ungzip_1; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); + +var p = /*#__PURE__*/Object.freeze({ + __proto__: null +}); + +/* + + Parser for .XKT Format V1 + +.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + + DEPRECATED + + */ + +let pako$9 = window.pako || p; +if (!pako$9.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$9 = pako$9.default; +} + +const decompressColor$9 = (function () { + const color2 = new Float32Array(3); + return function (color) { + color2[0] = color[0] / 255.0; + color2[1] = color[1] / 255.0; + color2[2] = color[2] / 255.0; + return color2; + }; +})(); + +function extract$9(elements) { + return { + positions: elements[0], + normals: elements[1], + indices: elements[2], + edgeIndices: elements[3], + meshPositions: elements[4], + meshIndices: elements[5], + meshEdgesIndices: elements[6], + meshColors: elements[7], + entityIDs: elements[8], + entityMeshes: elements[9], + entityIsObjects: elements[10], + positionsDecodeMatrix: elements[11] + }; +} + +function inflate$9(deflatedData) { + return { + positions: new Uint16Array(pako$9.inflate(deflatedData.positions).buffer), + normals: new Int8Array(pako$9.inflate(deflatedData.normals).buffer), + indices: new Uint32Array(pako$9.inflate(deflatedData.indices).buffer), + edgeIndices: new Uint32Array(pako$9.inflate(deflatedData.edgeIndices).buffer), + meshPositions: new Uint32Array(pako$9.inflate(deflatedData.meshPositions).buffer), + meshIndices: new Uint32Array(pako$9.inflate(deflatedData.meshIndices).buffer), + meshEdgesIndices: new Uint32Array(pako$9.inflate(deflatedData.meshEdgesIndices).buffer), + meshColors: new Uint8Array(pako$9.inflate(deflatedData.meshColors).buffer), + entityIDs: pako$9.inflate(deflatedData.entityIDs, {to: 'string'}), + entityMeshes: new Uint32Array(pako$9.inflate(deflatedData.entityMeshes).buffer), + entityIsObjects: new Uint8Array(pako$9.inflate(deflatedData.entityIsObjects).buffer), + positionsDecodeMatrix: new Float32Array(pako$9.inflate(deflatedData.positionsDecodeMatrix).buffer) + }; +} + +function load$9(viewer, options, inflatedData, sceneModel) { + + sceneModel.positionsCompression = "precompressed"; + sceneModel.normalsCompression = "precompressed"; + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + const meshPositions = inflatedData.meshPositions; + const meshIndices = inflatedData.meshIndices; + const meshEdgesIndices = inflatedData.meshEdgesIndices; + const meshColors = inflatedData.meshColors; + const entityIDs = JSON.parse(inflatedData.entityIDs); + const entityMeshes = inflatedData.entityMeshes; + const entityIsObjects = inflatedData.entityIsObjects; + const numMeshes = meshPositions.length; + const numEntities = entityMeshes.length; + + for (let i = 0; i < numEntities; i++) { + + const xktEntityId = entityIDs [i]; + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + + if (metaObject) { + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; } - } - if (position < 0) { - throw new FS.ErrnoError(28); - } - return position; - }, allocate: function(stream, offset, length) { - MEMFS.expandFileStorage(stream.node, offset + length); - stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); - }, mmap: function(stream, address, length, position, prot, flags) { - assert(address === 0); - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - var ptr; - var allocated; - var contents = stream.node.contents; - if (!(flags & 2) && contents.buffer === buffer) { - allocated = false; - ptr = contents.byteOffset; - } else { - if (position > 0 || position + length < contents.length) { - if (contents.subarray) { - contents = contents.subarray(position, position + length); - } else { - contents = Array.prototype.slice.call(contents, position, position + length); - } + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; } - allocated = true; - ptr = mmapAlloc(length); - if (!ptr) { - throw new FS.ErrnoError(48); + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } } - ptr >>>= 0; - GROWABLE_HEAP_I8().set(contents, ptr); - } - return { ptr, allocated }; - }, msync: function(stream, buffer2, offset, length, mmapFlags) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (mmapFlags & 2) { - return 0; - } - MEMFS.stream_ops.write(stream, buffer2, 0, length, offset, false); - return 0; - } } }; - var FS = { root: null, mounts: [], devices: {}, streams: [], nextInode: 1, nameTable: null, currentPath: "/", initialized: false, ignorePermissions: true, trackingDelegate: {}, tracking: { openFlags: { READ: 1, WRITE: 2 } }, ErrnoError: null, genericErrors: {}, filesystems: null, syncFSRequests: 0, lookupPath: function(path, opts) { - path = PATH_FS.resolve(FS.cwd(), path); - opts = opts || {}; - if (!path) - return { path: "", node: null }; - var defaults = { follow_mount: true, recurse_count: 0 }; - for (var key2 in defaults) { - if (opts[key2] === void 0) { - opts[key2] = defaults[key2]; + } else { + if (options.excludeUnclassifiedObjects) { + continue; } - } - if (opts.recurse_count > 8) { - throw new FS.ErrnoError(32); - } - var parts = PATH.normalizeArray(path.split("/").filter(function(p) { - return !!p; - }), false); - var current = FS.root; - var current_path = "/"; - for (var i = 0; i < parts.length; i++) { - var islast = i === parts.length - 1; - if (islast && opts.parent) { - break; + } + + const lastEntity = (i === numEntities - 1); + const meshIds = []; + + for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshes.length : entityMeshes [i + 1]; j < jlen; j++) { + + const lastMesh = (j === (numMeshes - 1)); + const meshId = entityId + ".mesh." + j; + + const color = decompressColor$9(meshColors.subarray((j * 4), (j * 4) + 3)); + const opacity = meshColors[(j * 4) + 3] / 255.0; + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + primitive: "triangles", + positionsCompressed: positions.subarray(meshPositions [j], lastMesh ? positions.length : meshPositions [j + 1]), + normalsCompressed: normals.subarray(meshPositions [j], lastMesh ? positions.length : meshPositions [j + 1]), + indices: indices.subarray(meshIndices [j], lastMesh ? indices.length : meshIndices [j + 1]), + edgeIndices: edgeIndices.subarray(meshEdgesIndices [j], lastMesh ? edgeIndices.length : meshEdgesIndices [j + 1]), + positionsDecodeMatrix: inflatedData.positionsDecodeMatrix, + color: color, + opacity: opacity + })); + + meshIds.push(meshId); + } + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: (entityIsObjects [i] === 1), + meshIds: meshIds + })); + } +} + +/** @private */ +const ParserV1 = { + version: 1, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$9(elements); + const inflatedData = inflate$9(deflatedData); + load$9(viewer, options, inflatedData, sceneModel); + } +}; + +/* + +Parser for .XKT Format V2 + +DEPRECATED + +.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + + */ + +let pako$8 = window.pako || p; +if (!pako$8.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$8 = pako$8.default; +} + +function extract$8(elements) { + return { + + positions: elements[0], + normals: elements[1], + indices: elements[2], + edgeIndices: elements[3], + + meshPositions: elements[4], + meshIndices: elements[5], + meshEdgesIndices: elements[6], + meshColors: elements[7], + + entityIDs: elements[8], + entityMeshes: elements[9], + entityIsObjects: elements[10], + + positionsDecodeMatrix: elements[11], + + entityMeshIds: elements[12], + entityMatrices: elements[13], + entityUsesInstancing: elements[14] + }; +} + +function inflate$8(deflatedData) { + return { + positions: new Uint16Array(pako$8.inflate(deflatedData.positions).buffer), + normals: new Int8Array(pako$8.inflate(deflatedData.normals).buffer), + indices: new Uint32Array(pako$8.inflate(deflatedData.indices).buffer), + edgeIndices: new Uint32Array(pako$8.inflate(deflatedData.edgeIndices).buffer), + + meshPositions: new Uint32Array(pako$8.inflate(deflatedData.meshPositions).buffer), + meshIndices: new Uint32Array(pako$8.inflate(deflatedData.meshIndices).buffer), + meshEdgesIndices: new Uint32Array(pako$8.inflate(deflatedData.meshEdgesIndices).buffer), + meshColors: new Uint8Array(pako$8.inflate(deflatedData.meshColors).buffer), + + entityIDs: pako$8.inflate(deflatedData.entityIDs, {to: 'string'}), + entityMeshes: new Uint32Array(pako$8.inflate(deflatedData.entityMeshes).buffer), + entityIsObjects: new Uint8Array(pako$8.inflate(deflatedData.entityIsObjects).buffer), + + positionsDecodeMatrix: new Float32Array(pako$8.inflate(deflatedData.positionsDecodeMatrix).buffer), + + entityMeshIds: new Uint32Array(pako$8.inflate(deflatedData.entityMeshIds).buffer), + entityMatrices: new Float32Array(pako$8.inflate(deflatedData.entityMatrices).buffer), + entityUsesInstancing: new Uint8Array(pako$8.inflate(deflatedData.entityUsesInstancing).buffer) + }; +} + +const decompressColor$8 = (function () { + const color2 = new Float32Array(3); + return function (color) { + color2[0] = color[0] / 255.0; + color2[1] = color[1] / 255.0; + color2[2] = color[2] / 255.0; + return color2; + }; +})(); + +function load$8(viewer, options, inflatedData, sceneModel) { + + sceneModel.positionsCompression = "precompressed"; + sceneModel.normalsCompression = "precompressed"; + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + const meshPositions = inflatedData.meshPositions; + const meshIndices = inflatedData.meshIndices; + const meshEdgesIndices = inflatedData.meshEdgesIndices; + const meshColors = inflatedData.meshColors; + const entityIDs = JSON.parse(inflatedData.entityIDs); + const entityMeshes = inflatedData.entityMeshes; + const entityIsObjects = inflatedData.entityIsObjects; + const entityMeshIds = inflatedData.entityMeshIds; + const entityMatrices = inflatedData.entityMatrices; + const entityUsesInstancing = inflatedData.entityUsesInstancing; + + const numMeshes = meshPositions.length; + const numEntities = entityMeshes.length; + + const alreadyCreatedGeometries = {}; + + for (let i = 0; i < numEntities; i++) { + + const xktEntityId = entityIDs [i]; + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + const entityMatrix = entityMatrices.subarray((i * 16), (i * 16) + 16); + + if (metaObject) { + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; } - current = FS.lookupNode(current, parts[i]); - current_path = PATH.join2(current_path, parts[i]); - if (FS.isMountpoint(current)) { - if (!islast || islast && opts.follow_mount) { - current = current.mounted.root; - } + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; } - if (!islast || opts.follow) { - var count = 0; - while (FS.isLink(current.mode)) { - var link = FS.readlink(current_path); - current_path = PATH_FS.resolve(PATH.dirname(current_path), link); - var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count }); - current = lookup.node; - if (count++ > 40) { - throw new FS.ErrnoError(32); + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; } - } - } - } - return { path: current_path, node: current }; - }, getPath: function(node) { - var path; - while (true) { - if (FS.isRoot(node)) { - var mount = node.mount.mountpoint; - if (!path) - return mount; - return mount[mount.length - 1] !== "/" ? mount + "/" + path : mount + path; } - path = path ? node.name + "/" + path : node.name; - node = node.parent; - } - }, hashName: function(parentid, name2) { - var hash = 0; - for (var i = 0; i < name2.length; i++) { - hash = (hash << 5) - hash + name2.charCodeAt(i) | 0; - } - return (parentid + hash >>> 0) % FS.nameTable.length; - }, hashAddNode: function(node) { - var hash = FS.hashName(node.parent.id, node.name); - node.name_next = FS.nameTable[hash]; - FS.nameTable[hash] = node; - }, hashRemoveNode: function(node) { - var hash = FS.hashName(node.parent.id, node.name); - if (FS.nameTable[hash] === node) { - FS.nameTable[hash] = node.name_next; - } else { - var current = FS.nameTable[hash]; - while (current) { - if (current.name_next === node) { - current.name_next = node.name_next; - break; - } - current = current.name_next; + } else { + if (options.excludeUnclassifiedObjects) { + continue; } - } - }, lookupNode: function(parent, name2) { - var errCode = FS.mayLookup(parent); - if (errCode) { - throw new FS.ErrnoError(errCode, parent); - } - var hash = FS.hashName(parent.id, name2); - for (var node = FS.nameTable[hash]; node; node = node.name_next) { - var nodeName = node.name; - if (node.parent.id === parent.id && nodeName === name2) { - return node; + } + + const lastEntity = (i === numEntities - 1); + + const meshIds = []; + + for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshIds.length : entityMeshes [i + 1]; j < jlen; j++) { + + const jj = entityMeshIds [j]; + + const lastMesh = (jj === (numMeshes - 1)); + const meshId = entityId + ".mesh." + jj; + + const color = decompressColor$8(meshColors.subarray((jj * 4), (jj * 4) + 3)); + const opacity = meshColors[(jj * 4) + 3] / 255.0; + + const tmpPositions = positions.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); + const tmpNormals = normals.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); + const tmpIndices = indices.subarray(meshIndices [jj], lastMesh ? indices.length : meshIndices [jj + 1]); + const tmpEdgeIndices = edgeIndices.subarray(meshEdgesIndices [jj], lastMesh ? edgeIndices.length : meshEdgesIndices [jj + 1]); + + if (entityUsesInstancing [i] === 1) { + + const geometryId = "geometry." + jj; + + if (!(geometryId in alreadyCreatedGeometries)) { + + sceneModel.createGeometry({ + id: geometryId, + positionsCompressed: tmpPositions, + normalsCompressed: tmpNormals, + indices: tmpIndices, + edgeIndices: tmpEdgeIndices, + primitive: "triangles", + positionsDecodeMatrix: inflatedData.positionsDecodeMatrix, + }); + + alreadyCreatedGeometries [geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + color: color, + opacity: opacity, + matrix: entityMatrix, + geometryId: geometryId, + })); + + meshIds.push(meshId); + + } else { + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + primitive: "triangles", + positionsCompressed: tmpPositions, + normalsCompressed: tmpNormals, + indices: tmpIndices, + edgeIndices: tmpEdgeIndices, + positionsDecodeMatrix: inflatedData.positionsDecodeMatrix, + color: color, + opacity: opacity + })); + + meshIds.push(meshId); } - } - return FS.lookup(parent, name2); - }, createNode: function(parent, name2, mode, rdev) { - var node = new FS.FSNode(parent, name2, mode, rdev); - FS.hashAddNode(node); - return node; - }, destroyNode: function(node) { - FS.hashRemoveNode(node); - }, isRoot: function(node) { - return node === node.parent; - }, isMountpoint: function(node) { - return !!node.mounted; - }, isFile: function(mode) { - return (mode & 61440) === 32768; - }, isDir: function(mode) { - return (mode & 61440) === 16384; - }, isLink: function(mode) { - return (mode & 61440) === 40960; - }, isChrdev: function(mode) { - return (mode & 61440) === 8192; - }, isBlkdev: function(mode) { - return (mode & 61440) === 24576; - }, isFIFO: function(mode) { - return (mode & 61440) === 4096; - }, isSocket: function(mode) { - return (mode & 49152) === 49152; - }, flagModes: { "r": 0, "r+": 2, "w": 577, "w+": 578, "a": 1089, "a+": 1090 }, modeStringToFlags: function(str) { - var flags = FS.flagModes[str]; - if (typeof flags === "undefined") { - throw new Error("Unknown file open mode: " + str); - } - return flags; - }, flagsToPermissionString: function(flag) { - var perms = ["r", "w", "rw"][flag & 3]; - if (flag & 512) { - perms += "w"; - } - return perms; - }, nodePermissions: function(node, perms) { - if (FS.ignorePermissions) { - return 0; - } - if (perms.indexOf("r") !== -1 && !(node.mode & 292)) { - return 2; - } else if (perms.indexOf("w") !== -1 && !(node.mode & 146)) { - return 2; - } else if (perms.indexOf("x") !== -1 && !(node.mode & 73)) { - return 2; - } - return 0; - }, mayLookup: function(dir) { - var errCode = FS.nodePermissions(dir, "x"); - if (errCode) - return errCode; - if (!dir.node_ops.lookup) - return 2; - return 0; - }, mayCreate: function(dir, name2) { - try { - var node = FS.lookupNode(dir, name2); - return 20; - } catch (e) { - } - return FS.nodePermissions(dir, "wx"); - }, mayDelete: function(dir, name2, isdir) { - var node; - try { - node = FS.lookupNode(dir, name2); - } catch (e) { - return e.errno; - } - var errCode = FS.nodePermissions(dir, "wx"); - if (errCode) { - return errCode; - } - if (isdir) { - if (!FS.isDir(node.mode)) { - return 54; + } + + if (meshIds.length) { + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: (entityIsObjects [i] === 1), + meshIds: meshIds + })); + } + } +} + +/** @private */ +const ParserV2 = { + version: 2, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$8(elements); + const inflatedData = inflate$8(deflatedData); + load$8(viewer, options, inflatedData, sceneModel); + } +}; + +/* + +Parser for .XKT Format V3 + +.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + + */ + +let pako$7 = window.pako || p; +if (!pako$7.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$7 = pako$7.default; +} + +function extract$7(elements) { + return { + positions: elements[0], + normals: elements[1], + indices: elements[2], + edgeIndices: elements[3], + meshPositions: elements[4], + meshIndices: elements[5], + meshEdgesIndices: elements[6], + meshColors: elements[7], + entityIDs: elements[8], + entityMeshes: elements[9], + entityIsObjects: elements[10], + instancedPositionsDecodeMatrix: elements[11], + batchedPositionsDecodeMatrix: elements[12], + entityMeshIds: elements[13], + entityMatrices: elements[14], + entityUsesInstancing: elements[15] + }; +} + +function inflate$7(deflatedData) { + return { + positions: new Uint16Array(pako$7.inflate(deflatedData.positions).buffer), + normals: new Int8Array(pako$7.inflate(deflatedData.normals).buffer), + indices: new Uint32Array(pako$7.inflate(deflatedData.indices).buffer), + edgeIndices: new Uint32Array(pako$7.inflate(deflatedData.edgeIndices).buffer), + meshPositions: new Uint32Array(pako$7.inflate(deflatedData.meshPositions).buffer), + meshIndices: new Uint32Array(pako$7.inflate(deflatedData.meshIndices).buffer), + meshEdgesIndices: new Uint32Array(pako$7.inflate(deflatedData.meshEdgesIndices).buffer), + meshColors: new Uint8Array(pako$7.inflate(deflatedData.meshColors).buffer), + entityIDs: pako$7.inflate(deflatedData.entityIDs, {to: 'string'}), + entityMeshes: new Uint32Array(pako$7.inflate(deflatedData.entityMeshes).buffer), + entityIsObjects: new Uint8Array(pako$7.inflate(deflatedData.entityIsObjects).buffer), + instancedPositionsDecodeMatrix: new Float32Array(pako$7.inflate(deflatedData.instancedPositionsDecodeMatrix).buffer), + batchedPositionsDecodeMatrix: new Float32Array(pako$7.inflate(deflatedData.batchedPositionsDecodeMatrix).buffer), + entityMeshIds: new Uint32Array(pako$7.inflate(deflatedData.entityMeshIds).buffer), + entityMatrices: new Float32Array(pako$7.inflate(deflatedData.entityMatrices).buffer), + entityUsesInstancing: new Uint8Array(pako$7.inflate(deflatedData.entityUsesInstancing).buffer) + }; +} + +const decompressColor$7 = (function () { + const color2 = new Float32Array(3); + return function (color) { + color2[0] = color[0] / 255.0; + color2[1] = color[1] / 255.0; + color2[2] = color[2] / 255.0; + return color2; + }; +})(); + +function load$7(viewer, options, inflatedData, sceneModel) { + + sceneModel.positionsCompression = "precompressed"; + sceneModel.normalsCompression = "precompressed"; + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + const meshPositions = inflatedData.meshPositions; + const meshIndices = inflatedData.meshIndices; + const meshEdgesIndices = inflatedData.meshEdgesIndices; + const meshColors = inflatedData.meshColors; + const entityIDs = JSON.parse(inflatedData.entityIDs); + const entityMeshes = inflatedData.entityMeshes; + const entityIsObjects = inflatedData.entityIsObjects; + const entityMeshIds = inflatedData.entityMeshIds; + const entityMatrices = inflatedData.entityMatrices; + const entityUsesInstancing = inflatedData.entityUsesInstancing; + + const numMeshes = meshPositions.length; + const numEntities = entityMeshes.length; + + const _alreadyCreatedGeometries = {}; + + for (let i = 0; i < numEntities; i++) { + + const xktEntityId = entityIDs [i]; + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + const entityMatrix = entityMatrices.subarray((i * 16), (i * 16) + 16); + + if (metaObject) { + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; } - if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { - return 10; + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; } - } else { - if (FS.isDir(node.mode)) { - return 31; + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } } - } - return 0; - }, mayOpen: function(node, flags) { - if (!node) { - return 44; - } - if (FS.isLink(node.mode)) { - return 32; - } else if (FS.isDir(node.mode)) { - if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) { - return 31; + } else { + if (options.excludeUnclassifiedObjects) { + continue; } - } - return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); - }, MAX_OPEN_FDS: 4096, nextfd: function(fd_start, fd_end) { - fd_start = fd_start || 0; - fd_end = fd_end || FS.MAX_OPEN_FDS; - for (var fd = fd_start; fd <= fd_end; fd++) { - if (!FS.streams[fd]) { - return fd; + } + + const lastEntity = (i === numEntities - 1); + + const meshIds = []; + + for (let j = entityMeshes [i], jlen = lastEntity ? entityMeshIds.length : entityMeshes [i + 1]; j < jlen; j++) { + var jj = entityMeshIds [j]; + + const lastMesh = (jj === (numMeshes - 1)); + const meshId = entityId + ".mesh." + jj; + + const color = decompressColor$7(meshColors.subarray((jj * 4), (jj * 4) + 3)); + const opacity = meshColors[(jj * 4) + 3] / 255.0; + + var tmpPositions = positions.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); + var tmpNormals = normals.subarray(meshPositions [jj], lastMesh ? positions.length : meshPositions [jj + 1]); + var tmpIndices = indices.subarray(meshIndices [jj], lastMesh ? indices.length : meshIndices [jj + 1]); + var tmpEdgeIndices = edgeIndices.subarray(meshEdgesIndices [jj], lastMesh ? edgeIndices.length : meshEdgesIndices [jj + 1]); + + if (entityUsesInstancing [i] === 1) { + var geometryId = "geometry." + jj; + + if (!(geometryId in _alreadyCreatedGeometries)) { + + sceneModel.createGeometry({ + id: geometryId, + positionsCompressed: tmpPositions, + normalsCompressed: tmpNormals, + indices: tmpIndices, + edgeIndices: tmpEdgeIndices, + primitive: "triangles", + positionsDecodeMatrix: inflatedData.instancedPositionsDecodeMatrix + }); + + _alreadyCreatedGeometries [geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + color: color, + opacity: opacity, + matrix: entityMatrix, + geometryId: geometryId, + })); + + meshIds.push(meshId); + + } else { + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + primitive: "triangles", + positionsCompressed: tmpPositions, + normalsCompressed: tmpNormals, + indices: tmpIndices, + edgeIndices: tmpEdgeIndices, + positionsDecodeMatrix: inflatedData.batchedPositionsDecodeMatrix, + color: color, + opacity: opacity + })); + + meshIds.push(meshId); } - } - throw new FS.ErrnoError(33); - }, getStream: function(fd) { - return FS.streams[fd]; - }, createStream: function(stream, fd_start, fd_end) { - if (!FS.FSStream) { - FS.FSStream = function() { - }; - FS.FSStream.prototype = { object: { get: function() { - return this.node; - }, set: function(val) { - this.node = val; - } }, isRead: { get: function() { - return (this.flags & 2097155) !== 1; - } }, isWrite: { get: function() { - return (this.flags & 2097155) !== 0; - } }, isAppend: { get: function() { - return this.flags & 1024; - } } }; - } - var newStream = new FS.FSStream(); - for (var p in stream) { - newStream[p] = stream[p]; - } - stream = newStream; - var fd = FS.nextfd(fd_start, fd_end); - stream.fd = fd; - FS.streams[fd] = stream; - return stream; - }, closeStream: function(fd) { - FS.streams[fd] = null; - }, chrdev_stream_ops: { open: function(stream) { - var device = FS.getDevice(stream.node.rdev); - stream.stream_ops = device.stream_ops; - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - }, llseek: function() { - throw new FS.ErrnoError(70); - } }, major: function(dev) { - return dev >> 8; - }, minor: function(dev) { - return dev & 255; - }, makedev: function(ma, mi) { - return ma << 8 | mi; - }, registerDevice: function(dev, ops) { - FS.devices[dev] = { stream_ops: ops }; - }, getDevice: function(dev) { - return FS.devices[dev]; - }, getMounts: function(mount) { - var mounts = []; - var check = [mount]; - while (check.length) { - var m = check.pop(); - mounts.push(m); - check.push.apply(check, m.mounts); - } - return mounts; - }, syncfs: function(populate, callback) { - if (typeof populate === "function") { - callback = populate; - populate = false; - } - FS.syncFSRequests++; - if (FS.syncFSRequests > 1) { - err("warning: " + FS.syncFSRequests + " FS.syncfs operations in flight at once, probably just doing extra work"); - } - var mounts = FS.getMounts(FS.root.mount); - var completed = 0; - function doCallback(errCode) { - FS.syncFSRequests--; - return callback(errCode); - } - function done(errCode) { - if (errCode) { - if (!done.errored) { - done.errored = true; - return doCallback(errCode); - } - return; - } - if (++completed >= mounts.length) { - doCallback(null); - } - } - mounts.forEach(function(mount) { - if (!mount.type.syncfs) { - return done(null); + } + + if (meshIds.length) { + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: (entityIsObjects [i] === 1), + meshIds: meshIds + })); + } + } +} + +/** @private */ +const ParserV3 = { + version: 3, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$7(elements); + const inflatedData = inflate$7(deflatedData); + load$7(viewer, options, inflatedData, sceneModel); + } +}; + +/* + +Parser for .XKT Format V4 + +.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + + */ + +let pako$6 = window.pako || p; +if (!pako$6.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$6 = pako$6.default; +} + +function extract$6(elements) { + return { + positions: elements[0], + normals: elements[1], + indices: elements[2], + edgeIndices: elements[3], + decodeMatrices: elements[4], + matrices: elements[5], + eachPrimitivePositionsAndNormalsPortion: elements[6], + eachPrimitiveIndicesPortion: elements[7], + eachPrimitiveEdgeIndicesPortion: elements[8], + eachPrimitiveDecodeMatricesPortion: elements[9], + eachPrimitiveColor: elements[10], + primitiveInstances: elements[11], + eachEntityId: elements[12], + eachEntityPrimitiveInstancesPortion: elements[13], + eachEntityMatricesPortion: elements[14], + eachEntityMatrix: elements[15] + }; +} + +function inflate$6(deflatedData) { + return { + positions: new Uint16Array(pako$6.inflate(deflatedData.positions).buffer), + normals: new Int8Array(pako$6.inflate(deflatedData.normals).buffer), + indices: new Uint32Array(pako$6.inflate(deflatedData.indices).buffer), + edgeIndices: new Uint32Array(pako$6.inflate(deflatedData.edgeIndices).buffer), + decodeMatrices: new Float32Array(pako$6.inflate(deflatedData.decodeMatrices).buffer), + matrices: new Float32Array(pako$6.inflate(deflatedData.matrices).buffer), + eachPrimitivePositionsAndNormalsPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitivePositionsAndNormalsPortion).buffer), + eachPrimitiveIndicesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitiveIndicesPortion).buffer), + eachPrimitiveEdgeIndicesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitiveEdgeIndicesPortion).buffer), + eachPrimitiveDecodeMatricesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachPrimitiveDecodeMatricesPortion).buffer), + eachPrimitiveColor: new Uint8Array(pako$6.inflate(deflatedData.eachPrimitiveColor).buffer), + primitiveInstances: new Uint32Array(pako$6.inflate(deflatedData.primitiveInstances).buffer), + eachEntityId: pako$6.inflate(deflatedData.eachEntityId, {to: 'string'}), + eachEntityPrimitiveInstancesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachEntityPrimitiveInstancesPortion).buffer), + eachEntityMatricesPortion: new Uint32Array(pako$6.inflate(deflatedData.eachEntityMatricesPortion).buffer) + }; +} + +const decompressColor$6 = (function () { + const color2 = new Float32Array(3); + return function (color) { + color2[0] = color[0] / 255.0; + color2[1] = color[1] / 255.0; + color2[2] = color[2] / 255.0; + return color2; + }; +})(); + +function load$6(viewer, options, inflatedData, sceneModel) { + + sceneModel.positionsCompression = "precompressed"; + sceneModel.normalsCompression = "precompressed"; + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + const decodeMatrices = inflatedData.decodeMatrices; + const matrices = inflatedData.matrices; + + const eachPrimitivePositionsAndNormalsPortion = inflatedData.eachPrimitivePositionsAndNormalsPortion; + const eachPrimitiveIndicesPortion = inflatedData.eachPrimitiveIndicesPortion; + const eachPrimitiveEdgeIndicesPortion = inflatedData.eachPrimitiveEdgeIndicesPortion; + const eachPrimitiveDecodeMatricesPortion = inflatedData.eachPrimitiveDecodeMatricesPortion; + const eachPrimitiveColor = inflatedData.eachPrimitiveColor; + + const primitiveInstances = inflatedData.primitiveInstances; + + const eachEntityId = JSON.parse(inflatedData.eachEntityId); + const eachEntityPrimitiveInstancesPortion = inflatedData.eachEntityPrimitiveInstancesPortion; + const eachEntityMatricesPortion = inflatedData.eachEntityMatricesPortion; + + const numPrimitives = eachPrimitivePositionsAndNormalsPortion.length; + const numPrimitiveInstances = primitiveInstances.length; + const primitiveInstanceCounts = new Uint8Array(numPrimitives); // For each mesh, how many times it is instanced + const orderedPrimitiveIndexes = new Uint32Array(numPrimitives); // For each mesh, its index sorted into runs that share the same decode matrix + + const numEntities = eachEntityId.length; + + // Get lookup that orders primitives into runs that share the same decode matrices; + // this is used to create meshes in batches that use the same decode matrix + + for (let primitiveIndex = 0; primitiveIndex < numPrimitives; primitiveIndex++) { + orderedPrimitiveIndexes[primitiveIndex] = primitiveIndex; + } + + orderedPrimitiveIndexes.sort((i1, i2) => { + if (eachPrimitiveDecodeMatricesPortion[i1] < eachPrimitiveDecodeMatricesPortion[i2]) { + return -1; + } + if (eachPrimitiveDecodeMatricesPortion[i1] > eachPrimitiveDecodeMatricesPortion[i2]) { + return 1; + } + return 0; + }); + + // Count instances of each primitive + + for (let primitiveInstanceIndex = 0; primitiveInstanceIndex < numPrimitiveInstances; primitiveInstanceIndex++) { + const primitiveIndex = primitiveInstances[primitiveInstanceIndex]; + primitiveInstanceCounts[primitiveIndex]++; + } + + // Map batched primitives to the entities that will use them + + const batchedPrimitiveEntityIndexes = {}; + + for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + + const lastEntityIndex = (numEntities - 1); + const atLastEntity = (entityIndex === lastEntityIndex); + const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; + const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + + for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + + const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; + const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; + const isInstancedPrimitive = (primitiveInstanceCount > 1); + + if (!isInstancedPrimitive) { + batchedPrimitiveEntityIndexes[primitiveIndex] = entityIndex; } - mount.type.syncfs(mount, populate, done); - }); - }, mount: function(type, opts, mountpoint) { - var root = mountpoint === "/"; - var pseudo = !mountpoint; - var node; - if (root && FS.root) { - throw new FS.ErrnoError(10); - } else if (!root && !pseudo) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - mountpoint = lookup.path; - node = lookup.node; - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); + } + } + + // Create 1) geometries for instanced primitives, and 2) meshes for batched primitives. We create all the + // batched meshes now, before we create entities, because we're creating the batched meshes in runs that share + // the same decode matrices. Each run of meshes with the same decode matrix will end up in the same + // BatchingLayer; the VBOSceneModel#createMesh() method starts a new BatchingLayer each time the decode + // matrix has changed since the last invocation of that method, hence why we need to order batched meshes + // in runs like this. + + for (let primitiveIndex = 0; primitiveIndex < numPrimitives; primitiveIndex++) { + + const orderedPrimitiveIndex = orderedPrimitiveIndexes[primitiveIndex]; + + const atLastPrimitive = (orderedPrimitiveIndex === (numPrimitives - 1)); + + const primitiveInstanceCount = primitiveInstanceCounts[orderedPrimitiveIndex]; + const isInstancedPrimitive = (primitiveInstanceCount > 1); + + const color = decompressColor$6(eachPrimitiveColor.subarray((orderedPrimitiveIndex * 4), (orderedPrimitiveIndex * 4) + 3)); + const opacity = eachPrimitiveColor[(orderedPrimitiveIndex * 4) + 3] / 255.0; + + const primitivePositions = positions.subarray(eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex], atLastPrimitive ? positions.length : eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex + 1]); + const primitiveNormals = normals.subarray(eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex], atLastPrimitive ? normals.length : eachPrimitivePositionsAndNormalsPortion [orderedPrimitiveIndex + 1]); + const primitiveIndices = indices.subarray(eachPrimitiveIndicesPortion [orderedPrimitiveIndex], atLastPrimitive ? indices.length : eachPrimitiveIndicesPortion [orderedPrimitiveIndex + 1]); + const primitiveEdgeIndices = edgeIndices.subarray(eachPrimitiveEdgeIndicesPortion [orderedPrimitiveIndex], atLastPrimitive ? edgeIndices.length : eachPrimitiveEdgeIndicesPortion [orderedPrimitiveIndex + 1]); + const primitiveDecodeMatrix = decodeMatrices.subarray(eachPrimitiveDecodeMatricesPortion [orderedPrimitiveIndex], eachPrimitiveDecodeMatricesPortion [orderedPrimitiveIndex] + 16); + + if (isInstancedPrimitive) { + + // Primitive instanced by more than one entity, and has positions in Model-space + + var geometryId = "geometry" + orderedPrimitiveIndex; // These IDs are local to the VBOSceneModel + + sceneModel.createGeometry({ + id: geometryId, + primitive: "triangles", + positionsCompressed: primitivePositions, + normalsCompressed: primitiveNormals, + indices: primitiveIndices, + edgeIndices: primitiveEdgeIndices, + positionsDecodeMatrix: primitiveDecodeMatrix + }); + + } else { + + // Primitive is used only by one entity, and has positions pre-transformed into World-space + + const meshId = orderedPrimitiveIndex; // These IDs are local to the VBOSceneModel + + const entityIndex = batchedPrimitiveEntityIndexes[orderedPrimitiveIndex]; + eachEntityId[entityIndex]; + + const meshDefaults = {}; // TODO: get from lookup from entity IDs + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + primitive: "triangles", + positionsCompressed: primitivePositions, + normalsCompressed: primitiveNormals, + indices: primitiveIndices, + edgeIndices: primitiveEdgeIndices, + positionsDecodeMatrix: primitiveDecodeMatrix, + color: color, + opacity: opacity + })); + } + } + + let countInstances = 0; + + for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + + const lastEntityIndex = (numEntities - 1); + const atLastEntity = (entityIndex === lastEntityIndex); + const entityId = eachEntityId[entityIndex]; + const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; + const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + + const meshIds = []; + + for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + + const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; + const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; + const isInstancedPrimitive = (primitiveInstanceCount > 1); + + if (isInstancedPrimitive) { + + const meshDefaults = {}; // TODO: get from lookup from entity IDs + + const meshId = "instance." + countInstances++; + const geometryId = "geometry" + primitiveIndex; + const matricesIndex = (eachEntityMatricesPortion [entityIndex]) * 16; + const matrix = matrices.subarray(matricesIndex, matricesIndex + 16); + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + matrix: matrix + })); + + meshIds.push(meshId); + + } else { + meshIds.push(primitiveIndex); } - if (!FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); + } + + if (meshIds.length > 0) { + + const entityDefaults = {}; // TODO: get from lookup from entity IDs + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, ///////////////// TODO: If metaobject exists + meshIds: meshIds + })); + } + } +} + +/** @private */ +const ParserV4 = { + version: 4, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$6(elements); + const inflatedData = inflate$6(deflatedData); + load$6(viewer, options, inflatedData, sceneModel); + } +}; + +/* + + Parser for .XKT Format V5 + +.XKT specifications: https://github.com/xeokit/xeokit-sdk/wiki/XKT-Format + + */ + +let pako$5 = window.pako || p; +if (!pako$5.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$5 = pako$5.default; +} + +function extract$5(elements) { + return { + positions: elements[0], + normals: elements[1], + indices: elements[2], + edgeIndices: elements[3], + matrices: elements[4], + eachPrimitivePositionsAndNormalsPortion: elements[5], + eachPrimitiveIndicesPortion: elements[6], + eachPrimitiveEdgeIndicesPortion: elements[7], + eachPrimitiveColor: elements[8], + primitiveInstances: elements[9], + eachEntityId: elements[10], + eachEntityPrimitiveInstancesPortion: elements[11], + eachEntityMatricesPortion: elements[12] + }; +} + +function inflate$5(deflatedData) { + return { + positions: new Float32Array(pako$5.inflate(deflatedData.positions).buffer), + normals: new Int8Array(pako$5.inflate(deflatedData.normals).buffer), + indices: new Uint32Array(pako$5.inflate(deflatedData.indices).buffer), + edgeIndices: new Uint32Array(pako$5.inflate(deflatedData.edgeIndices).buffer), + matrices: new Float32Array(pako$5.inflate(deflatedData.matrices).buffer), + eachPrimitivePositionsAndNormalsPortion: new Uint32Array(pako$5.inflate(deflatedData.eachPrimitivePositionsAndNormalsPortion).buffer), + eachPrimitiveIndicesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachPrimitiveIndicesPortion).buffer), + eachPrimitiveEdgeIndicesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachPrimitiveEdgeIndicesPortion).buffer), + eachPrimitiveColor: new Uint8Array(pako$5.inflate(deflatedData.eachPrimitiveColor).buffer), + primitiveInstances: new Uint32Array(pako$5.inflate(deflatedData.primitiveInstances).buffer), + eachEntityId: pako$5.inflate(deflatedData.eachEntityId, {to: 'string'}), + eachEntityPrimitiveInstancesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachEntityPrimitiveInstancesPortion).buffer), + eachEntityMatricesPortion: new Uint32Array(pako$5.inflate(deflatedData.eachEntityMatricesPortion).buffer) + }; +} + +const decompressColor$5 = (function () { + const color2 = new Float32Array(3); + return function (color) { + color2[0] = color[0] / 255.0; + color2[1] = color[1] / 255.0; + color2[2] = color[2] / 255.0; + return color2; + }; +})(); + +function load$5(viewer, options, inflatedData, sceneModel) { + + sceneModel.positionsCompression = "disabled"; // Positions in XKT V4 are floats, which we never quantize, for precision with big models + sceneModel.normalsCompression = "precompressed"; // Normals are oct-encoded though + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + const matrices = inflatedData.matrices; + + const eachPrimitivePositionsAndNormalsPortion = inflatedData.eachPrimitivePositionsAndNormalsPortion; + const eachPrimitiveIndicesPortion = inflatedData.eachPrimitiveIndicesPortion; + const eachPrimitiveEdgeIndicesPortion = inflatedData.eachPrimitiveEdgeIndicesPortion; + const eachPrimitiveColor = inflatedData.eachPrimitiveColor; + + const primitiveInstances = inflatedData.primitiveInstances; + + const eachEntityId = JSON.parse(inflatedData.eachEntityId); + const eachEntityPrimitiveInstancesPortion = inflatedData.eachEntityPrimitiveInstancesPortion; + const eachEntityMatricesPortion = inflatedData.eachEntityMatricesPortion; + + const numPrimitives = eachPrimitivePositionsAndNormalsPortion.length; + const numPrimitiveInstances = primitiveInstances.length; + const primitiveInstanceCounts = new Uint8Array(numPrimitives); // For each mesh, how many times it is instanced + + const numEntities = eachEntityId.length; + + // Count instances of each primitive + + for (let primitiveInstanceIndex = 0; primitiveInstanceIndex < numPrimitiveInstances; primitiveInstanceIndex++) { + const primitiveIndex = primitiveInstances[primitiveInstanceIndex]; + primitiveInstanceCounts[primitiveIndex]++; + } + + // Map batched primitives to the entities that will use them + + const batchedPrimitiveEntityIndexes = {}; + + for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + + const lastEntityIndex = (numEntities - 1); + const atLastEntity = (entityIndex === lastEntityIndex); + const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; + const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + + for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + + const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; + const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; + const isInstancedPrimitive = (primitiveInstanceCount > 1); + + if (!isInstancedPrimitive) { + batchedPrimitiveEntityIndexes[primitiveIndex] = entityIndex; } - } - var mount = { type, opts, mountpoint, mounts: [] }; - var mountRoot = type.mount(mount); - mountRoot.mount = mount; - mount.root = mountRoot; - if (root) { - FS.root = mountRoot; - } else if (node) { - node.mounted = mount; - if (node.mount) { - node.mount.mounts.push(mount); + } + } + + // Create geometries for instanced primitives and meshes for batched primitives. + + for (let primitiveIndex = 0; primitiveIndex < numPrimitives; primitiveIndex++) { + + const atLastPrimitive = (primitiveIndex === (numPrimitives - 1)); + + const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; + const isInstancedPrimitive = (primitiveInstanceCount > 1); + + const color = decompressColor$5(eachPrimitiveColor.subarray((primitiveIndex * 4), (primitiveIndex * 4) + 3)); + const opacity = eachPrimitiveColor[(primitiveIndex * 4) + 3] / 255.0; + + const primitivePositions = positions.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? positions.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); + const primitiveNormals = normals.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? normals.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); + const primitiveIndices = indices.subarray(eachPrimitiveIndicesPortion [primitiveIndex], atLastPrimitive ? indices.length : eachPrimitiveIndicesPortion [primitiveIndex + 1]); + const primitiveEdgeIndices = edgeIndices.subarray(eachPrimitiveEdgeIndicesPortion [primitiveIndex], atLastPrimitive ? edgeIndices.length : eachPrimitiveEdgeIndicesPortion [primitiveIndex + 1]); + + if (isInstancedPrimitive) { + + // Primitive instanced by more than one entity, and has positions in Model-space + + var geometryId = "geometry" + primitiveIndex; // These IDs are local to the VBOSceneModel + + sceneModel.createGeometry({ + id: geometryId, + primitive: "triangles", + positionsCompressed: primitivePositions, + normalsCompressed: primitiveNormals, + indices: primitiveIndices, + edgeIndices: primitiveEdgeIndices + }); + + } else { + + // Primitive is used only by one entity, and has positions pre-transformed into World-space + + const meshId = primitiveIndex; // These IDs are local to the VBOSceneModel + + const entityIndex = batchedPrimitiveEntityIndexes[primitiveIndex]; + eachEntityId[entityIndex]; + + const meshDefaults = {}; // TODO: get from lookup from entity IDs + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + primitive: "triangles", + positionsCompressed: primitivePositions, + normalsCompressed: primitiveNormals, + indices: primitiveIndices, + edgeIndices: primitiveEdgeIndices, + color: color, + opacity: opacity + })); + } + } + + let countInstances = 0; + + for (let entityIndex = 0; entityIndex < numEntities; entityIndex++) { + + const lastEntityIndex = (numEntities - 1); + const atLastEntity = (entityIndex === lastEntityIndex); + const entityId = eachEntityId[entityIndex]; + const firstEntityPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [entityIndex]; + const lastEntityPrimitiveInstanceIndex = atLastEntity ? eachEntityPrimitiveInstancesPortion[lastEntityIndex] : eachEntityPrimitiveInstancesPortion[entityIndex + 1]; + + const meshIds = []; + + for (let primitiveInstancesIndex = firstEntityPrimitiveInstanceIndex; primitiveInstancesIndex < lastEntityPrimitiveInstanceIndex; primitiveInstancesIndex++) { + + const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; + const primitiveInstanceCount = primitiveInstanceCounts[primitiveIndex]; + const isInstancedPrimitive = (primitiveInstanceCount > 1); + + if (isInstancedPrimitive) { + + const meshDefaults = {}; // TODO: get from lookup from entity IDs + + const meshId = "instance." + countInstances++; + const geometryId = "geometry" + primitiveIndex; + const matricesIndex = (eachEntityMatricesPortion [entityIndex]) * 16; + const matrix = matrices.subarray(matricesIndex, matricesIndex + 16); + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + matrix: matrix + })); + + meshIds.push(meshId); + + } else { + meshIds.push(primitiveIndex); } - } - return mountRoot; - }, unmount: function(mountpoint) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - if (!FS.isMountpoint(lookup.node)) { - throw new FS.ErrnoError(28); - } - var node = lookup.node; - var mount = node.mounted; - var mounts = FS.getMounts(mount); - Object.keys(FS.nameTable).forEach(function(hash) { - var current = FS.nameTable[hash]; - while (current) { - var next = current.name_next; - if (mounts.indexOf(current.mount) !== -1) { - FS.destroyNode(current); - } - current = next; + } + + if (meshIds.length > 0) { + + const entityDefaults = {}; // TODO: get from lookup from entity IDs + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, ///////////////// TODO: If metaobject exists + meshIds: meshIds + })); + } + } +} + +/** @private */ +const ParserV5 = { + version: 5, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$5(elements); + const inflatedData = inflate$5(deflatedData); + load$5(viewer, options, inflatedData, sceneModel); + } +}; + +/* + + Parser for .XKT Format V6 + + */ + +let pako$4 = window.pako || p; +if (!pako$4.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$4 = pako$4.default; +} + +function extract$4(elements) { + + return { + positions: elements[0], + normals: elements[1], + indices: elements[2], + edgeIndices: elements[3], + matrices: elements[4], + reusedPrimitivesDecodeMatrix: elements[5], + eachPrimitivePositionsAndNormalsPortion: elements[6], + eachPrimitiveIndicesPortion: elements[7], + eachPrimitiveEdgeIndicesPortion: elements[8], + eachPrimitiveColorAndOpacity: elements[9], + primitiveInstances: elements[10], + eachEntityId: elements[11], + eachEntityPrimitiveInstancesPortion: elements[12], + eachEntityMatricesPortion: elements[13], + eachTileAABB: elements[14], + eachTileEntitiesPortion: elements[15] + }; +} + +function inflate$4(deflatedData) { + + function inflate(array, options) { + return (array.length === 0) ? [] : pako$4.inflate(array, options).buffer; + } + + return { + positions: new Uint16Array(inflate(deflatedData.positions)), + normals: new Int8Array(inflate(deflatedData.normals)), + indices: new Uint32Array(inflate(deflatedData.indices)), + edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + matrices: new Float32Array(inflate(deflatedData.matrices)), + reusedPrimitivesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedPrimitivesDecodeMatrix)), + eachPrimitivePositionsAndNormalsPortion: new Uint32Array(inflate(deflatedData.eachPrimitivePositionsAndNormalsPortion)), + eachPrimitiveIndicesPortion: new Uint32Array(inflate(deflatedData.eachPrimitiveIndicesPortion)), + eachPrimitiveEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachPrimitiveEdgeIndicesPortion)), + eachPrimitiveColorAndOpacity: new Uint8Array(inflate(deflatedData.eachPrimitiveColorAndOpacity)), + primitiveInstances: new Uint32Array(inflate(deflatedData.primitiveInstances)), + eachEntityId: pako$4.inflate(deflatedData.eachEntityId, {to: 'string'}), + eachEntityPrimitiveInstancesPortion: new Uint32Array(inflate(deflatedData.eachEntityPrimitiveInstancesPortion)), + eachEntityMatricesPortion: new Uint32Array(inflate(deflatedData.eachEntityMatricesPortion)), + eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), + eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)) + }; +} + +const decompressColor$4 = (function () { + const floatColor = new Float32Array(3); + return function (intColor) { + floatColor[0] = intColor[0] / 255.0; + floatColor[1] = intColor[1] / 255.0; + floatColor[2] = intColor[2] / 255.0; + return floatColor; + }; +})(); + +function load$4(viewer, options, inflatedData, sceneModel) { + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + + const matrices = inflatedData.matrices; + + const reusedPrimitivesDecodeMatrix = inflatedData.reusedPrimitivesDecodeMatrix; + + const eachPrimitivePositionsAndNormalsPortion = inflatedData.eachPrimitivePositionsAndNormalsPortion; + const eachPrimitiveIndicesPortion = inflatedData.eachPrimitiveIndicesPortion; + const eachPrimitiveEdgeIndicesPortion = inflatedData.eachPrimitiveEdgeIndicesPortion; + const eachPrimitiveColorAndOpacity = inflatedData.eachPrimitiveColorAndOpacity; + + const primitiveInstances = inflatedData.primitiveInstances; + + const eachEntityId = JSON.parse(inflatedData.eachEntityId); + const eachEntityPrimitiveInstancesPortion = inflatedData.eachEntityPrimitiveInstancesPortion; + const eachEntityMatricesPortion = inflatedData.eachEntityMatricesPortion; + + const eachTileAABB = inflatedData.eachTileAABB; + const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + + const numPrimitives = eachPrimitivePositionsAndNormalsPortion.length; + const numPrimitiveInstances = primitiveInstances.length; + const numEntities = eachEntityId.length; + const numTiles = eachTileEntitiesPortion.length; + + let nextMeshId = 0; + + // Count instances of each primitive + + const primitiveReuseCounts = new Uint32Array(numPrimitives); + + for (let primitiveInstanceIndex = 0; primitiveInstanceIndex < numPrimitiveInstances; primitiveInstanceIndex++) { + const primitiveIndex = primitiveInstances[primitiveInstanceIndex]; + if (primitiveReuseCounts[primitiveIndex] !== undefined) { + primitiveReuseCounts[primitiveIndex]++; + } else { + primitiveReuseCounts[primitiveIndex] = 1; + } + } + + // Iterate over tiles + + const tileCenter = math.vec3(); + const rtcAABB = math.AABB3(); + + for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + + const lastTileIndex = (numTiles - 1); + + const atLastTile = (tileIndex === lastTileIndex); + + const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; + const lastTileEntityIndex = atLastTile ? numEntities : eachTileEntitiesPortion[tileIndex + 1]; + + const tileAABBIndex = tileIndex * 6; + const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + + math.getAABB3Center(tileAABB, tileCenter); + + rtcAABB[0] = tileAABB[0] - tileCenter[0]; + rtcAABB[1] = tileAABB[1] - tileCenter[1]; + rtcAABB[2] = tileAABB[2] - tileCenter[2]; + rtcAABB[3] = tileAABB[3] - tileCenter[0]; + rtcAABB[4] = tileAABB[4] - tileCenter[1]; + rtcAABB[5] = tileAABB[5] - tileCenter[2]; + + const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + + const geometryCreated = {}; + + // Iterate over each tile's entities + + for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex < lastTileEntityIndex; tileEntityIndex++) { + + const xktEntityId = eachEntityId[tileEntityIndex]; + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + + const entityMatrixIndex = eachEntityMatricesPortion[tileEntityIndex]; + const entityMatrix = matrices.slice(entityMatrixIndex, entityMatrixIndex + 16); + + const lastTileEntityIndex = (numEntities - 1); + const atLastTileEntity = (tileEntityIndex === lastTileEntityIndex); + const firstPrimitiveInstanceIndex = eachEntityPrimitiveInstancesPortion [tileEntityIndex]; + const lastPrimitiveInstanceIndex = atLastTileEntity ? primitiveInstances.length : eachEntityPrimitiveInstancesPortion[tileEntityIndex + 1]; + + const meshIds = []; + + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + + if (metaObject) { + + // Mask loading of object types + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; + } + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; + } + + // Get initial property values for object types + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } + } + + } else { + if (options.excludeUnclassifiedObjects) { + continue; + } } - }); - node.mounted = null; - var idx = node.mount.mounts.indexOf(mount); - node.mount.mounts.splice(idx, 1); - }, lookup: function(parent, name2) { - return parent.node_ops.lookup(parent, name2); - }, mknod: function(path, mode, dev) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name2 = PATH.basename(path); - if (!name2 || name2 === "." || name2 === "..") { - throw new FS.ErrnoError(28); - } - var errCode = FS.mayCreate(parent, name2); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.mknod) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.mknod(parent, name2, mode, dev); - }, create: function(path, mode) { - mode = mode !== void 0 ? mode : 438; - mode &= 4095; - mode |= 32768; - return FS.mknod(path, mode, 0); - }, mkdir: function(path, mode) { - mode = mode !== void 0 ? mode : 511; - mode &= 511 | 512; - mode |= 16384; - return FS.mknod(path, mode, 0); - }, mkdirTree: function(path, mode) { - var dirs = path.split("/"); - var d = ""; - for (var i = 0; i < dirs.length; ++i) { - if (!dirs[i]) - continue; - d += "/" + dirs[i]; - try { - FS.mkdir(d, mode); - } catch (e) { - if (e.errno != 20) - throw e; + + // Iterate each entity's primitive instances + + for (let primitiveInstancesIndex = firstPrimitiveInstanceIndex; primitiveInstancesIndex < lastPrimitiveInstanceIndex; primitiveInstancesIndex++) { + + const primitiveIndex = primitiveInstances[primitiveInstancesIndex]; + const primitiveReuseCount = primitiveReuseCounts[primitiveIndex]; + const isReusedPrimitive = (primitiveReuseCount > 1); + + const atLastPrimitive = (primitiveIndex === (numPrimitives - 1)); + + const primitivePositions = positions.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? positions.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); + const primitiveNormals = normals.subarray(eachPrimitivePositionsAndNormalsPortion [primitiveIndex], atLastPrimitive ? normals.length : eachPrimitivePositionsAndNormalsPortion [primitiveIndex + 1]); + const primitiveIndices = indices.subarray(eachPrimitiveIndicesPortion [primitiveIndex], atLastPrimitive ? indices.length : eachPrimitiveIndicesPortion [primitiveIndex + 1]); + const primitiveEdgeIndices = edgeIndices.subarray(eachPrimitiveEdgeIndicesPortion [primitiveIndex], atLastPrimitive ? edgeIndices.length : eachPrimitiveEdgeIndicesPortion [primitiveIndex + 1]); + + const color = decompressColor$4(eachPrimitiveColorAndOpacity.subarray((primitiveIndex * 4), (primitiveIndex * 4) + 3)); + const opacity = eachPrimitiveColorAndOpacity[(primitiveIndex * 4) + 3] / 255.0; + + const meshId = nextMeshId++; + + if (isReusedPrimitive) { + + // Create mesh for multi-use primitive - create (or reuse) geometry, create mesh using that geometry + + const geometryId = "geometry." + tileIndex + "." + primitiveIndex; // These IDs are local to the VBOSceneModel + + if (!geometryCreated[geometryId]) { + + sceneModel.createGeometry({ + id: geometryId, + primitive: "triangles", + positionsCompressed: primitivePositions, + normalsCompressed: primitiveNormals, + indices: primitiveIndices, + edgeIndices: primitiveEdgeIndices, + positionsDecodeMatrix: reusedPrimitivesDecodeMatrix + }); + + geometryCreated[geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + origin: tileCenter, + matrix: entityMatrix, + color: color, + opacity: opacity + })); + + meshIds.push(meshId); + + } else { + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + origin: tileCenter, + primitive: "triangles", + positionsCompressed: primitivePositions, + normalsCompressed: primitiveNormals, + indices: primitiveIndices, + edgeIndices: primitiveEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: color, + opacity: opacity + })); + + meshIds.push(meshId); + } } - } - }, mkdev: function(path, mode, dev) { - if (typeof dev === "undefined") { - dev = mode; - mode = 438; - } - mode |= 8192; - return FS.mknod(path, mode, dev); - }, symlink: function(oldpath, newpath) { - if (!PATH_FS.resolve(oldpath)) { - throw new FS.ErrnoError(44); - } - var lookup = FS.lookupPath(newpath, { parent: true }); - var parent = lookup.node; - if (!parent) { - throw new FS.ErrnoError(44); - } - var newname = PATH.basename(newpath); - var errCode = FS.mayCreate(parent, newname); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.symlink) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.symlink(parent, newname, oldpath); - }, rename: function(old_path, new_path) { - var old_dirname = PATH.dirname(old_path); - var new_dirname = PATH.dirname(new_path); - var old_name = PATH.basename(old_path); - var new_name = PATH.basename(new_path); - var lookup, old_dir, new_dir; - lookup = FS.lookupPath(old_path, { parent: true }); - old_dir = lookup.node; - lookup = FS.lookupPath(new_path, { parent: true }); - new_dir = lookup.node; - if (!old_dir || !new_dir) - throw new FS.ErrnoError(44); - if (old_dir.mount !== new_dir.mount) { - throw new FS.ErrnoError(75); - } - var old_node = FS.lookupNode(old_dir, old_name); - var relative = PATH_FS.relative(old_path, new_dirname); - if (relative.charAt(0) !== ".") { - throw new FS.ErrnoError(28); - } - relative = PATH_FS.relative(new_path, old_dirname); - if (relative.charAt(0) !== ".") { - throw new FS.ErrnoError(55); - } - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) { - } - if (old_node === new_node) { - return; - } - var isdir = FS.isDir(old_node.mode); - var errCode = FS.mayDelete(old_dir, old_name, isdir); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!old_dir.node_ops.rename) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(old_node) || new_node && FS.isMountpoint(new_node)) { - throw new FS.ErrnoError(10); - } - if (new_dir !== old_dir) { - errCode = FS.nodePermissions(old_dir, "w"); - if (errCode) { - throw new FS.ErrnoError(errCode); + + if (meshIds.length > 0) { + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, + meshIds: meshIds + })); } - } - try { - if (FS.trackingDelegate["willMovePath"]) { - FS.trackingDelegate["willMovePath"](old_path, new_path); - } - } catch (e) { - err("FS.trackingDelegate['willMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message); - } - FS.hashRemoveNode(old_node); - try { - old_dir.node_ops.rename(old_node, new_dir, new_name); - } catch (e) { - throw e; - } finally { - FS.hashAddNode(old_node); - } - try { - if (FS.trackingDelegate["onMovePath"]) - FS.trackingDelegate["onMovePath"](old_path, new_path); - } catch (e) { - err("FS.trackingDelegate['onMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message); - } - }, rmdir: function(path) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name2 = PATH.basename(path); - var node = FS.lookupNode(parent, name2); - var errCode = FS.mayDelete(parent, name2, true); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.rmdir) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - try { - if (FS.trackingDelegate["willDeletePath"]) { - FS.trackingDelegate["willDeletePath"](path); - } - } catch (e) { - err("FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message); - } - parent.node_ops.rmdir(parent, name2); - FS.destroyNode(node); - try { - if (FS.trackingDelegate["onDeletePath"]) - FS.trackingDelegate["onDeletePath"](path); - } catch (e) { - err("FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message); - } - }, readdir: function(path) { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - if (!node.node_ops.readdir) { - throw new FS.ErrnoError(54); - } - return node.node_ops.readdir(node); - }, unlink: function(path) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name2 = PATH.basename(path); - var node = FS.lookupNode(parent, name2); - var errCode = FS.mayDelete(parent, name2, false); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.unlink) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - try { - if (FS.trackingDelegate["willDeletePath"]) { - FS.trackingDelegate["willDeletePath"](path); - } - } catch (e) { - err("FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message); - } - parent.node_ops.unlink(parent, name2); - FS.destroyNode(node); - try { - if (FS.trackingDelegate["onDeletePath"]) - FS.trackingDelegate["onDeletePath"](path); - } catch (e) { - err("FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message); - } - }, readlink: function(path) { - var lookup = FS.lookupPath(path); - var link = lookup.node; - if (!link) { - throw new FS.ErrnoError(44); - } - if (!link.node_ops.readlink) { - throw new FS.ErrnoError(28); - } - return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); - }, stat: function(path, dontFollow) { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - var node = lookup.node; - if (!node) { - throw new FS.ErrnoError(44); - } - if (!node.node_ops.getattr) { - throw new FS.ErrnoError(63); - } - return node.node_ops.getattr(node); - }, lstat: function(path) { - return FS.stat(path, true); - }, chmod: function(path, mode, dontFollow) { - var node; - if (typeof path === "string") { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { mode: mode & 4095 | node.mode & ~4095, timestamp: Date.now() }); - }, lchmod: function(path, mode) { - FS.chmod(path, mode, true); - }, fchmod: function(fd, mode) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - FS.chmod(stream.node, mode); - }, chown: function(path, uid, gid, dontFollow) { - var node; - if (typeof path === "string") { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - node.node_ops.setattr(node, { timestamp: Date.now() }); - }, lchown: function(path, uid, gid) { - FS.chown(path, uid, gid, true); - }, fchown: function(fd, uid, gid) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - FS.chown(stream.node, uid, gid); - }, truncate: function(path, len) { - if (len < 0) { - throw new FS.ErrnoError(28); - } - var node; - if (typeof path === "string") { - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - } else { - node = path; - } - if (!node.node_ops.setattr) { - throw new FS.ErrnoError(63); - } - if (FS.isDir(node.mode)) { - throw new FS.ErrnoError(31); - } - if (!FS.isFile(node.mode)) { - throw new FS.ErrnoError(28); - } - var errCode = FS.nodePermissions(node, "w"); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - node.node_ops.setattr(node, { size: len, timestamp: Date.now() }); - }, ftruncate: function(fd, len) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(28); - } - FS.truncate(stream.node, len); - }, utime: function(path, atime, mtime) { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) }); - }, open: function(path, flags, mode, fd_start, fd_end) { - if (path === "") { - throw new FS.ErrnoError(44); - } - flags = typeof flags === "string" ? FS.modeStringToFlags(flags) : flags; - mode = typeof mode === "undefined" ? 438 : mode; - if (flags & 64) { - mode = mode & 4095 | 32768; - } else { - mode = 0; - } - var node; - if (typeof path === "object") { - node = path; - } else { - path = PATH.normalize(path); - try { - var lookup = FS.lookupPath(path, { follow: !(flags & 131072) }); - node = lookup.node; - } catch (e) { - } - } - var created = false; - if (flags & 64) { - if (node) { - if (flags & 128) { - throw new FS.ErrnoError(20); - } + } + } +} + +/** @private */ +const ParserV6 = { + version: 6, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$4(elements); + const inflatedData = inflate$4(deflatedData); + load$4(viewer, options, inflatedData, sceneModel); + } +}; + +/* + + Parser for .XKT Format V7 + + */ + +let pako$3 = window.pako || p; +if (!pako$3.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$3 = pako$3.default; +} + +function extract$3(elements) { + + return { + + // Vertex attributes + + positions: elements[0], + normals: elements[1], + colors: elements[2], + + // Indices + + indices: elements[3], + edgeIndices: elements[4], + + // Transform matrices + + matrices: elements[5], + + reusedGeometriesDecodeMatrix: elements[6], + + // Geometries + + eachGeometryPrimitiveType: elements[7], + eachGeometryPositionsPortion: elements[8], + eachGeometryNormalsPortion: elements[9], + eachGeometryColorsPortion: elements[10], + eachGeometryIndicesPortion: elements[11], + eachGeometryEdgeIndicesPortion: elements[12], + + // Meshes are grouped in runs that are shared by the same entities + + eachMeshGeometriesPortion: elements[13], + eachMeshMatricesPortion: elements[14], + eachMeshMaterial: elements[15], + + // Entity elements in the following arrays are grouped in runs that are shared by the same tiles + + eachEntityId: elements[16], + eachEntityMeshesPortion: elements[17], + + eachTileAABB: elements[18], + eachTileEntitiesPortion: elements[19] + }; +} + +function inflate$3(deflatedData) { + + function inflate(array, options) { + return (array.length === 0) ? [] : pako$3.inflate(array, options).buffer; + } + + return { + positions: new Uint16Array(inflate(deflatedData.positions)), + normals: new Int8Array(inflate(deflatedData.normals)), + colors: new Uint8Array(inflate(deflatedData.colors)), + + indices: new Uint32Array(inflate(deflatedData.indices)), + edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + + matrices: new Float32Array(inflate(deflatedData.matrices)), + + reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + + eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), + eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), + eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), + eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), + eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), + eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + + eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), + eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), + eachMeshMaterial: new Uint8Array(inflate(deflatedData.eachMeshMaterial)), + + eachEntityId: pako$3.inflate(deflatedData.eachEntityId, {to: 'string'}), + eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + + eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), + eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), + }; +} + +const decompressColor$3 = (function () { + const floatColor = new Float32Array(3); + return function (intColor) { + floatColor[0] = intColor[0] / 255.0; + floatColor[1] = intColor[1] / 255.0; + floatColor[2] = intColor[2] / 255.0; + return floatColor; + }; +})(); + +function convertColorsRGBToRGBA$1(colorsRGB) { + const colorsRGBA = []; + for (let i = 0, len = colorsRGB.length; i < len; i+=3) { + colorsRGBA.push(colorsRGB[i]); + colorsRGBA.push(colorsRGB[i+1]); + colorsRGBA.push(colorsRGB[i+2]); + colorsRGBA.push(1.0); + } + return colorsRGBA; +} + +function load$3(viewer, options, inflatedData, sceneModel) { + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const colors = inflatedData.colors; + + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + + const matrices = inflatedData.matrices; + + const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + + const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; + const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; + const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; + const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; + const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; + const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + + const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; + const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; + const eachMeshMaterial = inflatedData.eachMeshMaterial; + + const eachEntityId = JSON.parse(inflatedData.eachEntityId); + const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + + const eachTileAABB = inflatedData.eachTileAABB; + const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + + const numGeometries = eachGeometryPositionsPortion.length; + const numMeshes = eachMeshGeometriesPortion.length; + const numEntities = eachEntityId.length; + const numTiles = eachTileEntitiesPortion.length; + + let nextMeshId = 0; + + // Count instances of each geometry + + const geometryReuseCounts = new Uint32Array(numGeometries); + + for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + if (geometryReuseCounts[geometryIndex] !== undefined) { + geometryReuseCounts[geometryIndex]++; + } else { + geometryReuseCounts[geometryIndex] = 1; + } + } + + // Iterate over tiles + + const tileCenter = math.vec3(); + const rtcAABB = math.AABB3(); + + for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + + const lastTileIndex = (numTiles - 1); + + const atLastTile = (tileIndex === lastTileIndex); + + const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; + const lastTileEntityIndex = atLastTile ? numEntities : eachTileEntitiesPortion[tileIndex + 1]; + + const tileAABBIndex = tileIndex * 6; + const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + + math.getAABB3Center(tileAABB, tileCenter); + + rtcAABB[0] = tileAABB[0] - tileCenter[0]; + rtcAABB[1] = tileAABB[1] - tileCenter[1]; + rtcAABB[2] = tileAABB[2] - tileCenter[2]; + rtcAABB[3] = tileAABB[3] - tileCenter[0]; + rtcAABB[4] = tileAABB[4] - tileCenter[1]; + rtcAABB[5] = tileAABB[5] - tileCenter[2]; + + const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + + const geometryCreated = {}; + + // Iterate over each tile's entities + + for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex < lastTileEntityIndex; tileEntityIndex++) { + + const xktEntityId = eachEntityId[tileEntityIndex]; + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + + const lastTileEntityIndex = (numEntities - 1); + const atLastTileEntity = (tileEntityIndex === lastTileEntityIndex); + const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; + const lastMeshIndex = atLastTileEntity ? eachMeshGeometriesPortion.length : eachEntityMeshesPortion[tileEntityIndex + 1]; + + const meshIds = []; + + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + + if (metaObject) { + + // Mask loading of object types + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; + } + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; + } + + // Get initial property values for object types + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } + if (props.metallic !== undefined && props.metallic !== null) { + meshDefaults.metallic = props.metallic; + } + if (props.roughness !== undefined && props.roughness !== null) { + meshDefaults.roughness = props.roughness; + } + } + } else { - node = FS.mknod(path, mode, 0); - created = true; - } - } - if (!node) { - throw new FS.ErrnoError(44); - } - if (FS.isChrdev(node.mode)) { - flags &= ~512; - } - if (flags & 65536 && !FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); - } - if (!created) { - var errCode = FS.mayOpen(node, flags); - if (errCode) { - throw new FS.ErrnoError(errCode); + if (options.excludeUnclassifiedObjects) { + continue; + } } - } - if (flags & 512) { - FS.truncate(node, 0); - } - flags &= ~(128 | 512 | 131072); - var stream = FS.createStream({ node, path: FS.getPath(node), flags, seekable: true, position: 0, stream_ops: node.stream_ops, ungotten: [], error: false }, fd_start, fd_end); - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - if (Module["logReadFiles"] && !(flags & 1)) { - if (!FS.readFiles) - FS.readFiles = {}; - if (!(path in FS.readFiles)) { - FS.readFiles[path] = 1; - err("FS.trackingDelegate error on read file: " + path); + + // Iterate each entity's meshes + + for (let meshIndex = firstMeshIndex; meshIndex < lastMeshIndex; meshIndex++) { + + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + const geometryReuseCount = geometryReuseCounts[geometryIndex]; + const isReusedGeometry = (geometryReuseCount > 1); + + const atLastGeometry = (geometryIndex === (numGeometries - 1)); + + const meshColor = decompressColor$3(eachMeshMaterial.subarray((meshIndex * 6), (meshIndex * 6) + 3)); + const meshOpacity = eachMeshMaterial[(meshIndex * 6) + 3] / 255.0; + const meshMetallic = eachMeshMaterial[(meshIndex * 6) + 4] / 255.0; + const meshRoughness = eachMeshMaterial[(meshIndex * 6) + 5] / 255.0; + + const meshId = nextMeshId++; + + if (isReusedGeometry) { + + // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry + + const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; + const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); + + const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel + + if (!geometryCreated[geometryId]) { + + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + + let primitiveName; + let geometryPositions; + let geometryNormals; + let geometryColors; + let geometryIndices; + let geometryEdgeIndices; + + switch (primitiveType) { + case 0: + primitiveName = "solid"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + break; + case 1: + primitiveName = "surface"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + break; + case 2: + primitiveName = "points"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryColors = convertColorsRGBToRGBA$1(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); + break; + case 3: + primitiveName = "lines"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + break; + default: + continue; + } + + sceneModel.createGeometry({ + id: geometryId, + primitive: primitiveName, + positionsCompressed: geometryPositions, + normalsCompressed: geometryNormals, + colors: geometryColors, + indices: geometryIndices, + edgeIndices: geometryEdgeIndices, + positionsDecodeMatrix: reusedGeometriesDecodeMatrix + }); + + geometryCreated[geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + origin: tileCenter, + matrix: meshMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + + } else { + + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + + let primitiveName; + let geometryPositions; + let geometryNormals; + let geometryColors; + let geometryIndices; + let geometryEdgeIndices; + + switch (primitiveType) { + case 0: + primitiveName = "solid"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + break; + case 1: + primitiveName = "surface"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + break; + case 2: + primitiveName = "points"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryColors = convertColorsRGBToRGBA$1(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); + break; + case 3: + primitiveName = "lines"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + break; + default: + continue; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + origin: tileCenter, + primitive: primitiveName, + positionsCompressed: geometryPositions, + normalsCompressed: geometryNormals, + colors: geometryColors, + indices: geometryIndices, + edgeIndices: geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + } } - } - try { - if (FS.trackingDelegate["onOpenFile"]) { - var trackingFlags = 0; - if ((flags & 2097155) !== 1) { - trackingFlags |= FS.tracking.openFlags.READ; - } - if ((flags & 2097155) !== 0) { - trackingFlags |= FS.tracking.openFlags.WRITE; - } - FS.trackingDelegate["onOpenFile"](path, trackingFlags); + + if (meshIds.length > 0) { + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, + meshIds: meshIds + })); } - } catch (e) { - err("FS.trackingDelegate['onOpenFile']('" + path + "', flags) threw an exception: " + e.message); - } - return stream; - }, close: function(stream) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (stream.getdents) - stream.getdents = null; - try { - if (stream.stream_ops.close) { - stream.stream_ops.close(stream); + } + } +} + +/** @private */ +const ParserV7 = { + version: 7, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$3(elements); + const inflatedData = inflate$3(deflatedData); + load$3(viewer, options, inflatedData, sceneModel); + } +}; + +/* + + Parser for .XKT Format V8 + + */ + +let pako$2 = window.pako || p; +if (!pako$2.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$2 = pako$2.default; +} + +const tempVec4a$2 = math.vec4(); +const tempVec4b$2 = math.vec4(); + +function extract$2(elements) { + + return { + + // Vertex attributes + + types: elements[0], + eachMetaObjectId: elements[1], + eachMetaObjectType: elements[2], + eachMetaObjectName: elements[3], + eachMetaObjectParent: elements[4], + + positions: elements[5], + normals: elements[6], + colors: elements[7], + indices: elements[8], + edgeIndices: elements[9], + + // Transform matrices + + matrices: elements[10], + reusedGeometriesDecodeMatrix: elements[11], + + // Geometries + + eachGeometryPrimitiveType: elements[12], + eachGeometryPositionsPortion: elements[13], + eachGeometryNormalsPortion: elements[14], + eachGeometryColorsPortion: elements[15], + eachGeometryIndicesPortion: elements[16], + eachGeometryEdgeIndicesPortion: elements[17], + + // Meshes are grouped in runs that are shared by the same entities + + eachMeshGeometriesPortion: elements[18], + eachMeshMatricesPortion: elements[19], + eachMeshMaterial: elements[20], + + // Entity elements in the following arrays are grouped in runs that are shared by the same tiles + + eachEntityMetaObject: elements[21], + eachEntityMeshesPortion: elements[22], + + eachTileAABB: elements[23], + eachTileEntitiesPortion: elements[24] + }; +} + +function inflate$2(deflatedData) { + + function inflate(array, options) { + return (array.length === 0) ? [] : pako$2.inflate(array, options).buffer; + } + + return { + + types: pako$2.inflate(deflatedData.types, {to: 'string'}), + eachMetaObjectId: pako$2.inflate(deflatedData.eachMetaObjectId, {to: 'string'}), + eachMetaObjectType: new Uint32Array(inflate(deflatedData.eachMetaObjectType)), + eachMetaObjectName: pako$2.inflate(deflatedData.eachMetaObjectName, {to: 'string'}), + eachMetaObjectParent: new Uint32Array(inflate(deflatedData.eachMetaObjectParent)), + + positions: new Uint16Array(inflate(deflatedData.positions)), + normals: new Int8Array(inflate(deflatedData.normals)), + colors: new Uint8Array(inflate(deflatedData.colors)), + indices: new Uint32Array(inflate(deflatedData.indices)), + edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + + matrices: new Float32Array(inflate(deflatedData.matrices)), + reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + + eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), + eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), + eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), + eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), + eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), + eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + + eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), + eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), + eachMeshMaterial: new Uint8Array(inflate(deflatedData.eachMeshMaterial)), + + eachEntityMetaObject: new Uint32Array(inflate(deflatedData.eachEntityMetaObject)), + eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + + eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), + eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), + }; +} + +const decompressColor$2 = (function () { + const floatColor = new Float32Array(3); + return function (intColor) { + floatColor[0] = intColor[0] / 255.0; + floatColor[1] = intColor[1] / 255.0; + floatColor[2] = intColor[2] / 255.0; + return floatColor; + }; +})(); + +function convertColorsRGBToRGBA(colorsRGB) { + const colorsRGBA = []; + for (let i = 0, len = colorsRGB.length; i < len; i += 3) { + colorsRGBA.push(colorsRGB[i]); + colorsRGBA.push(colorsRGB[i + 1]); + colorsRGBA.push(colorsRGB[i + 2]); + colorsRGBA.push(1.0); + } + return colorsRGBA; +} + +function load$2(viewer, options, inflatedData, sceneModel) { + + const types = JSON.parse(inflatedData.types); + const eachMetaObjectId = JSON.parse(inflatedData.eachMetaObjectId); + const eachMetaObjectType = inflatedData.eachMetaObjectType; + const eachMetaObjectName = JSON.parse(inflatedData.eachMetaObjectName); + const eachMetaObjectParent = inflatedData.eachMetaObjectParent; + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const colors = inflatedData.colors; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + + const matrices = inflatedData.matrices; + const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + + const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; + const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; + const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; + const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; + const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; + const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + + const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; + const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; + const eachMeshMaterial = inflatedData.eachMeshMaterial; + + const eachEntityMetaObject = inflatedData.eachEntityMetaObject; + const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + + const eachTileAABB = inflatedData.eachTileAABB; + const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + + const numMetaObjects = eachMetaObjectId.length; + const numGeometries = eachGeometryPositionsPortion.length; + const numMeshes = eachMeshGeometriesPortion.length; + const numEntities = eachEntityMetaObject.length; + const numTiles = eachTileEntitiesPortion.length; + + let nextMeshId = 0; + + // Create metamodel, unless already loaded from JSON by XKTLoaderPlugin + + const metaModelId = sceneModel.id; + + if (!viewer.metaScene.metaModels[metaModelId]) { + + const metaModelData = { + metaObjects: [] + }; + + for (let metaObjectIndex = 0; metaObjectIndex < numMetaObjects; metaObjectIndex++) { + + const metaObjectId = eachMetaObjectId[metaObjectIndex]; + const typeIndex = eachMetaObjectType[metaObjectIndex]; + const metaObjectType = types[typeIndex] || "default"; + const metaObjectName = eachMetaObjectName[metaObjectIndex]; + const metaObjectParentIndex = eachMetaObjectParent[metaObjectIndex]; + const metaObjectParentId = (metaObjectParentIndex !== metaObjectIndex) ? eachMetaObjectId[metaObjectParentIndex] : null; + + metaModelData.metaObjects.push({ + id: metaObjectId, + type: metaObjectType, + name: metaObjectName, + parent: metaObjectParentId + }); + } + + viewer.metaScene.createMetaModel(metaModelId, metaModelData, { + includeTypes: options.includeTypes, + excludeTypes: options.excludeTypes, + globalizeObjectIds: options.globalizeObjectIds + }); + + sceneModel.once("destroyed", () => { + viewer.metaScene.destroyMetaModel(metaModelId); + }); + } + + // Count instances of each geometry + + const geometryReuseCounts = new Uint32Array(numGeometries); + + for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + if (geometryReuseCounts[geometryIndex] !== undefined) { + geometryReuseCounts[geometryIndex]++; + } else { + geometryReuseCounts[geometryIndex] = 1; + } + } + + // Iterate over tiles + + const tileCenter = math.vec3(); + const rtcAABB = math.AABB3(); + + const geometryArraysCache = {}; + + for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + + const lastTileIndex = (numTiles - 1); + + const atLastTile = (tileIndex === lastTileIndex); + + const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; + const lastTileEntityIndex = atLastTile ? numEntities : eachTileEntitiesPortion[tileIndex + 1]; + + const tileAABBIndex = tileIndex * 6; + const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + + math.getAABB3Center(tileAABB, tileCenter); + + rtcAABB[0] = tileAABB[0] - tileCenter[0]; + rtcAABB[1] = tileAABB[1] - tileCenter[1]; + rtcAABB[2] = tileAABB[2] - tileCenter[2]; + rtcAABB[3] = tileAABB[3] - tileCenter[0]; + rtcAABB[4] = tileAABB[4] - tileCenter[1]; + rtcAABB[5] = tileAABB[5] - tileCenter[2]; + + const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + + const geometryCreatedInTile = {}; + + // Iterate over each tile's entities + + for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex < lastTileEntityIndex; tileEntityIndex++) { + + const xktMetaObjectIndex = eachEntityMetaObject[tileEntityIndex]; + const xktMetaObjectId = eachMetaObjectId[xktMetaObjectIndex]; + const xktEntityId = xktMetaObjectId; + + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + + const lastTileEntityIndex = (numEntities - 1); + const atLastTileEntity = (tileEntityIndex === lastTileEntityIndex); + const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; + const lastMeshIndex = atLastTileEntity ? eachMeshGeometriesPortion.length : eachEntityMeshesPortion[tileEntityIndex + 1]; + + const meshIds = []; + + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + + if (metaObject) { + + // Mask loading of object types + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; + } + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; + } + + // Get initial property values for object types + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } + if (props.metallic !== undefined && props.metallic !== null) { + meshDefaults.metallic = props.metallic; + } + if (props.roughness !== undefined && props.roughness !== null) { + meshDefaults.roughness = props.roughness; + } + } + + } else { + if (options.excludeUnclassifiedObjects) { + continue; + } } - } catch (e) { - throw e; - } finally { - FS.closeStream(stream.fd); - } - stream.fd = null; - }, isClosed: function(stream) { - return stream.fd === null; - }, llseek: function(stream, offset, whence) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (!stream.seekable || !stream.stream_ops.llseek) { - throw new FS.ErrnoError(70); - } - if (whence != 0 && whence != 1 && whence != 2) { - throw new FS.ErrnoError(28); - } - stream.position = stream.stream_ops.llseek(stream, offset, whence); - stream.ungotten = []; - return stream.position; - }, read: function(stream, buffer2, offset, length, position) { - offset >>>= 0; - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.read) { - throw new FS.ErrnoError(28); - } - var seeking = typeof position !== "undefined"; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesRead = stream.stream_ops.read(stream, buffer2, offset, length, position); - if (!seeking) - stream.position += bytesRead; - return bytesRead; - }, write: function(stream, buffer2, offset, length, position, canOwn) { - offset >>>= 0; - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.write) { - throw new FS.ErrnoError(28); - } - if (stream.seekable && stream.flags & 1024) { - FS.llseek(stream, 0, 2); - } - var seeking = typeof position !== "undefined"; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesWritten = stream.stream_ops.write(stream, buffer2, offset, length, position, canOwn); - if (!seeking) - stream.position += bytesWritten; - try { - if (stream.path && FS.trackingDelegate["onWriteToFile"]) - FS.trackingDelegate["onWriteToFile"](stream.path); - } catch (e) { - err("FS.trackingDelegate['onWriteToFile']('" + stream.path + "') threw an exception: " + e.message); - } - return bytesWritten; - }, allocate: function(stream, offset, length) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (offset < 0 || length <= 0) { - throw new FS.ErrnoError(28); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (!stream.stream_ops.allocate) { - throw new FS.ErrnoError(138); - } - stream.stream_ops.allocate(stream, offset, length); - }, mmap: function(stream, address, length, position, prot, flags) { - address >>>= 0; - if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) { - throw new FS.ErrnoError(2); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(2); - } - if (!stream.stream_ops.mmap) { - throw new FS.ErrnoError(43); - } - return stream.stream_ops.mmap(stream, address, length, position, prot, flags); - }, msync: function(stream, buffer2, offset, length, mmapFlags) { - offset >>>= 0; - if (!stream || !stream.stream_ops.msync) { - return 0; - } - return stream.stream_ops.msync(stream, buffer2, offset, length, mmapFlags); - }, munmap: function(stream) { - return 0; - }, ioctl: function(stream, cmd, arg) { - if (!stream.stream_ops.ioctl) { - throw new FS.ErrnoError(59); - } - return stream.stream_ops.ioctl(stream, cmd, arg); - }, readFile: function(path, opts) { - opts = opts || {}; - opts.flags = opts.flags || 0; - opts.encoding = opts.encoding || "binary"; - if (opts.encoding !== "utf8" && opts.encoding !== "binary") { - throw new Error('Invalid encoding type "' + opts.encoding + '"'); - } - var ret; - var stream = FS.open(path, opts.flags); - var stat = FS.stat(path); - var length = stat.size; - var buf = new Uint8Array(length); - FS.read(stream, buf, 0, length, 0); - if (opts.encoding === "utf8") { - ret = UTF8ArrayToString(buf, 0); - } else if (opts.encoding === "binary") { - ret = buf; - } - FS.close(stream); - return ret; - }, writeFile: function(path, data, opts) { - opts = opts || {}; - opts.flags = opts.flags || 577; - var stream = FS.open(path, opts.flags, opts.mode); - if (typeof data === "string") { - var buf = new Uint8Array(lengthBytesUTF8(data) + 1); - var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); - FS.write(stream, buf, 0, actualNumBytes, void 0, opts.canOwn); - } else if (ArrayBuffer.isView(data)) { - FS.write(stream, data, 0, data.byteLength, void 0, opts.canOwn); - } else { - throw new Error("Unsupported data type"); - } - FS.close(stream); - }, cwd: function() { - return FS.currentPath; - }, chdir: function(path) { - var lookup = FS.lookupPath(path, { follow: true }); - if (lookup.node === null) { - throw new FS.ErrnoError(44); - } - if (!FS.isDir(lookup.node.mode)) { - throw new FS.ErrnoError(54); - } - var errCode = FS.nodePermissions(lookup.node, "x"); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - FS.currentPath = lookup.path; - }, createDefaultDirectories: function() { - FS.mkdir("/tmp"); - FS.mkdir("/home"); - FS.mkdir("/home/web_user"); - }, createDefaultDevices: function() { - FS.mkdir("/dev"); - FS.registerDevice(FS.makedev(1, 3), { read: function() { - return 0; - }, write: function(stream, buffer2, offset, length, pos) { - return length; - } }); - FS.mkdev("/dev/null", FS.makedev(1, 3)); - TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); - TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); - FS.mkdev("/dev/tty", FS.makedev(5, 0)); - FS.mkdev("/dev/tty1", FS.makedev(6, 0)); - var random_device = getRandomDevice(); - FS.createDevice("/dev", "random", random_device); - FS.createDevice("/dev", "urandom", random_device); - FS.mkdir("/dev/shm"); - FS.mkdir("/dev/shm/tmp"); - }, createSpecialDirectories: function() { - FS.mkdir("/proc"); - FS.mkdir("/proc/self"); - FS.mkdir("/proc/self/fd"); - FS.mount({ mount: function() { - var node = FS.createNode("/proc/self", "fd", 16384 | 511, 73); - node.node_ops = { lookup: function(parent, name2) { - var fd = +name2; - var stream = FS.getStream(fd); - if (!stream) - throw new FS.ErrnoError(8); - var ret = { parent: null, mount: { mountpoint: "fake" }, node_ops: { readlink: function() { - return stream.path; - } } }; - ret.parent = ret; - return ret; - } }; - return node; - } }, {}, "/proc/self/fd"); - }, createStandardStreams: function() { - if (Module["stdin"]) { - FS.createDevice("/dev", "stdin", Module["stdin"]); - } else { - FS.symlink("/dev/tty", "/dev/stdin"); - } - if (Module["stdout"]) { - FS.createDevice("/dev", "stdout", null, Module["stdout"]); - } else { - FS.symlink("/dev/tty", "/dev/stdout"); - } - if (Module["stderr"]) { - FS.createDevice("/dev", "stderr", null, Module["stderr"]); - } else { - FS.symlink("/dev/tty1", "/dev/stderr"); - } - FS.open("/dev/stdin", 0); - FS.open("/dev/stdout", 1); - FS.open("/dev/stderr", 1); - }, ensureErrnoError: function() { - if (FS.ErrnoError) - return; - FS.ErrnoError = function ErrnoError(errno, node) { - this.node = node; - this.setErrno = function(errno2) { - this.errno = errno2; - }; - this.setErrno(errno); - this.message = "FS error"; - }; - FS.ErrnoError.prototype = new Error(); - FS.ErrnoError.prototype.constructor = FS.ErrnoError; - [44].forEach(function(code) { - FS.genericErrors[code] = new FS.ErrnoError(code); - FS.genericErrors[code].stack = ""; - }); - }, staticInit: function() { - FS.ensureErrnoError(); - FS.nameTable = new Array(4096); - FS.mount(MEMFS, {}, "/"); - FS.createDefaultDirectories(); - FS.createDefaultDevices(); - FS.createSpecialDirectories(); - FS.filesystems = { "MEMFS": MEMFS }; - }, init: function(input, output, error) { - FS.init.initialized = true; - FS.ensureErrnoError(); - Module["stdin"] = input || Module["stdin"]; - Module["stdout"] = output || Module["stdout"]; - Module["stderr"] = error || Module["stderr"]; - FS.createStandardStreams(); - }, quit: function() { - FS.init.initialized = false; - var fflush = Module["_fflush"]; - if (fflush) - fflush(0); - for (var i = 0; i < FS.streams.length; i++) { - var stream = FS.streams[i]; - if (!stream) { - continue; - } - FS.close(stream); - } - }, getMode: function(canRead, canWrite) { - var mode = 0; - if (canRead) - mode |= 292 | 73; - if (canWrite) - mode |= 146; - return mode; - }, findObject: function(path, dontResolveLastLink) { - var ret = FS.analyzePath(path, dontResolveLastLink); - if (ret.exists) { - return ret.object; - } else { - return null; - } - }, analyzePath: function(path, dontResolveLastLink) { - try { - var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - path = lookup.path; - } catch (e) { - } - var ret = { isRoot: false, exists: false, error: 0, name: null, path: null, object: null, parentExists: false, parentPath: null, parentObject: null }; - try { - var lookup = FS.lookupPath(path, { parent: true }); - ret.parentExists = true; - ret.parentPath = lookup.path; - ret.parentObject = lookup.node; - ret.name = PATH.basename(path); - lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - ret.exists = true; - ret.path = lookup.path; - ret.object = lookup.node; - ret.name = lookup.node.name; - ret.isRoot = lookup.path === "/"; - } catch (e) { - ret.error = e.errno; - } - return ret; - }, createPath: function(parent, path, canRead, canWrite) { - parent = typeof parent === "string" ? parent : FS.getPath(parent); - var parts = path.split("/").reverse(); - while (parts.length) { - var part = parts.pop(); - if (!part) - continue; - var current = PATH.join2(parent, part); - try { - FS.mkdir(current); - } catch (e) { - } - parent = current; - } - return current; - }, createFile: function(parent, name2, properties, canRead, canWrite) { - var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name2); - var mode = FS.getMode(canRead, canWrite); - return FS.create(path, mode); - }, createDataFile: function(parent, name2, data, canRead, canWrite, canOwn) { - var path = name2 ? PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name2) : parent; - var mode = FS.getMode(canRead, canWrite); - var node = FS.create(path, mode); - if (data) { - if (typeof data === "string") { - var arr = new Array(data.length); - for (var i = 0, len = data.length; i < len; ++i) - arr[i] = data.charCodeAt(i); - data = arr; - } - FS.chmod(node, mode | 146); - var stream = FS.open(node, 577); - FS.write(stream, data, 0, data.length, 0, canOwn); - FS.close(stream); - FS.chmod(node, mode); - } - return node; - }, createDevice: function(parent, name2, input, output) { - var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name2); - var mode = FS.getMode(!!input, !!output); - if (!FS.createDevice.major) - FS.createDevice.major = 64; - var dev = FS.makedev(FS.createDevice.major++, 0); - FS.registerDevice(dev, { open: function(stream) { - stream.seekable = false; - }, close: function(stream) { - if (output && output.buffer && output.buffer.length) { - output(10); - } - }, read: function(stream, buffer2, offset, length, pos) { - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = input(); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === void 0 && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === void 0) - break; - bytesRead++; - buffer2[offset + i] = result; - } - if (bytesRead) { - stream.node.timestamp = Date.now(); - } - return bytesRead; - }, write: function(stream, buffer2, offset, length, pos) { - for (var i = 0; i < length; i++) { - try { - output(buffer2[offset + i]); - } catch (e) { - throw new FS.ErrnoError(29); - } - } - if (length) { - stream.node.timestamp = Date.now(); - } - return i; - } }); - return FS.mkdev(path, mode, dev); - }, forceLoadFile: function(obj) { - if (obj.isDevice || obj.isFolder || obj.link || obj.contents) - return true; - if (typeof XMLHttpRequest !== "undefined") { - throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); - } else if (read_) { - try { - obj.contents = intArrayFromString(read_(obj.url), true); - obj.usedBytes = obj.contents.length; - } catch (e) { - throw new FS.ErrnoError(29); - } - } else { - throw new Error("Cannot load without read() or XMLHttpRequest."); - } - }, createLazyFile: function(parent, name2, url, canRead, canWrite) { - function LazyUint8Array() { - this.lengthKnown = false; - this.chunks = []; - } - LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) { - if (idx > this.length - 1 || idx < 0) { - return void 0; - } - var chunkOffset = idx % this.chunkSize; - var chunkNum = idx / this.chunkSize | 0; - return this.getter(chunkNum)[chunkOffset]; - }; - LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) { - this.getter = getter; - }; - LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() { - var xhr = new XMLHttpRequest(); - xhr.open("HEAD", url, false); - xhr.send(null); - if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) - throw new Error("Couldn't load " + url + ". Status: " + xhr.status); - var datalength = Number(xhr.getResponseHeader("Content-length")); - var header; - var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; - var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; - var chunkSize = 1024 * 1024; - if (!hasByteServing) - chunkSize = datalength; - var doXHR = function(from, to) { - if (from > to) - throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); - if (to > datalength - 1) - throw new Error("only " + datalength + " bytes available! programmer error!"); - var xhr2 = new XMLHttpRequest(); - xhr2.open("GET", url, false); - if (datalength !== chunkSize) - xhr2.setRequestHeader("Range", "bytes=" + from + "-" + to); - if (typeof Uint8Array != "undefined") - xhr2.responseType = "arraybuffer"; - if (xhr2.overrideMimeType) { - xhr2.overrideMimeType("text/plain; charset=x-user-defined"); - } - xhr2.send(null); - if (!(xhr2.status >= 200 && xhr2.status < 300 || xhr2.status === 304)) - throw new Error("Couldn't load " + url + ". Status: " + xhr2.status); - if (xhr2.response !== void 0) { - return new Uint8Array(xhr2.response || []); - } else { - return intArrayFromString(xhr2.responseText || "", true); - } - }; - var lazyArray2 = this; - lazyArray2.setDataGetter(function(chunkNum) { - var start = chunkNum * chunkSize; - var end = (chunkNum + 1) * chunkSize - 1; - end = Math.min(end, datalength - 1); - if (typeof lazyArray2.chunks[chunkNum] === "undefined") { - lazyArray2.chunks[chunkNum] = doXHR(start, end); - } - if (typeof lazyArray2.chunks[chunkNum] === "undefined") - throw new Error("doXHR failed!"); - return lazyArray2.chunks[chunkNum]; - }); - if (usesGzip || !datalength) { - chunkSize = datalength = 1; - datalength = this.getter(0).length; - chunkSize = datalength; - out("LazyFiles on gzip forces download of the whole file when length is accessed"); - } - this._length = datalength; - this._chunkSize = chunkSize; - this.lengthKnown = true; - }; - if (typeof XMLHttpRequest !== "undefined") { - if (!ENVIRONMENT_IS_WORKER) - throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"; - var lazyArray = new LazyUint8Array(); - Object.defineProperties(lazyArray, { length: { get: function() { - if (!this.lengthKnown) { - this.cacheLength(); - } - return this._length; - } }, chunkSize: { get: function() { - if (!this.lengthKnown) { - this.cacheLength(); - } - return this._chunkSize; - } } }); - var properties = { isDevice: false, contents: lazyArray }; - } else { - var properties = { isDevice: false, url }; - } - var node = FS.createFile(parent, name2, properties, canRead, canWrite); - if (properties.contents) { - node.contents = properties.contents; - } else if (properties.url) { - node.contents = null; - node.url = properties.url; - } - Object.defineProperties(node, { usedBytes: { get: function() { - return this.contents.length; - } } }); - var stream_ops = {}; - var keys = Object.keys(node.stream_ops); - keys.forEach(function(key2) { - var fn = node.stream_ops[key2]; - stream_ops[key2] = function forceLoadLazyFile() { - FS.forceLoadFile(node); - return fn.apply(null, arguments); - }; - }); - stream_ops.read = function stream_ops_read(stream, buffer2, offset, length, position) { - FS.forceLoadFile(node); - var contents = stream.node.contents; - if (position >= contents.length) - return 0; - var size = Math.min(contents.length - position, length); - if (contents.slice) { - for (var i = 0; i < size; i++) { - buffer2[offset + i] = contents[position + i]; - } - } else { - for (var i = 0; i < size; i++) { - buffer2[offset + i] = contents.get(position + i); - } - } - return size; - }; - node.stream_ops = stream_ops; - return node; - }, createPreloadedFile: function(parent, name2, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) { - Browser.init(); - var fullname = name2 ? PATH_FS.resolve(PATH.join2(parent, name2)) : parent; - function processData(byteArray) { - function finish(byteArray2) { - if (preFinish) - preFinish(); - if (!dontCreateFile) { - FS.createDataFile(parent, name2, byteArray2, canRead, canWrite, canOwn); - } - if (onload) - onload(); - removeRunDependency(); - } - var handled = false; - Module["preloadPlugins"].forEach(function(plugin) { - if (handled) - return; - if (plugin["canHandle"](fullname)) { - plugin["handle"](byteArray, fullname, finish, function() { - if (onerror) - onerror(); - removeRunDependency(); - }); - handled = true; - } - }); - if (!handled) - finish(byteArray); - } - addRunDependency(); - if (typeof url == "string") { - Browser.asyncLoad(url, function(byteArray) { - processData(byteArray); - }, onerror); - } else { - processData(url); - } - }, indexedDB: function() { - return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; - }, DB_NAME: function() { - return "EM_FS_" + window.location.pathname; - }, DB_VERSION: 20, DB_STORE_NAME: "FILE_DATA", saveFilesToDB: function(paths, onload, onerror) { - onload = onload || function() { - }; - onerror = onerror || function() { - }; - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = function openRequest_onupgradeneeded() { - out("creating db"); - var db = openRequest.result; - db.createObjectStore(FS.DB_STORE_NAME); - }; - openRequest.onsuccess = function openRequest_onsuccess() { - var db = openRequest.result; - var transaction = db.transaction([FS.DB_STORE_NAME], "readwrite"); - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, fail = 0, total = paths.length; - function finish() { - if (fail == 0) - onload(); - else - onerror(); - } - paths.forEach(function(path) { - var putRequest = files.put(FS.analyzePath(path).object.contents, path); - putRequest.onsuccess = function putRequest_onsuccess() { - ok++; - if (ok + fail == total) - finish(); - }; - putRequest.onerror = function putRequest_onerror() { - fail++; - if (ok + fail == total) - finish(); - }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - }, loadFilesFromDB: function(paths, onload, onerror) { - onload = onload || function() { - }; - onerror = onerror || function() { - }; - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = onerror; - openRequest.onsuccess = function openRequest_onsuccess() { - var db = openRequest.result; - try { - var transaction = db.transaction([FS.DB_STORE_NAME], "readonly"); - } catch (e) { - onerror(e); - return; - } - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, fail = 0, total = paths.length; - function finish() { - if (fail == 0) - onload(); - else - onerror(); - } - paths.forEach(function(path) { - var getRequest = files.get(path); - getRequest.onsuccess = function getRequest_onsuccess() { - if (FS.analyzePath(path).exists) { - FS.unlink(path); + + // Iterate each entity's meshes + + for (let meshIndex = firstMeshIndex; meshIndex < lastMeshIndex; meshIndex++) { + + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + const geometryReuseCount = geometryReuseCounts[geometryIndex]; + const isReusedGeometry = (geometryReuseCount > 1); + + const atLastGeometry = (geometryIndex === (numGeometries - 1)); + + const meshColor = decompressColor$2(eachMeshMaterial.subarray((meshIndex * 6), (meshIndex * 6) + 3)); + const meshOpacity = eachMeshMaterial[(meshIndex * 6) + 3] / 255.0; + const meshMetallic = eachMeshMaterial[(meshIndex * 6) + 4] / 255.0; + const meshRoughness = eachMeshMaterial[(meshIndex * 6) + 5] / 255.0; + + const meshId = nextMeshId++; + + if (isReusedGeometry) { + + // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry + + const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; + const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); + + const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel + + let geometryArrays = geometryArraysCache[geometryId]; + + if (!geometryArrays) { + + geometryArrays = { + batchThisMesh: (!options.reuseGeometries) + }; + + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + + let geometryValid = false; + + switch (primitiveType) { + case 0: + geometryArrays.primitiveName = "solid"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + case 1: + geometryArrays.primitiveName = "surface"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + case 2: + geometryArrays.primitiveName = "points"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryColors = convertColorsRGBToRGBA(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); + geometryValid = (geometryArrays.geometryPositions.length > 0); + break; + case 3: + geometryArrays.primitiveName = "lines"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + default: + continue; + } + + if (!geometryValid) { + geometryArrays = null; + } + + if (geometryArrays) { + if (geometryArrays.geometryPositions.length > 1000) ; + if (geometryArrays.batchThisMesh) { + geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length); + const geometryPositions = geometryArrays.geometryPositions; + const decompressedPositions = geometryArrays.decompressedPositions; + for (let i = 0, len = geometryPositions.length; i < len; i += 3) { + decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12]; + decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13]; + decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14]; + } + geometryArrays.geometryPositions = null; + geometryArraysCache[geometryId] = geometryArrays; + } + } + } + + if (geometryArrays) { + + if (geometryArrays.batchThisMesh) { + + const decompressedPositions = geometryArrays.decompressedPositions; + const positions = new Uint16Array(decompressedPositions.length); + for (let i = 0, len = decompressedPositions.length; i < len; i += 3) { + tempVec4a$2[0] = decompressedPositions[i + 0]; + tempVec4a$2[1] = decompressedPositions[i + 1]; + tempVec4a$2[2] = decompressedPositions[i + 2]; + tempVec4a$2[3] = 1; + math.transformVec4(meshMatrix, tempVec4a$2, tempVec4b$2); + geometryCompressionUtils.compressPosition(tempVec4b$2, rtcAABB, tempVec4a$2); + positions[i + 0] = tempVec4a$2[0]; + positions[i + 1] = tempVec4a$2[1]; + positions[i + 2] = tempVec4a$2[2]; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + origin: tileCenter, + primitive: geometryArrays.primitiveName, + positionsCompressed: positions, + normalsCompressed: geometryArrays.geometryNormals, + colorsCompressed: geometryArrays.geometryColors, + indices: geometryArrays.geometryIndices, + edgeIndices: geometryArrays.geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + + } else { + + if (!geometryCreatedInTile[geometryId]) { + + sceneModel.createGeometry({ + id: geometryId, + primitive: geometryArrays.primitiveName, + positionsCompressed: geometryArrays.geometryPositions, + normalsCompressed: geometryArrays.geometryNormals, + colorsCompressed: geometryArrays.geometryColors, + indices: geometryArrays.geometryIndices, + edgeIndices: geometryArrays.geometryEdgeIndices, + positionsDecodeMatrix: reusedGeometriesDecodeMatrix + }); + + geometryCreatedInTile[geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + origin: tileCenter, + matrix: meshMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + } + } + + } else { + + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + + let primitiveName; + let geometryPositions; + let geometryNormals; + let geometryColors; + let geometryIndices; + let geometryEdgeIndices; + let geometryValid = false; + + switch (primitiveType) { + case 0: + primitiveName = "solid"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + case 1: + primitiveName = "surface"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + case 2: + primitiveName = "points"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryColors = convertColorsRGBToRGBA(colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1])); + geometryValid = (geometryPositions.length > 0); + break; + case 3: + primitiveName = "lines"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + default: + continue; + } + + if (geometryValid) { + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + origin: tileCenter, + primitive: primitiveName, + positionsCompressed: geometryPositions, + normalsCompressed: geometryNormals, + colorsCompressed: geometryColors, + indices: geometryIndices, + edgeIndices: geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + } } - FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true); - ok++; - if (ok + fail == total) - finish(); - }; - getRequest.onerror = function getRequest_onerror() { - fail++; - if (ok + fail == total) - finish(); - }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - } }; - var SYSCALLS = { mappings: {}, DEFAULT_POLLMASK: 5, umask: 511, calculateAt: function(dirfd, path) { - if (path[0] !== "/") { - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = FS.getStream(dirfd); - if (!dirstream) - throw new FS.ErrnoError(8); - dir = dirstream.path; } - path = PATH.join2(dir, path); - } - return path; - }, doStat: function(func, path, buf) { - try { - var stat = func(path); - } catch (e) { - if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) { - return -54; + + if (meshIds.length > 0) { + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, + meshIds: meshIds + })); } - throw e; - } - GROWABLE_HEAP_I32()[buf >> 2] = stat.dev; - GROWABLE_HEAP_I32()[buf + 4 >> 2] = 0; - GROWABLE_HEAP_I32()[buf + 8 >> 2] = stat.ino; - GROWABLE_HEAP_I32()[buf + 12 >> 2] = stat.mode; - GROWABLE_HEAP_I32()[buf + 16 >> 2] = stat.nlink; - GROWABLE_HEAP_I32()[buf + 20 >> 2] = stat.uid; - GROWABLE_HEAP_I32()[buf + 24 >> 2] = stat.gid; - GROWABLE_HEAP_I32()[buf + 28 >> 2] = stat.rdev; - GROWABLE_HEAP_I32()[buf + 32 >> 2] = 0; - tempI64 = [stat.size >>> 0, (tempDouble = stat.size, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf + 40 >> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 44 >> 2] = tempI64[1]; - GROWABLE_HEAP_I32()[buf + 48 >> 2] = 4096; - GROWABLE_HEAP_I32()[buf + 52 >> 2] = stat.blocks; - GROWABLE_HEAP_I32()[buf + 56 >> 2] = stat.atime.getTime() / 1e3 | 0; - GROWABLE_HEAP_I32()[buf + 60 >> 2] = 0; - GROWABLE_HEAP_I32()[buf + 64 >> 2] = stat.mtime.getTime() / 1e3 | 0; - GROWABLE_HEAP_I32()[buf + 68 >> 2] = 0; - GROWABLE_HEAP_I32()[buf + 72 >> 2] = stat.ctime.getTime() / 1e3 | 0; - GROWABLE_HEAP_I32()[buf + 76 >> 2] = 0; - tempI64 = [stat.ino >>> 0, (tempDouble = stat.ino, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf + 80 >> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 84 >> 2] = tempI64[1]; - return 0; - }, doMsync: function(addr, stream, len, flags, offset) { - var buffer2 = GROWABLE_HEAP_U8().slice(addr, addr + len); - FS.msync(stream, buffer2, offset, len, flags); - }, doMkdir: function(path, mode) { - path = PATH.normalize(path); - if (path[path.length - 1] === "/") - path = path.substr(0, path.length - 1); - FS.mkdir(path, mode, 0); - return 0; - }, doMknod: function(path, mode, dev) { - switch (mode & 61440) { - case 32768: - case 8192: - case 24576: - case 4096: - case 49152: - break; - default: - return -28; - } - FS.mknod(path, mode, dev); - return 0; - }, doReadlink: function(path, buf, bufsize) { - if (bufsize <= 0) - return -28; - var ret = FS.readlink(path); - var len = Math.min(bufsize, lengthBytesUTF8(ret)); - var endChar = GROWABLE_HEAP_I8()[buf + len]; - stringToUTF8(ret, buf, bufsize + 1); - GROWABLE_HEAP_I8()[buf + len] = endChar; - return len; - }, doAccess: function(path, amode) { - if (amode & ~7) { - return -28; - } - var node; - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - if (!node) { - return -44; - } - var perms = ""; - if (amode & 4) - perms += "r"; - if (amode & 2) - perms += "w"; - if (amode & 1) - perms += "x"; - if (perms && FS.nodePermissions(node, perms)) { - return -2; - } - return 0; - }, doDup: function(path, flags, suggestFD) { - var suggest = FS.getStream(suggestFD); - if (suggest) - FS.close(suggest); - return FS.open(path, flags, 0, suggestFD, suggestFD).fd; - }, doReadv: function(stream, iov, iovcnt, offset) { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = GROWABLE_HEAP_I32()[iov + i * 8 >> 2]; - var len = GROWABLE_HEAP_I32()[iov + (i * 8 + 4) >> 2]; - var curr = FS.read(stream, GROWABLE_HEAP_I8(), ptr, len, offset); - if (curr < 0) - return -1; - ret += curr; - if (curr < len) - break; - } - return ret; - }, doWritev: function(stream, iov, iovcnt, offset) { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = GROWABLE_HEAP_I32()[iov + i * 8 >> 2]; - var len = GROWABLE_HEAP_I32()[iov + (i * 8 + 4) >> 2]; - var curr = FS.write(stream, GROWABLE_HEAP_I8(), ptr, len, offset); - if (curr < 0) - return -1; - ret += curr; - } - return ret; - }, varargs: void 0, get: function() { - SYSCALLS.varargs += 4; - var ret = GROWABLE_HEAP_I32()[SYSCALLS.varargs - 4 >> 2]; - return ret; - }, getStr: function(ptr) { - var ret = UTF8ToString(ptr); - return ret; - }, getStreamFromFD: function(fd) { - var stream = FS.getStream(fd); - if (!stream) - throw new FS.ErrnoError(8); - return stream; - }, get64: function(low, high) { - return low; - } }; - function ___sys_ioctl(fd, op, varargs) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(2, 1, fd, op, varargs); - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (op) { - case 21509: - case 21505: { - if (!stream.tty) - return -59; - return 0; - } - case 21510: - case 21511: - case 21512: - case 21506: - case 21507: - case 21508: { - if (!stream.tty) - return -59; - return 0; - } - case 21519: { - if (!stream.tty) - return -59; - var argp = SYSCALLS.get(); - GROWABLE_HEAP_I32()[argp >> 2] = 0; - return 0; - } - case 21520: { - if (!stream.tty) - return -59; - return -28; - } - case 21531: { - var argp = SYSCALLS.get(); - return FS.ioctl(stream, op, argp); - } - case 21523: { - if (!stream.tty) - return -59; - return 0; - } - case 21524: { - if (!stream.tty) - return -59; - return 0; - } - default: - abort("bad ioctl syscall " + op); - } - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - function ___sys_open(path, flags, varargs) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(3, 1, path, flags, varargs); - SYSCALLS.varargs = varargs; - try { - var pathname = SYSCALLS.getStr(path); - var mode = SYSCALLS.get(); - var stream = FS.open(pathname, flags, mode); - return stream.fd; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return -e.errno; - } - } - var tupleRegistrations = {}; - function runDestructors(destructors) { - while (destructors.length) { - var ptr = destructors.pop(); - var del = destructors.pop(); - del(ptr); - } - } - function simpleReadValueFromPointer(pointer) { - return this["fromWireType"](GROWABLE_HEAP_U32()[pointer >> 2]); - } - var awaitingDependencies = {}; - var registeredTypes = {}; - var typeDependencies = {}; - var char_0 = 48; - var char_9 = 57; - function makeLegalFunctionName(name2) { - if (name2 === void 0) { - return "_unknown"; - } - name2 = name2.replace(/[^a-zA-Z0-9_]/g, "$"); - var f = name2.charCodeAt(0); - if (f >= char_0 && f <= char_9) { - return "_" + name2; - } else { - return name2; - } - } - function createNamedFunction(name2, body) { - name2 = makeLegalFunctionName(name2); - return new Function("body", "return function " + name2 + '() {\n "use strict"; return body.apply(this, arguments);\n};\n')(body); - } - function extendError(baseErrorType, errorName) { - var errorClass = createNamedFunction(errorName, function(message) { - this.name = errorName; - this.message = message; - var stack = new Error(message).stack; - if (stack !== void 0) { - this.stack = this.toString() + "\n" + stack.replace(/^Error(:[^\n]*)?\n/, ""); - } - }); - errorClass.prototype = Object.create(baseErrorType.prototype); - errorClass.prototype.constructor = errorClass; - errorClass.prototype.toString = function() { - if (this.message === void 0) { - return this.name; - } else { - return this.name + ": " + this.message; - } - }; - return errorClass; } - var InternalError = void 0; - function throwInternalError(message) { - throw new InternalError(message); + } +} + +/** @private */ +const ParserV8 = { + version: 8, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$2(elements); + const inflatedData = inflate$2(deflatedData); + load$2(viewer, options, inflatedData, sceneModel); + } +}; + +/* + + Parser for .XKT Format V9 + + */ + +let pako$1 = window.pako || p; +if (!pako$1.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako$1 = pako$1.default; +} + +const tempVec4a$1 = math.vec4(); +const tempVec4b$1 = math.vec4(); + +function extract$1(elements) { + + return { + + // Metadata + + metadata: elements[0], + + positions: elements[1], + normals: elements[2], + colors: elements[3], + indices: elements[4], + edgeIndices: elements[5], + + // Transform matrices + + matrices: elements[6], + reusedGeometriesDecodeMatrix: elements[7], + + // Geometries + + eachGeometryPrimitiveType: elements[8], + eachGeometryPositionsPortion: elements[9], + eachGeometryNormalsPortion: elements[10], + eachGeometryColorsPortion: elements[11], + eachGeometryIndicesPortion: elements[12], + eachGeometryEdgeIndicesPortion: elements[13], + + // Meshes are grouped in runs that are shared by the same entities + + eachMeshGeometriesPortion: elements[14], + eachMeshMatricesPortion: elements[15], + eachMeshMaterial: elements[16], + + // Entity elements in the following arrays are grouped in runs that are shared by the same tiles + + eachEntityId: elements[17], + eachEntityMeshesPortion: elements[18], + + eachTileAABB: elements[19], + eachTileEntitiesPortion: elements[20] + }; +} + +function inflate$1(deflatedData) { + + function inflate(array, options) { + return (array.length === 0) ? [] : pako$1.inflate(array, options).buffer; + } + + return { + + metadata: JSON.parse(pako$1.inflate(deflatedData.metadata, {to: 'string'})), + + positions: new Uint16Array(inflate(deflatedData.positions)), + normals: new Int8Array(inflate(deflatedData.normals)), + colors: new Uint8Array(inflate(deflatedData.colors)), + indices: new Uint32Array(inflate(deflatedData.indices)), + edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + + matrices: new Float32Array(inflate(deflatedData.matrices)), + reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + + eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), + eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), + eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), + eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), + eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), + eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + + eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), + eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), + eachMeshMaterial: new Uint8Array(inflate(deflatedData.eachMeshMaterial)), + + eachEntityId: JSON.parse(pako$1.inflate(deflatedData.eachEntityId, {to: 'string'})), + eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + + eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), + eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), + }; +} + +const decompressColor$1 = (function () { + const floatColor = new Float32Array(3); + return function (intColor) { + floatColor[0] = intColor[0] / 255.0; + floatColor[1] = intColor[1] / 255.0; + floatColor[2] = intColor[2] / 255.0; + return floatColor; + }; +})(); + +function load$1(viewer, options, inflatedData, sceneModel) { + + const metadata = inflatedData.metadata; + + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const colors = inflatedData.colors; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + + const matrices = inflatedData.matrices; + const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + + const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; + const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; + const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; + const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; + const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; + const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + + const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; + const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; + const eachMeshMaterial = inflatedData.eachMeshMaterial; + + const eachEntityId = inflatedData.eachEntityId; + const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + + const eachTileAABB = inflatedData.eachTileAABB; + const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + + const numGeometries = eachGeometryPositionsPortion.length; + const numMeshes = eachMeshGeometriesPortion.length; + const numEntities = eachEntityMeshesPortion.length; + const numTiles = eachTileEntitiesPortion.length; + + let nextMeshId = 0; + + // Create metamodel, unless already loaded from external JSON file by XKTLoaderPlugin + + const metaModelId = sceneModel.id; + + if (!viewer.metaScene.metaModels[metaModelId]) { + + viewer.metaScene.createMetaModel(metaModelId, metadata, { + includeTypes: options.includeTypes, + excludeTypes: options.excludeTypes, + globalizeObjectIds: options.globalizeObjectIds + }); + + sceneModel.once("destroyed", () => { + viewer.metaScene.destroyMetaModel(metaModelId); + }); + } + + // Count instances of each geometry + + const geometryReuseCounts = new Uint32Array(numGeometries); + + for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + if (geometryReuseCounts[geometryIndex] !== undefined) { + geometryReuseCounts[geometryIndex]++; + } else { + geometryReuseCounts[geometryIndex] = 1; } - function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) { - myTypes.forEach(function(type) { - typeDependencies[type] = dependentTypes; - }); - function onComplete(typeConverters2) { - var myTypeConverters = getTypeConverters(typeConverters2); - if (myTypeConverters.length !== myTypes.length) { - throwInternalError("Mismatched type converter count"); - } - for (var i = 0; i < myTypes.length; ++i) { - registerType(myTypes[i], myTypeConverters[i]); - } - } - var typeConverters = new Array(dependentTypes.length); - var unregisteredTypes = []; - var registered = 0; - dependentTypes.forEach(function(dt, i) { - if (registeredTypes.hasOwnProperty(dt)) { - typeConverters[i] = registeredTypes[dt]; + } + + // Iterate over tiles + + const tileCenter = math.vec3(); + const rtcAABB = math.AABB3(); + + const geometryArraysCache = {}; + + for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + + const lastTileIndex = (numTiles - 1); + + const atLastTile = (tileIndex === lastTileIndex); + + const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; + const lastTileEntityIndex = atLastTile ? (numEntities - 1) : (eachTileEntitiesPortion[tileIndex + 1] - 1); + + const tileAABBIndex = tileIndex * 6; + const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + + math.getAABB3Center(tileAABB, tileCenter); + + rtcAABB[0] = tileAABB[0] - tileCenter[0]; + rtcAABB[1] = tileAABB[1] - tileCenter[1]; + rtcAABB[2] = tileAABB[2] - tileCenter[2]; + rtcAABB[3] = tileAABB[3] - tileCenter[0]; + rtcAABB[4] = tileAABB[4] - tileCenter[1]; + rtcAABB[5] = tileAABB[5] - tileCenter[2]; + + const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + + const geometryCreatedInTile = {}; + + // Iterate over each tile's entities + + for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex <= lastTileEntityIndex; tileEntityIndex++) { + + const xktEntityId = eachEntityId[tileEntityIndex]; + + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + + const finalTileEntityIndex = (numEntities - 1); + const atLastTileEntity = (tileEntityIndex === finalTileEntityIndex); + const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; + const lastMeshIndex = atLastTileEntity ? (eachMeshGeometriesPortion.length - 1) : (eachEntityMeshesPortion[tileEntityIndex + 1] - 1); + + const meshIds = []; + + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + + if (metaObject) { + + // Mask loading of object types + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; + } + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; + } + + // Get initial property values for object types + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } + if (props.metallic !== undefined && props.metallic !== null) { + meshDefaults.metallic = props.metallic; + } + if (props.roughness !== undefined && props.roughness !== null) { + meshDefaults.roughness = props.roughness; + } + } + } else { - unregisteredTypes.push(dt); - if (!awaitingDependencies.hasOwnProperty(dt)) { - awaitingDependencies[dt] = []; - } - awaitingDependencies[dt].push(function() { - typeConverters[i] = registeredTypes[dt]; - ++registered; - if (registered === unregisteredTypes.length) { - onComplete(typeConverters); + if (options.excludeUnclassifiedObjects) { + continue; } - }); } - }); - if (unregisteredTypes.length === 0) { - onComplete(typeConverters); - } - } - function __embind_finalize_value_array(rawTupleType) { - var reg = tupleRegistrations[rawTupleType]; - delete tupleRegistrations[rawTupleType]; - var elements = reg.elements; - var elementsLength = elements.length; - var elementTypes = elements.map(function(elt) { - return elt.getterReturnType; - }).concat(elements.map(function(elt) { - return elt.setterArgumentType; - })); - var rawConstructor = reg.rawConstructor; - var rawDestructor = reg.rawDestructor; - whenDependentTypesAreResolved([rawTupleType], elementTypes, function(elementTypes2) { - elements.forEach(function(elt, i) { - var getterReturnType = elementTypes2[i]; - var getter = elt.getter; - var getterContext = elt.getterContext; - var setterArgumentType = elementTypes2[i + elementsLength]; - var setter = elt.setter; - var setterContext = elt.setterContext; - elt.read = function(ptr) { - return getterReturnType["fromWireType"](getter(getterContext, ptr)); - }; - elt.write = function(ptr, o) { - var destructors = []; - setter(setterContext, ptr, setterArgumentType["toWireType"](destructors, o)); - runDestructors(destructors); - }; - }); - return [{ name: reg.name, "fromWireType": function(ptr) { - var rv = new Array(elementsLength); - for (var i = 0; i < elementsLength; ++i) { - rv[i] = elements[i].read(ptr); - } - rawDestructor(ptr); - return rv; - }, "toWireType": function(destructors, o) { - if (elementsLength !== o.length) { - throw new TypeError("Incorrect number of tuple elements for " + reg.name + ": expected=" + elementsLength + ", actual=" + o.length); - } - var ptr = rawConstructor(); - for (var i = 0; i < elementsLength; ++i) { - elements[i].write(ptr, o[i]); - } - if (destructors !== null) { - destructors.push(rawDestructor, ptr); - } - return ptr; - }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: rawDestructor }]; - }); - } - var structRegistrations = {}; - function __embind_finalize_value_object(structType) { - var reg = structRegistrations[structType]; - delete structRegistrations[structType]; - var rawConstructor = reg.rawConstructor; - var rawDestructor = reg.rawDestructor; - var fieldRecords = reg.fields; - var fieldTypes = fieldRecords.map(function(field) { - return field.getterReturnType; - }).concat(fieldRecords.map(function(field) { - return field.setterArgumentType; - })); - whenDependentTypesAreResolved([structType], fieldTypes, function(fieldTypes2) { - var fields = {}; - fieldRecords.forEach(function(field, i) { - var fieldName = field.fieldName; - var getterReturnType = fieldTypes2[i]; - var getter = field.getter; - var getterContext = field.getterContext; - var setterArgumentType = fieldTypes2[i + fieldRecords.length]; - var setter = field.setter; - var setterContext = field.setterContext; - fields[fieldName] = { read: function(ptr) { - return getterReturnType["fromWireType"](getter(getterContext, ptr)); - }, write: function(ptr, o) { - var destructors = []; - setter(setterContext, ptr, setterArgumentType["toWireType"](destructors, o)); - runDestructors(destructors); - } }; - }); - return [{ name: reg.name, "fromWireType": function(ptr) { - var rv = {}; - for (var i in fields) { - rv[i] = fields[i].read(ptr); - } - rawDestructor(ptr); - return rv; - }, "toWireType": function(destructors, o) { - for (var fieldName in fields) { - if (!(fieldName in o)) { - throw new TypeError('Missing field: "' + fieldName + '"'); + + // Iterate each entity's meshes + + for (let meshIndex = firstMeshIndex; meshIndex <= lastMeshIndex; meshIndex++) { + + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + const geometryReuseCount = geometryReuseCounts[geometryIndex]; + const isReusedGeometry = (geometryReuseCount > 1); + + const atLastGeometry = (geometryIndex === (numGeometries - 1)); + + const meshColor = decompressColor$1(eachMeshMaterial.subarray((meshIndex * 6), (meshIndex * 6) + 3)); + const meshOpacity = eachMeshMaterial[(meshIndex * 6) + 3] / 255.0; + const meshMetallic = eachMeshMaterial[(meshIndex * 6) + 4] / 255.0; + const meshRoughness = eachMeshMaterial[(meshIndex * 6) + 5] / 255.0; + + const meshId = nextMeshId++; + + if (isReusedGeometry) { + + // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry + + const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; + const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); + + const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel + + let geometryArrays = geometryArraysCache[geometryId]; + + if (!geometryArrays) { + geometryArrays = { + batchThisMesh: (!options.reuseGeometries) + }; + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + let geometryValid = false; + switch (primitiveType) { + case 0: + geometryArrays.primitiveName = "solid"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + case 1: + geometryArrays.primitiveName = "surface"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + case 2: + geometryArrays.primitiveName = "points"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0); + break; + case 3: + geometryArrays.primitiveName = "lines"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + default: + continue; + } + + if (!geometryValid) { + geometryArrays = null; + } + + if (geometryArrays) { + if (geometryArrays.geometryPositions.length > 1000) ; + if (geometryArrays.batchThisMesh) { + geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length); + geometryArrays.transformedAndRecompressedPositions = new Uint16Array(geometryArrays.geometryPositions.length); + const geometryPositions = geometryArrays.geometryPositions; + const decompressedPositions = geometryArrays.decompressedPositions; + for (let i = 0, len = geometryPositions.length; i < len; i += 3) { + decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12]; + decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13]; + decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14]; + } + geometryArrays.geometryPositions = null; + geometryArraysCache[geometryId] = geometryArrays; + } + } + } + + if (geometryArrays) { + + if (geometryArrays.batchThisMesh) { + + const decompressedPositions = geometryArrays.decompressedPositions; + const transformedAndRecompressedPositions = geometryArrays.transformedAndRecompressedPositions; + + for (let i = 0, len = decompressedPositions.length; i < len; i += 3) { + tempVec4a$1[0] = decompressedPositions[i + 0]; + tempVec4a$1[1] = decompressedPositions[i + 1]; + tempVec4a$1[2] = decompressedPositions[i + 2]; + tempVec4a$1[3] = 1; + math.transformVec4(meshMatrix, tempVec4a$1, tempVec4b$1); + geometryCompressionUtils.compressPosition(tempVec4b$1, rtcAABB, tempVec4a$1); + transformedAndRecompressedPositions[i + 0] = tempVec4a$1[0]; + transformedAndRecompressedPositions[i + 1] = tempVec4a$1[1]; + transformedAndRecompressedPositions[i + 2] = tempVec4a$1[2]; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + origin: tileCenter, + primitive: geometryArrays.primitiveName, + positionsCompressed: transformedAndRecompressedPositions, + normalsCompressed: geometryArrays.geometryNormals, + colorsCompressed: geometryArrays.geometryColors, + indices: geometryArrays.geometryIndices, + edgeIndices: geometryArrays.geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + + } else { + + if (!geometryCreatedInTile[geometryId]) { + + sceneModel.createGeometry({ + id: geometryId, + primitive: geometryArrays.primitiveName, + positionsCompressed: geometryArrays.geometryPositions, + normalsCompressed: geometryArrays.geometryNormals, + colorsCompressed: geometryArrays.geometryColors, + indices: geometryArrays.geometryIndices, + edgeIndices: geometryArrays.geometryEdgeIndices, + positionsDecodeMatrix: reusedGeometriesDecodeMatrix + }); + + geometryCreatedInTile[geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + origin: tileCenter, + matrix: meshMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + } + } + + } else { + + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + + let primitiveName; + let geometryPositions; + let geometryNormals; + let geometryColors; + let geometryIndices; + let geometryEdgeIndices; + let geometryValid = false; + + switch (primitiveType) { + case 0: + primitiveName = "solid"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + case 1: + primitiveName = "surface"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + case 2: + primitiveName = "points"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0); + break; + case 3: + primitiveName = "lines"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + default: + continue; + } + + if (geometryValid) { + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + origin: tileCenter, + primitive: primitiveName, + positionsCompressed: geometryPositions, + normalsCompressed: geometryNormals, + colorsCompressed: geometryColors, + indices: geometryIndices, + edgeIndices: geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + } } - } - var ptr = rawConstructor(); - for (fieldName in fields) { - fields[fieldName].write(ptr, o[fieldName]); - } - if (destructors !== null) { - destructors.push(rawDestructor, ptr); - } - return ptr; - }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: rawDestructor }]; - }); - } - function getShiftFromSize(size) { - switch (size) { - case 1: - return 0; - case 2: - return 1; - case 4: - return 2; - case 8: - return 3; - default: - throw new TypeError("Unknown type size: " + size); - } - } - function embind_init_charCodes() { - var codes = new Array(256); - for (var i = 0; i < 256; ++i) { - codes[i] = String.fromCharCode(i); - } - embind_charCodes = codes; - } - var embind_charCodes = void 0; - function readLatin1String(ptr) { - var ret = ""; - var c = ptr; - while (GROWABLE_HEAP_U8()[c]) { - ret += embind_charCodes[GROWABLE_HEAP_U8()[c++]]; - } - return ret; - } - var BindingError = void 0; - function throwBindingError(message) { - throw new BindingError(message); - } - function registerType(rawType, registeredInstance, options) { - options = options || {}; - if (!("argPackAdvance" in registeredInstance)) { - throw new TypeError("registerType registeredInstance requires argPackAdvance"); - } - var name2 = registeredInstance.name; - if (!rawType) { - throwBindingError('type "' + name2 + '" must have a positive integer typeid pointer'); - } - if (registeredTypes.hasOwnProperty(rawType)) { - if (options.ignoreDuplicateRegistrations) { - return; - } else { - throwBindingError("Cannot register type '" + name2 + "' twice"); } - } - registeredTypes[rawType] = registeredInstance; - delete typeDependencies[rawType]; - if (awaitingDependencies.hasOwnProperty(rawType)) { - var callbacks = awaitingDependencies[rawType]; - delete awaitingDependencies[rawType]; - callbacks.forEach(function(cb) { - cb(); - }); - } + + if (meshIds.length > 0) { + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, + meshIds: meshIds + })); + } } - function __embind_register_bool(rawType, name2, size, trueValue, falseValue) { - var shift = getShiftFromSize(size); - name2 = readLatin1String(name2); - registerType(rawType, { name: name2, "fromWireType": function(wt) { - return !!wt; - }, "toWireType": function(destructors, o) { - return o ? trueValue : falseValue; - }, "argPackAdvance": 8, "readValueFromPointer": function(pointer) { - var heap; - if (size === 1) { - heap = GROWABLE_HEAP_I8(); - } else if (size === 2) { - heap = GROWABLE_HEAP_I16(); - } else if (size === 4) { - heap = GROWABLE_HEAP_I32(); + } +} + +/** @private */ +const ParserV9 = { + version: 9, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract$1(elements); + const inflatedData = inflate$1(deflatedData); + load$1(viewer, options, inflatedData, sceneModel); + } +}; + +/* + Parser for .XKT Format V10 +*/ + +let pako = window.pako || p; +if (!pako.inflate) { // See https://github.com/nodeca/pako/issues/97 + pako = pako.default; +} + +const tempVec4a = math.vec4(); +const tempVec4b = math.vec4(); + +const NUM_TEXTURE_ATTRIBUTES = 9; + +function extract(elements) { + + let i = 0; + + return { + metadata: elements[i++], + textureData: elements[i++], + eachTextureDataPortion: elements[i++], + eachTextureAttributes: elements[i++], + positions: elements[i++], + normals: elements[i++], + colors: elements[i++], + uvs: elements[i++], + indices: elements[i++], + edgeIndices: elements[i++], + eachTextureSetTextures: elements[i++], + matrices: elements[i++], + reusedGeometriesDecodeMatrix: elements[i++], + eachGeometryPrimitiveType: elements[i++], + eachGeometryPositionsPortion: elements[i++], + eachGeometryNormalsPortion: elements[i++], + eachGeometryColorsPortion: elements[i++], + eachGeometryUVsPortion: elements[i++], + eachGeometryIndicesPortion: elements[i++], + eachGeometryEdgeIndicesPortion: elements[i++], + eachMeshGeometriesPortion: elements[i++], + eachMeshMatricesPortion: elements[i++], + eachMeshTextureSet: elements[i++], + eachMeshMaterialAttributes: elements[i++], + eachEntityId: elements[i++], + eachEntityMeshesPortion: elements[i++], + eachTileAABB: elements[i++], + eachTileEntitiesPortion: elements[i++] + }; +} + +function inflate(deflatedData) { + + function inflate(array, options) { + return (array.length === 0) ? [] : pako.inflate(array, options).buffer; + } + + return { + metadata: JSON.parse(pako.inflate(deflatedData.metadata, {to: 'string'})), + textureData: new Uint8Array(inflate(deflatedData.textureData)), // <<----------------------------- ??? ZIPPing to blame? + eachTextureDataPortion: new Uint32Array(inflate(deflatedData.eachTextureDataPortion)), + eachTextureAttributes: new Uint16Array(inflate(deflatedData.eachTextureAttributes)), + positions: new Uint16Array(inflate(deflatedData.positions)), + normals: new Int8Array(inflate(deflatedData.normals)), + colors: new Uint8Array(inflate(deflatedData.colors)), + uvs: new Float32Array(inflate(deflatedData.uvs)), + indices: new Uint32Array(inflate(deflatedData.indices)), + edgeIndices: new Uint32Array(inflate(deflatedData.edgeIndices)), + eachTextureSetTextures: new Int32Array(inflate(deflatedData.eachTextureSetTextures)), + matrices: new Float32Array(inflate(deflatedData.matrices)), + reusedGeometriesDecodeMatrix: new Float32Array(inflate(deflatedData.reusedGeometriesDecodeMatrix)), + eachGeometryPrimitiveType: new Uint8Array(inflate(deflatedData.eachGeometryPrimitiveType)), + eachGeometryPositionsPortion: new Uint32Array(inflate(deflatedData.eachGeometryPositionsPortion)), + eachGeometryNormalsPortion: new Uint32Array(inflate(deflatedData.eachGeometryNormalsPortion)), + eachGeometryColorsPortion: new Uint32Array(inflate(deflatedData.eachGeometryColorsPortion)), + eachGeometryUVsPortion: new Uint32Array(inflate(deflatedData.eachGeometryUVsPortion)), + eachGeometryIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryIndicesPortion)), + eachGeometryEdgeIndicesPortion: new Uint32Array(inflate(deflatedData.eachGeometryEdgeIndicesPortion)), + eachMeshGeometriesPortion: new Uint32Array(inflate(deflatedData.eachMeshGeometriesPortion)), + eachMeshMatricesPortion: new Uint32Array(inflate(deflatedData.eachMeshMatricesPortion)), + eachMeshTextureSet: new Int32Array(inflate(deflatedData.eachMeshTextureSet)), // Can be -1 + eachMeshMaterialAttributes: new Uint8Array(inflate(deflatedData.eachMeshMaterialAttributes)), + eachEntityId: JSON.parse(pako.inflate(deflatedData.eachEntityId, {to: 'string'})), + eachEntityMeshesPortion: new Uint32Array(inflate(deflatedData.eachEntityMeshesPortion)), + eachTileAABB: new Float64Array(inflate(deflatedData.eachTileAABB)), + eachTileEntitiesPortion: new Uint32Array(inflate(deflatedData.eachTileEntitiesPortion)), + }; +} + +const decompressColor = (function () { + const floatColor = new Float32Array(3); + return function (intColor) { + floatColor[0] = intColor[0] / 255.0; + floatColor[1] = intColor[1] / 255.0; + floatColor[2] = intColor[2] / 255.0; + return floatColor; + }; +})(); + +((function () { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + return function (imagedata) { + canvas.width = imagedata.width; + canvas.height = imagedata.height; + context.putImageData(imagedata, 0, 0); + return canvas.toDataURL(); + }; +}))(); + +function load(viewer, options, inflatedData, sceneModel) { + + const metadata = inflatedData.metadata; + const textureData = inflatedData.textureData; + const eachTextureDataPortion = inflatedData.eachTextureDataPortion; + const eachTextureAttributes = inflatedData.eachTextureAttributes; + const positions = inflatedData.positions; + const normals = inflatedData.normals; + const colors = inflatedData.colors; + const uvs = inflatedData.uvs; + const indices = inflatedData.indices; + const edgeIndices = inflatedData.edgeIndices; + const eachTextureSetTextures = inflatedData.eachTextureSetTextures; + const matrices = inflatedData.matrices; + const reusedGeometriesDecodeMatrix = inflatedData.reusedGeometriesDecodeMatrix; + const eachGeometryPrimitiveType = inflatedData.eachGeometryPrimitiveType; + const eachGeometryPositionsPortion = inflatedData.eachGeometryPositionsPortion; + const eachGeometryNormalsPortion = inflatedData.eachGeometryNormalsPortion; + const eachGeometryColorsPortion = inflatedData.eachGeometryColorsPortion; + const eachGeometryUVsPortion = inflatedData.eachGeometryUVsPortion; + const eachGeometryIndicesPortion = inflatedData.eachGeometryIndicesPortion; + const eachGeometryEdgeIndicesPortion = inflatedData.eachGeometryEdgeIndicesPortion; + const eachMeshGeometriesPortion = inflatedData.eachMeshGeometriesPortion; + const eachMeshMatricesPortion = inflatedData.eachMeshMatricesPortion; + const eachMeshTextureSet = inflatedData.eachMeshTextureSet; + const eachMeshMaterialAttributes = inflatedData.eachMeshMaterialAttributes; + const eachEntityId = inflatedData.eachEntityId; + const eachEntityMeshesPortion = inflatedData.eachEntityMeshesPortion; + const eachTileAABB = inflatedData.eachTileAABB; + const eachTileEntitiesPortion = inflatedData.eachTileEntitiesPortion; + + const numTextures = eachTextureDataPortion.length; + const numTextureSets = eachTextureSetTextures.length / 5; + const numGeometries = eachGeometryPositionsPortion.length; + const numMeshes = eachMeshGeometriesPortion.length; + const numEntities = eachEntityMeshesPortion.length; + const numTiles = eachTileEntitiesPortion.length; + + let nextMeshId = 0; + + // Create metamodel, unless already loaded from external JSON file by XKTLoaderPlugin + + const metaModelId = sceneModel.id; + + if (!viewer.metaScene.metaModels[metaModelId]) { + + viewer.metaScene.createMetaModel(metaModelId, metadata, { + includeTypes: options.includeTypes, + excludeTypes: options.excludeTypes, + globalizeObjectIds: options.globalizeObjectIds + }); + + sceneModel.once("destroyed", () => { + viewer.metaScene.destroyMetaModel(metaModelId); + }); + } + + // Create textures + + for (let textureIndex = 0; textureIndex < numTextures; textureIndex++) { + const atLastTexture = (textureIndex === (numTextures - 1)); + const textureDataPortionStart = eachTextureDataPortion[textureIndex]; + const textureDataPortionEnd = atLastTexture ? textureData.length : (eachTextureDataPortion[textureIndex + 1]); + + const textureDataPortionSize = textureDataPortionEnd - textureDataPortionStart; + const textureDataPortionExists = (textureDataPortionSize > 0); + + const textureAttrBaseIdx = (textureIndex * NUM_TEXTURE_ATTRIBUTES); + + const compressed = (eachTextureAttributes[textureAttrBaseIdx + 0] === 1); + const mediaType = eachTextureAttributes[textureAttrBaseIdx + 1]; + eachTextureAttributes[textureAttrBaseIdx + 2]; + eachTextureAttributes[textureAttrBaseIdx + 3]; + const minFilter = eachTextureAttributes[textureAttrBaseIdx + 4]; + const magFilter = eachTextureAttributes[textureAttrBaseIdx + 5]; // LinearFilter | NearestFilter + const wrapS = eachTextureAttributes[textureAttrBaseIdx + 6]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping + const wrapT = eachTextureAttributes[textureAttrBaseIdx + 7]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping + const wrapR = eachTextureAttributes[textureAttrBaseIdx + 8]; // ClampToEdgeWrapping | MirroredRepeatWrapping | RepeatWrapping + + if (textureDataPortionExists) { + + const imageDataSubarray = new Uint8Array(textureData.subarray(textureDataPortionStart, textureDataPortionEnd)); + const arrayBuffer = imageDataSubarray.buffer; + const textureId = `texture-${textureIndex}`; + + if (compressed) { + + sceneModel.createTexture({ + id: textureId, + buffers: [arrayBuffer], + minFilter, + magFilter, + wrapS, + wrapT, + wrapR + }); + } else { - throw new TypeError("Unknown boolean type size: " + name2); + + const mimeType = mediaType === JPEGMediaType ? "image/jpeg" : (mediaType === PNGMediaType ? "image/png" : "image/gif"); + const blob = new Blob([arrayBuffer], {type: mimeType}); + const urlCreator = window.URL || window.webkitURL; + const imageUrl = urlCreator.createObjectURL(blob); + const img = document.createElement('img'); + img.src = imageUrl; + + sceneModel.createTexture({ + id: textureId, + image: img, + //mediaType, + minFilter, + magFilter, + wrapS, + wrapT, + wrapR + }); } - return this["fromWireType"](heap[pointer >>> shift]); - }, destructorFunction: null }); - } - function ClassHandle_isAliasOf(other) { - if (!(this instanceof ClassHandle)) { - return false; - } - if (!(other instanceof ClassHandle)) { - return false; - } - var leftClass = this.$$.ptrType.registeredClass; - var left = this.$$.ptr; - var rightClass = other.$$.ptrType.registeredClass; - var right = other.$$.ptr; - while (leftClass.baseClass) { - left = leftClass.upcast(left); - leftClass = leftClass.baseClass; - } - while (rightClass.baseClass) { - right = rightClass.upcast(right); - rightClass = rightClass.baseClass; - } - return leftClass === rightClass && left === right; - } - function shallowCopyInternalPointer(o) { - return { count: o.count, deleteScheduled: o.deleteScheduled, preservePointerOnDelete: o.preservePointerOnDelete, ptr: o.ptr, ptrType: o.ptrType, smartPtr: o.smartPtr, smartPtrType: o.smartPtrType }; - } - function throwInstanceAlreadyDeleted(obj) { - function getInstanceTypeName(handle) { - return handle.$$.ptrType.registeredClass.name; - } - throwBindingError(getInstanceTypeName(obj) + " instance already deleted"); - } - var finalizationGroup = false; - function detachFinalizer(handle) { } - function runDestructor($$) { - if ($$.smartPtr) { - $$.smartPtrType.rawDestructor($$.smartPtr); - } else { - $$.ptrType.registeredClass.rawDestructor($$.ptr); - } - } - function releaseClassHandle($$) { - $$.count.value -= 1; - var toDelete = $$.count.value === 0; - if (toDelete) { - runDestructor($$); - } - } - function attachFinalizer(handle) { - if (typeof FinalizationGroup === "undefined") { - attachFinalizer = function(handle2) { - return handle2; - }; - return handle; - } - finalizationGroup = new FinalizationGroup(function(iter) { - for (var result = iter.next(); !result.done; result = iter.next()) { - var $$ = result.value; - if (!$$.ptr) { - console.warn("object already deleted: " + $$.ptr); - } else { - releaseClassHandle($$); - } - } - }); - attachFinalizer = function(handle2) { - finalizationGroup.register(handle2, handle2.$$, handle2.$$); - return handle2; - }; - detachFinalizer = function(handle2) { - finalizationGroup.unregister(handle2.$$); - }; - return attachFinalizer(handle); - } - function ClassHandle_clone() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - if (this.$$.preservePointerOnDelete) { - this.$$.count.value += 1; - return this; - } else { - var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { $$: { value: shallowCopyInternalPointer(this.$$) } })); - clone.$$.count.value += 1; - clone.$$.deleteScheduled = false; - return clone; - } - } - function ClassHandle_delete() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { - throwBindingError("Object already scheduled for deletion"); - } - detachFinalizer(this); - releaseClassHandle(this.$$); - if (!this.$$.preservePointerOnDelete) { - this.$$.smartPtr = void 0; - this.$$.ptr = void 0; - } - } - function ClassHandle_isDeleted() { - return !this.$$.ptr; - } - var delayFunction = void 0; - var deletionQueue = []; - function flushPendingDeletes() { - while (deletionQueue.length) { - var obj = deletionQueue.pop(); - obj.$$.deleteScheduled = false; - obj["delete"](); - } - } - function ClassHandle_deleteLater() { - if (!this.$$.ptr) { - throwInstanceAlreadyDeleted(this); - } - if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { - throwBindingError("Object already scheduled for deletion"); - } - deletionQueue.push(this); - if (deletionQueue.length === 1 && delayFunction) { - delayFunction(flushPendingDeletes); - } - this.$$.deleteScheduled = true; - return this; - } - function init_ClassHandle() { - ClassHandle.prototype["isAliasOf"] = ClassHandle_isAliasOf; - ClassHandle.prototype["clone"] = ClassHandle_clone; - ClassHandle.prototype["delete"] = ClassHandle_delete; - ClassHandle.prototype["isDeleted"] = ClassHandle_isDeleted; - ClassHandle.prototype["deleteLater"] = ClassHandle_deleteLater; - } - function ClassHandle() { - } - var registeredPointers = {}; - function ensureOverloadTable(proto, methodName, humanName) { - if (proto[methodName].overloadTable === void 0) { - var prevFunc = proto[methodName]; - proto[methodName] = function() { - if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); - } - return proto[methodName].overloadTable[arguments.length].apply(this, arguments); - }; - proto[methodName].overloadTable = []; - proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; - } - } - function exposePublicSymbol(name2, value, numArguments) { - if (Module.hasOwnProperty(name2)) { - if (numArguments === void 0 || Module[name2].overloadTable !== void 0 && Module[name2].overloadTable[numArguments] !== void 0) { - throwBindingError("Cannot register public name '" + name2 + "' twice"); - } - ensureOverloadTable(Module, name2, name2); - if (Module.hasOwnProperty(numArguments)) { - throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); - } - Module[name2].overloadTable[numArguments] = value; - } else { - Module[name2] = value; - if (numArguments !== void 0) { - Module[name2].numArguments = numArguments; - } - } - } - function RegisteredClass(name2, constructor, instancePrototype, rawDestructor, baseClass, getActualType, upcast, downcast) { - this.name = name2; - this.constructor = constructor; - this.instancePrototype = instancePrototype; - this.rawDestructor = rawDestructor; - this.baseClass = baseClass; - this.getActualType = getActualType; - this.upcast = upcast; - this.downcast = downcast; - this.pureVirtualFunctions = []; - } - function upcastPointer(ptr, ptrClass, desiredClass) { - while (ptrClass !== desiredClass) { - if (!ptrClass.upcast) { - throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); - } - ptr = ptrClass.upcast(ptr); - ptrClass = ptrClass.baseClass; - } - return ptr; - } - function constNoSmartPtrRawPointerToWireType(destructors, handle) { - if (handle === null) { - if (this.isReference) { - throwBindingError("null is not a valid " + this.name); - } - return 0; - } - if (!handle.$$) { - throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); - } - if (!handle.$$.ptr) { - throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); - } - var handleClass = handle.$$.ptrType.registeredClass; - var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - return ptr; + } + + // Create texture sets + + for (let textureSetIndex = 0; textureSetIndex < numTextureSets; textureSetIndex++) { + const eachTextureSetTexturesIndex = textureSetIndex * 5; + const textureSetId = `textureSet-${textureSetIndex}`; + const colorTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 0]; + const metallicRoughnessTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 1]; + const normalsTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 2]; + const emissiveTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 3]; + const occlusionTextureIndex = eachTextureSetTextures[eachTextureSetTexturesIndex + 4]; + sceneModel.createTextureSet({ + id: textureSetId, + colorTextureId: colorTextureIndex >= 0 ? `texture-${colorTextureIndex}` : null, + normalsTextureId: normalsTextureIndex >= 0 ? `texture-${normalsTextureIndex}` : null, + metallicRoughnessTextureId: metallicRoughnessTextureIndex >= 0 ? `texture-${metallicRoughnessTextureIndex}` : null, + emissiveTextureId: emissiveTextureIndex >= 0 ? `texture-${emissiveTextureIndex}` : null, + occlusionTextureId: occlusionTextureIndex >= 0 ? `texture-${occlusionTextureIndex}` : null + }); + } + + // Count instances of each geometry + + const geometryReuseCounts = new Uint32Array(numGeometries); + + for (let meshIndex = 0; meshIndex < numMeshes; meshIndex++) { + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + if (geometryReuseCounts[geometryIndex] !== undefined) { + geometryReuseCounts[geometryIndex]++; + } else { + geometryReuseCounts[geometryIndex] = 1; } - function genericPointerToWireType(destructors, handle) { - var ptr; - if (handle === null) { - if (this.isReference) { - throwBindingError("null is not a valid " + this.name); - } - if (this.isSmartPointer) { - ptr = this.rawConstructor(); - if (destructors !== null) { - destructors.push(this.rawDestructor, ptr); - } - return ptr; - } else { - return 0; - } - } - if (!handle.$$) { - throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); - } - if (!handle.$$.ptr) { - throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); - } - if (!this.isConst && handle.$$.ptrType.isConst) { - throwBindingError("Cannot convert argument of type " + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + " to parameter type " + this.name); - } - var handleClass = handle.$$.ptrType.registeredClass; - ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - if (this.isSmartPointer) { - if (handle.$$.smartPtr === void 0) { - throwBindingError("Passing raw pointer to smart pointer is illegal"); - } - switch (this.sharingPolicy) { - case 0: - if (handle.$$.smartPtrType === this) { - ptr = handle.$$.smartPtr; - } else { - throwBindingError("Cannot convert argument of type " + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + " to parameter type " + this.name); + } + + // Iterate over tiles + + const tileCenter = math.vec3(); + const rtcAABB = math.AABB3(); + + const geometryArraysCache = {}; + + for (let tileIndex = 0; tileIndex < numTiles; tileIndex++) { + + const lastTileIndex = (numTiles - 1); + + const atLastTile = (tileIndex === lastTileIndex); + + const firstTileEntityIndex = eachTileEntitiesPortion [tileIndex]; + const lastTileEntityIndex = atLastTile ? (numEntities - 1) : (eachTileEntitiesPortion[tileIndex + 1] - 1); + + const tileAABBIndex = tileIndex * 6; + const tileAABB = eachTileAABB.subarray(tileAABBIndex, tileAABBIndex + 6); + + math.getAABB3Center(tileAABB, tileCenter); + + rtcAABB[0] = tileAABB[0] - tileCenter[0]; + rtcAABB[1] = tileAABB[1] - tileCenter[1]; + rtcAABB[2] = tileAABB[2] - tileCenter[2]; + rtcAABB[3] = tileAABB[3] - tileCenter[0]; + rtcAABB[4] = tileAABB[4] - tileCenter[1]; + rtcAABB[5] = tileAABB[5] - tileCenter[2]; + + const tileDecodeMatrix = geometryCompressionUtils.createPositionsDecodeMatrix(rtcAABB); + + const geometryCreatedInTile = {}; + + // Iterate over each tile's entities + + for (let tileEntityIndex = firstTileEntityIndex; tileEntityIndex <= lastTileEntityIndex; tileEntityIndex++) { + + const xktEntityId = eachEntityId[tileEntityIndex]; + + const entityId = options.globalizeObjectIds ? math.globalizeObjectId(sceneModel.id, xktEntityId) : xktEntityId; + + const finalTileEntityIndex = (numEntities - 1); + const atLastTileEntity = (tileEntityIndex === finalTileEntityIndex); + const firstMeshIndex = eachEntityMeshesPortion [tileEntityIndex]; + const lastMeshIndex = atLastTileEntity ? (eachMeshGeometriesPortion.length - 1) : (eachEntityMeshesPortion[tileEntityIndex + 1] - 1); + + const meshIds = []; + + const metaObject = viewer.metaScene.metaObjects[entityId]; + const entityDefaults = {}; + const meshDefaults = {}; + + if (metaObject) { + + // Mask loading of object types + + if (options.excludeTypesMap && metaObject.type && options.excludeTypesMap[metaObject.type]) { + continue; } - break; - case 1: - ptr = handle.$$.smartPtr; - break; - case 2: - if (handle.$$.smartPtrType === this) { - ptr = handle.$$.smartPtr; - } else { - var clonedHandle = handle["clone"](); - ptr = this.rawShare(ptr, __emval_register(function() { - clonedHandle["delete"](); - })); - if (destructors !== null) { - destructors.push(this.rawDestructor, ptr); - } + + if (options.includeTypesMap && metaObject.type && (!options.includeTypesMap[metaObject.type])) { + continue; } - break; - default: - throwBindingError("Unsupporting sharing policy"); - } - } - return ptr; - } - function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) { - if (handle === null) { - if (this.isReference) { - throwBindingError("null is not a valid " + this.name); - } - return 0; - } - if (!handle.$$) { - throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); - } - if (!handle.$$.ptr) { - throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); - } - if (handle.$$.ptrType.isConst) { - throwBindingError("Cannot convert argument of type " + handle.$$.ptrType.name + " to parameter type " + this.name); - } - var handleClass = handle.$$.ptrType.registeredClass; - var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); - return ptr; - } - function RegisteredPointer_getPointee(ptr) { - if (this.rawGetPointee) { - ptr = this.rawGetPointee(ptr); - } - return ptr; - } - function RegisteredPointer_destructor(ptr) { - if (this.rawDestructor) { - this.rawDestructor(ptr); - } - } - function RegisteredPointer_deleteObject(handle) { - if (handle !== null) { - handle["delete"](); - } - } - function downcastPointer(ptr, ptrClass, desiredClass) { - if (ptrClass === desiredClass) { - return ptr; - } - if (desiredClass.baseClass === void 0) { - return null; - } - var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); - if (rv === null) { - return null; - } - return desiredClass.downcast(rv); - } - function getInheritedInstanceCount() { - return Object.keys(registeredInstances).length; - } - function getLiveInheritedInstances() { - var rv = []; - for (var k in registeredInstances) { - if (registeredInstances.hasOwnProperty(k)) { - rv.push(registeredInstances[k]); - } - } - return rv; - } - function setDelayFunction(fn) { - delayFunction = fn; - if (deletionQueue.length && delayFunction) { - delayFunction(flushPendingDeletes); - } - } - function init_embind() { - Module["getInheritedInstanceCount"] = getInheritedInstanceCount; - Module["getLiveInheritedInstances"] = getLiveInheritedInstances; - Module["flushPendingDeletes"] = flushPendingDeletes; - Module["setDelayFunction"] = setDelayFunction; - } - var registeredInstances = {}; - function getBasestPointer(class_, ptr) { - if (ptr === void 0) { - throwBindingError("ptr should not be undefined"); - } - while (class_.baseClass) { - ptr = class_.upcast(ptr); - class_ = class_.baseClass; - } - return ptr; - } - function getInheritedInstance(class_, ptr) { - ptr = getBasestPointer(class_, ptr); - return registeredInstances[ptr]; - } - function makeClassHandle(prototype, record) { - if (!record.ptrType || !record.ptr) { - throwInternalError("makeClassHandle requires ptr and ptrType"); - } - var hasSmartPtrType = !!record.smartPtrType; - var hasSmartPtr = !!record.smartPtr; - if (hasSmartPtrType !== hasSmartPtr) { - throwInternalError("Both smartPtrType and smartPtr must be specified"); - } - record.count = { value: 1 }; - return attachFinalizer(Object.create(prototype, { $$: { value: record } })); - } - function RegisteredPointer_fromWireType(ptr) { - var rawPointer = this.getPointee(ptr); - if (!rawPointer) { - this.destructor(ptr); - return null; - } - var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer); - if (registeredInstance !== void 0) { - if (registeredInstance.$$.count.value === 0) { - registeredInstance.$$.ptr = rawPointer; - registeredInstance.$$.smartPtr = ptr; - return registeredInstance["clone"](); - } else { - var rv = registeredInstance["clone"](); - this.destructor(ptr); - return rv; - } - } - function makeDefaultHandle() { - if (this.isSmartPointer) { - return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this.pointeeType, ptr: rawPointer, smartPtrType: this, smartPtr: ptr }); - } else { - return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this, ptr }); - } - } - var actualType = this.registeredClass.getActualType(rawPointer); - var registeredPointerRecord = registeredPointers[actualType]; - if (!registeredPointerRecord) { - return makeDefaultHandle.call(this); - } - var toType; - if (this.isConst) { - toType = registeredPointerRecord.constPointerType; - } else { - toType = registeredPointerRecord.pointerType; - } - var dp = downcastPointer(rawPointer, this.registeredClass, toType.registeredClass); - if (dp === null) { - return makeDefaultHandle.call(this); - } - if (this.isSmartPointer) { - return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp, smartPtrType: this, smartPtr: ptr }); - } else { - return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp }); - } - } - function init_RegisteredPointer() { - RegisteredPointer.prototype.getPointee = RegisteredPointer_getPointee; - RegisteredPointer.prototype.destructor = RegisteredPointer_destructor; - RegisteredPointer.prototype["argPackAdvance"] = 8; - RegisteredPointer.prototype["readValueFromPointer"] = simpleReadValueFromPointer; - RegisteredPointer.prototype["deleteObject"] = RegisteredPointer_deleteObject; - RegisteredPointer.prototype["fromWireType"] = RegisteredPointer_fromWireType; - } - function RegisteredPointer(name2, registeredClass, isReference, isConst, isSmartPointer, pointeeType, sharingPolicy, rawGetPointee, rawConstructor, rawShare, rawDestructor) { - this.name = name2; - this.registeredClass = registeredClass; - this.isReference = isReference; - this.isConst = isConst; - this.isSmartPointer = isSmartPointer; - this.pointeeType = pointeeType; - this.sharingPolicy = sharingPolicy; - this.rawGetPointee = rawGetPointee; - this.rawConstructor = rawConstructor; - this.rawShare = rawShare; - this.rawDestructor = rawDestructor; - if (!isSmartPointer && registeredClass.baseClass === void 0) { - if (isConst) { - this["toWireType"] = constNoSmartPtrRawPointerToWireType; - this.destructorFunction = null; - } else { - this["toWireType"] = nonConstNoSmartPtrRawPointerToWireType; - this.destructorFunction = null; - } - } else { - this["toWireType"] = genericPointerToWireType; - } - } - function replacePublicSymbol(name2, value, numArguments) { - if (!Module.hasOwnProperty(name2)) { - throwInternalError("Replacing nonexistant public symbol"); - } - if (Module[name2].overloadTable !== void 0 && numArguments !== void 0) { - Module[name2].overloadTable[numArguments] = value; - } else { - Module[name2] = value; - Module[name2].argCount = numArguments; - } - } - function getDynCaller(sig, ptr) { - assert(sig.indexOf("j") >= 0, "getDynCaller should only be called with i64 sigs"); - var argCache = []; - return function() { - argCache.length = arguments.length; - for (var i = 0; i < arguments.length; i++) { - argCache[i] = arguments[i]; - } - return dynCall(sig, ptr, argCache); - }; - } - function embind__requireFunction(signature, rawFunction) { - signature = readLatin1String(signature); - function makeDynCaller() { - if (signature.indexOf("j") != -1) { - return getDynCaller(signature, rawFunction); - } - return wasmTable.get(rawFunction); - } - var fp = makeDynCaller(); - if (typeof fp !== "function") { - throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); - } - return fp; - } - var UnboundTypeError = void 0; - function getTypeName(type) { - var ptr = ___getTypeName(type); - var rv = readLatin1String(ptr); - _free(ptr); - return rv; - } - function throwUnboundTypeError(message, types) { - var unboundTypes = []; - var seen = {}; - function visit(type) { - if (seen[type]) { - return; - } - if (registeredTypes[type]) { - return; - } - if (typeDependencies[type]) { - typeDependencies[type].forEach(visit); - return; - } - unboundTypes.push(type); - seen[type] = true; - } - types.forEach(visit); - throw new UnboundTypeError(message + ": " + unboundTypes.map(getTypeName).join([", "])); - } - function __embind_register_class(rawType, rawPointerType, rawConstPointerType, baseClassRawType, getActualTypeSignature, getActualType, upcastSignature, upcast, downcastSignature, downcast, name2, destructorSignature, rawDestructor) { - name2 = readLatin1String(name2); - getActualType = embind__requireFunction(getActualTypeSignature, getActualType); - if (upcast) { - upcast = embind__requireFunction(upcastSignature, upcast); - } - if (downcast) { - downcast = embind__requireFunction(downcastSignature, downcast); - } - rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); - var legalFunctionName = makeLegalFunctionName(name2); - exposePublicSymbol(legalFunctionName, function() { - throwUnboundTypeError("Cannot construct " + name2 + " due to unbound types", [baseClassRawType]); - }); - whenDependentTypesAreResolved([rawType, rawPointerType, rawConstPointerType], baseClassRawType ? [baseClassRawType] : [], function(base) { - base = base[0]; - var baseClass; - var basePrototype; - if (baseClassRawType) { - baseClass = base.registeredClass; - basePrototype = baseClass.instancePrototype; - } else { - basePrototype = ClassHandle.prototype; - } - var constructor = createNamedFunction(legalFunctionName, function() { - if (Object.getPrototypeOf(this) !== instancePrototype) { - throw new BindingError("Use 'new' to construct " + name2); - } - if (registeredClass.constructor_body === void 0) { - throw new BindingError(name2 + " has no accessible constructor"); - } - var body = registeredClass.constructor_body[arguments.length]; - if (body === void 0) { - throw new BindingError("Tried to invoke ctor of " + name2 + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); - } - return body.apply(this, arguments); - }); - var instancePrototype = Object.create(basePrototype, { constructor: { value: constructor } }); - constructor.prototype = instancePrototype; - var registeredClass = new RegisteredClass(name2, constructor, instancePrototype, rawDestructor, baseClass, getActualType, upcast, downcast); - var referenceConverter = new RegisteredPointer(name2, registeredClass, true, false, false); - var pointerConverter = new RegisteredPointer(name2 + "*", registeredClass, false, false, false); - var constPointerConverter = new RegisteredPointer(name2 + " const*", registeredClass, false, true, false); - registeredPointers[rawType] = { pointerType: pointerConverter, constPointerType: constPointerConverter }; - replacePublicSymbol(legalFunctionName, constructor); - return [referenceConverter, pointerConverter, constPointerConverter]; - }); - } - function heap32VectorToArray(count, firstElement) { - var array = []; - for (var i = 0; i < count; i++) { - array.push(GROWABLE_HEAP_I32()[(firstElement >> 2) + i]); - } - return array; - } - function __embind_register_class_constructor(rawClassType, argCount, rawArgTypesAddr, invokerSignature, invoker, rawConstructor) { - assert(argCount > 0); - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - invoker = embind__requireFunction(invokerSignature, invoker); - var args = [rawConstructor]; - var destructors = []; - whenDependentTypesAreResolved([], [rawClassType], function(classType) { - classType = classType[0]; - var humanName = "constructor " + classType.name; - if (classType.registeredClass.constructor_body === void 0) { - classType.registeredClass.constructor_body = []; - } - if (classType.registeredClass.constructor_body[argCount - 1] !== void 0) { - throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount - 1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); - } - classType.registeredClass.constructor_body[argCount - 1] = function unboundTypeHandler() { - throwUnboundTypeError("Cannot construct " + classType.name + " due to unbound types", rawArgTypes); - }; - whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - classType.registeredClass.constructor_body[argCount - 1] = function constructor_body() { - if (arguments.length !== argCount - 1) { - throwBindingError(humanName + " called with " + arguments.length + " arguments, expected " + (argCount - 1)); + + // Get initial property values for object types + + const props = options.objectDefaults ? options.objectDefaults[metaObject.type] || options.objectDefaults["DEFAULT"] : null; + + if (props) { + if (props.visible === false) { + entityDefaults.visible = false; + } + if (props.pickable === false) { + entityDefaults.pickable = false; + } + if (props.colorize) { + meshDefaults.color = props.colorize; + } + if (props.opacity !== undefined && props.opacity !== null) { + meshDefaults.opacity = props.opacity; + } + if (props.metallic !== undefined && props.metallic !== null) { + meshDefaults.metallic = props.metallic; + } + if (props.roughness !== undefined && props.roughness !== null) { + meshDefaults.roughness = props.roughness; + } } - destructors.length = 0; - args.length = argCount; - for (var i = 1; i < argCount; ++i) { - args[i] = argTypes[i]["toWireType"](destructors, arguments[i - 1]); + + } else { + if (options.excludeUnclassifiedObjects) { + continue; } - var ptr = invoker.apply(null, args); - runDestructors(destructors); - return argTypes[0]["fromWireType"](ptr); - }; - return []; - }); - return []; - }); - } - function new_(constructor, argumentList) { - if (!(constructor instanceof Function)) { - throw new TypeError("new_ called with constructor type " + typeof constructor + " which is not a function"); - } - var dummy = createNamedFunction(constructor.name || "unknownFunctionName", function() { - }); - dummy.prototype = constructor.prototype; - var obj = new dummy(); - var r = constructor.apply(obj, argumentList); - return r instanceof Object ? r : obj; - } - function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { - var argCount = argTypes.length; - if (argCount < 2) { - throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); - } - var isClassMethodFunc = argTypes[1] !== null && classType !== null; - var needsDestructorStack = false; - for (var i = 1; i < argTypes.length; ++i) { - if (argTypes[i] !== null && argTypes[i].destructorFunction === void 0) { - needsDestructorStack = true; - break; - } - } - var returns = argTypes[0].name !== "void"; - var argsList = ""; - var argsListWired = ""; - for (var i = 0; i < argCount - 2; ++i) { - argsList += (i !== 0 ? ", " : "") + "arg" + i; - argsListWired += (i !== 0 ? ", " : "") + "arg" + i + "Wired"; - } - var invokerFnBody = "return function " + makeLegalFunctionName(humanName) + "(" + argsList + ") {\nif (arguments.length !== " + (argCount - 2) + ") {\nthrowBindingError('function " + humanName + " called with ' + arguments.length + ' arguments, expected " + (argCount - 2) + " args!');\n}\n"; - if (needsDestructorStack) { - invokerFnBody += "var destructors = [];\n"; - } - var dtorStack = needsDestructorStack ? "destructors" : "null"; - var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; - var args2 = [throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; - if (isClassMethodFunc) { - invokerFnBody += "var thisWired = classParam.toWireType(" + dtorStack + ", this);\n"; - } - for (var i = 0; i < argCount - 2; ++i) { - invokerFnBody += "var arg" + i + "Wired = argType" + i + ".toWireType(" + dtorStack + ", arg" + i + "); // " + argTypes[i + 2].name + "\n"; - args1.push("argType" + i); - args2.push(argTypes[i + 2]); - } - if (isClassMethodFunc) { - argsListWired = "thisWired" + (argsListWired.length > 0 ? ", " : "") + argsListWired; - } - invokerFnBody += (returns ? "var rv = " : "") + "invoker(fn" + (argsListWired.length > 0 ? ", " : "") + argsListWired + ");\n"; - if (needsDestructorStack) { - invokerFnBody += "runDestructors(destructors);\n"; - } else { - for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; ++i) { - var paramName = i === 1 ? "thisWired" : "arg" + (i - 2) + "Wired"; - if (argTypes[i].destructorFunction !== null) { - invokerFnBody += paramName + "_dtor(" + paramName + "); // " + argTypes[i].name + "\n"; - args1.push(paramName + "_dtor"); - args2.push(argTypes[i].destructorFunction); - } - } - } - if (returns) { - invokerFnBody += "var ret = retType.fromWireType(rv);\nreturn ret;\n"; - } - invokerFnBody += "}\n"; - args1.push(invokerFnBody); - var invokerFunction = new_(Function, args1).apply(null, args2); - return invokerFunction; - } - function __embind_register_class_function(rawClassType, methodName, argCount, rawArgTypesAddr, invokerSignature, rawInvoker, context, isPureVirtual) { - var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - methodName = readLatin1String(methodName); - rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); - whenDependentTypesAreResolved([], [rawClassType], function(classType) { - classType = classType[0]; - var humanName = classType.name + "." + methodName; - if (isPureVirtual) { - classType.registeredClass.pureVirtualFunctions.push(methodName); } - function unboundTypesHandler() { - throwUnboundTypeError("Cannot call " + humanName + " due to unbound types", rawArgTypes); + + // Iterate each entity's meshes + + for (let meshIndex = firstMeshIndex; meshIndex <= lastMeshIndex; meshIndex++) { + + const geometryIndex = eachMeshGeometriesPortion[meshIndex]; + const geometryReuseCount = geometryReuseCounts[geometryIndex]; + const isReusedGeometry = (geometryReuseCount > 1); + + const atLastGeometry = (geometryIndex === (numGeometries - 1)); + + const textureSetIndex = eachMeshTextureSet[meshIndex]; + + const textureSetId = (textureSetIndex >= 0) ? `textureSet-${textureSetIndex}` : null; + + const meshColor = decompressColor(eachMeshMaterialAttributes.subarray((meshIndex * 6), (meshIndex * 6) + 3)); + const meshOpacity = eachMeshMaterialAttributes[(meshIndex * 6) + 3] / 255.0; + const meshMetallic = eachMeshMaterialAttributes[(meshIndex * 6) + 4] / 255.0; + const meshRoughness = eachMeshMaterialAttributes[(meshIndex * 6) + 5] / 255.0; + + const meshId = nextMeshId++; + + if (isReusedGeometry) { + + // Create mesh for multi-use geometry - create (or reuse) geometry, create mesh using that geometry + + const meshMatrixIndex = eachMeshMatricesPortion[meshIndex]; + const meshMatrix = matrices.slice(meshMatrixIndex, meshMatrixIndex + 16); + + const geometryId = "geometry." + tileIndex + "." + geometryIndex; // These IDs are local to the VBOSceneModel + + let geometryArrays = geometryArraysCache[geometryId]; + + if (!geometryArrays) { + geometryArrays = { + batchThisMesh: (!options.reuseGeometries) + }; + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + let geometryValid = false; + switch (primitiveType) { + case 0: + geometryArrays.primitiveName = "solid"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + case 1: + geometryArrays.primitiveName = "surface"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryArrays.geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryArrays.geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + case 2: + geometryArrays.primitiveName = "points"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0); + break; + case 3: + geometryArrays.primitiveName = "lines"; + geometryArrays.geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryArrays.geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryArrays.geometryPositions.length > 0 && geometryArrays.geometryIndices.length > 0); + break; + default: + continue; + } + + if (!geometryValid) { + geometryArrays = null; + } + + if (geometryArrays) { + if (geometryArrays.geometryPositions.length > 1000) ; + if (geometryArrays.batchThisMesh) { + geometryArrays.decompressedPositions = new Float32Array(geometryArrays.geometryPositions.length); + geometryArrays.transformedAndRecompressedPositions = new Uint16Array(geometryArrays.geometryPositions.length); + const geometryPositions = geometryArrays.geometryPositions; + const decompressedPositions = geometryArrays.decompressedPositions; + for (let i = 0, len = geometryPositions.length; i < len; i += 3) { + decompressedPositions[i + 0] = geometryPositions[i + 0] * reusedGeometriesDecodeMatrix[0] + reusedGeometriesDecodeMatrix[12]; + decompressedPositions[i + 1] = geometryPositions[i + 1] * reusedGeometriesDecodeMatrix[5] + reusedGeometriesDecodeMatrix[13]; + decompressedPositions[i + 2] = geometryPositions[i + 2] * reusedGeometriesDecodeMatrix[10] + reusedGeometriesDecodeMatrix[14]; + } + geometryArrays.geometryPositions = null; + geometryArraysCache[geometryId] = geometryArrays; + } + } + } + + if (geometryArrays) { + + if (geometryArrays.batchThisMesh) { + + const decompressedPositions = geometryArrays.decompressedPositions; + const transformedAndRecompressedPositions = geometryArrays.transformedAndRecompressedPositions; + + for (let i = 0, len = decompressedPositions.length; i < len; i += 3) { + tempVec4a[0] = decompressedPositions[i + 0]; + tempVec4a[1] = decompressedPositions[i + 1]; + tempVec4a[2] = decompressedPositions[i + 2]; + tempVec4a[3] = 1; + math.transformVec4(meshMatrix, tempVec4a, tempVec4b); + geometryCompressionUtils.compressPosition(tempVec4b, rtcAABB, tempVec4a); + transformedAndRecompressedPositions[i + 0] = tempVec4a[0]; + transformedAndRecompressedPositions[i + 1] = tempVec4a[1]; + transformedAndRecompressedPositions[i + 2] = tempVec4a[2]; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + textureSetId: textureSetId, + origin: tileCenter, + primitive: geometryArrays.primitiveName, + positionsCompressed: transformedAndRecompressedPositions, + normalsCompressed: geometryArrays.geometryNormals, + uv: geometryArrays.geometryUVs, + colorsCompressed: geometryArrays.geometryColors, + indices: geometryArrays.geometryIndices, + edgeIndices: geometryArrays.geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + + } else { + + if (!geometryCreatedInTile[geometryId]) { + + sceneModel.createGeometry({ + id: geometryId, + primitive: geometryArrays.primitiveName, + positionsCompressed: geometryArrays.geometryPositions, + normalsCompressed: geometryArrays.geometryNormals, + uv: geometryArrays.geometryUVs, + colorsCompressed: geometryArrays.geometryColors, + indices: geometryArrays.geometryIndices, + edgeIndices: geometryArrays.geometryEdgeIndices, + positionsDecodeMatrix: reusedGeometriesDecodeMatrix + }); + + geometryCreatedInTile[geometryId] = true; + } + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + geometryId: geometryId, + textureSetId: textureSetId, + matrix: meshMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity, + origin: tileCenter + })); + + meshIds.push(meshId); + } + } + + } else { // Do not reuse geometry + + const primitiveType = eachGeometryPrimitiveType[geometryIndex]; + + let primitiveName; + let geometryPositions; + let geometryNormals; + let geometryUVs; + let geometryColors; + let geometryIndices; + let geometryEdgeIndices; + let geometryValid = false; + + switch (primitiveType) { + case 0: + primitiveName = "solid"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + case 1: + primitiveName = "surface"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryNormals = normals.subarray(eachGeometryNormalsPortion [geometryIndex], atLastGeometry ? normals.length : eachGeometryNormalsPortion [geometryIndex + 1]); + geometryUVs = uvs.subarray(eachGeometryUVsPortion [geometryIndex], atLastGeometry ? uvs.length : eachGeometryUVsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryEdgeIndices = edgeIndices.subarray(eachGeometryEdgeIndicesPortion [geometryIndex], atLastGeometry ? edgeIndices.length : eachGeometryEdgeIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + case 2: + primitiveName = "points"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryColors = colors.subarray(eachGeometryColorsPortion [geometryIndex], atLastGeometry ? colors.length : eachGeometryColorsPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0); + break; + case 3: + primitiveName = "lines"; + geometryPositions = positions.subarray(eachGeometryPositionsPortion [geometryIndex], atLastGeometry ? positions.length : eachGeometryPositionsPortion [geometryIndex + 1]); + geometryIndices = indices.subarray(eachGeometryIndicesPortion [geometryIndex], atLastGeometry ? indices.length : eachGeometryIndicesPortion [geometryIndex + 1]); + geometryValid = (geometryPositions.length > 0 && geometryIndices.length > 0); + break; + default: + continue; + } + + if (geometryValid) { + + sceneModel.createMesh(utils.apply(meshDefaults, { + id: meshId, + textureSetId: textureSetId, + origin: tileCenter, + primitive: primitiveName, + positionsCompressed: geometryPositions, + normalsCompressed: geometryNormals, + uv: geometryUVs && geometryUVs.length > 0 ? geometryUVs : null, + colorsCompressed: geometryColors, + indices: geometryIndices, + edgeIndices: geometryEdgeIndices, + positionsDecodeMatrix: tileDecodeMatrix, + color: meshColor, + metallic: meshMetallic, + roughness: meshRoughness, + opacity: meshOpacity + })); + + meshIds.push(meshId); + } + } } - var proto = classType.registeredClass.instancePrototype; - var method = proto[methodName]; - if (method === void 0 || method.overloadTable === void 0 && method.className !== classType.name && method.argCount === argCount - 2) { - unboundTypesHandler.argCount = argCount - 2; - unboundTypesHandler.className = classType.name; - proto[methodName] = unboundTypesHandler; - } else { - ensureOverloadTable(proto, methodName, humanName); - proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; + + if (meshIds.length > 0) { + + sceneModel.createEntity(utils.apply(entityDefaults, { + id: entityId, + isObject: true, + meshIds: meshIds + })); } - whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { - var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context); - if (proto[methodName].overloadTable === void 0) { - memberFunction.argCount = argCount - 2; - proto[methodName] = memberFunction; - } else { - proto[methodName].overloadTable[argCount - 2] = memberFunction; - } - return []; - }); - return []; - }); - } - var emval_free_list = []; - var emval_handle_array = [{}, { value: void 0 }, { value: null }, { value: true }, { value: false }]; - function __emval_decref(handle) { - if (handle > 4 && --emval_handle_array[handle].refcount === 0) { - emval_handle_array[handle] = void 0; - emval_free_list.push(handle); - } } - function count_emval_handles() { - var count = 0; - for (var i = 5; i < emval_handle_array.length; ++i) { - if (emval_handle_array[i] !== void 0) { - ++count; + } +} + +/** @private */ +const ParserV10 = { + version: 10, + parse: function (viewer, options, elements, sceneModel) { + const deflatedData = extract(elements); + const inflatedData = inflate(deflatedData); + load(viewer, options, inflatedData, sceneModel); + } +}; + +const parsers = {}; + +parsers[ParserV1.version] = ParserV1; +parsers[ParserV2.version] = ParserV2; +parsers[ParserV3.version] = ParserV3; +parsers[ParserV4.version] = ParserV4; +parsers[ParserV5.version] = ParserV5; +parsers[ParserV6.version] = ParserV6; +parsers[ParserV7.version] = ParserV7; +parsers[ParserV8.version] = ParserV8; +parsers[ParserV9.version] = ParserV9; +parsers[ParserV10.version] = ParserV10; + +/** + * {@link Viewer} plugin that loads models from xeokit's optimized *````.XKT````* format. + * + * + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_OTCConferenceCenter)] + * + * ## Overview + * + * * XKTLoaderPlugin is the most efficient way to load high-detail models into xeokit. + * * An *````.XKT````* file is a single BLOB containing a model, compressed using geometry quantization + * and [pako](https://nodeca.github.io/pako/). + * * Supports double-precision coordinates. + * * Supports compressed textures. + * * Set the position, scale and rotation of each model as you load it. + * * Filter which IFC types get loaded. + * * Configure initial default appearances for IFC types. + * * Set a custom data source for *````.XKT````* and IFC metadata files. + * * Option to load multiple copies of the same model, without object ID clashes. + * + * ## Creating *````.XKT````* Files and Metadata + * + * We have several sways to convert your files into XKT. See these tutorials for more info: + * + * * [Converting Models to XKT with convert2xkt](https://www.notion.so/xeokit/Converting-Models-to-XKT-with-convert2xkt-fa567843313f4db8a7d6535e76da9380) - how to convert various file formats (glTF, IFC, CityJSON, LAS/LAZ...) to XKT using our nodejs-based converter. + * * [Converting IFC Models to XKT using 3rd-Party Open Source Tools](https://www.notion.so/xeokit/Converting-IFC-Models-to-XKT-using-3rd-Party-Open-Source-Tools-c373e48bc4094ff5b6e5c5700ff580ee) - how to convert IFC files to XKT using 3rd-party open source CLI tools. + * + * ## Scene representation + * + * When loading a model, XKTLoaderPlugin creates an {@link Entity} that represents the model, which + * will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} + * in {@link Scene#models}. The XKTLoaderPlugin also creates an {@link Entity} for each object within the + * model. Those Entities will have {@link Entity#isObject} set ````true```` and will be registered + * by {@link Entity#id} in {@link Scene#objects}. + * + * ## Metadata + * + * Since XKT V8, model metadata is included in the XKT file. If the XKT file has metadata, then loading it creates + * model metadata components within the Viewer, namely a {@link MetaModel} corresponding to the model {@link Entity}, + * and a {@link MetaObject} for each object {@link Entity}. + * + * Each {@link MetaObject} has a {@link MetaObject#type}, which indicates the classification of its corresponding + * {@link Entity}. When loading metadata, we can also configure XKTLoaderPlugin with a custom lookup table of initial + * values to set on the properties of each type of {@link Entity}. By default, XKTLoaderPlugin uses its own map of + * default colors and visibilities for IFC element types. + * + * For XKT versions prior to V8, we provided the metadata to XKTLoaderPlugin as an accompanying JSON file to load. We can + * still do that for all XKT versions, and for XKT V8+ it will override any metadata provided within the XKT file. + * + * ## Usage + * + * In the example below we'll load the Schependomlaan model from a [.XKT file](https://github.com/xeokit/xeokit-sdk/tree/master/examples/models/xkt/schependomlaan). + * + * This will create a bunch of {@link Entity}s that represents the model and its objects, along with a {@link MetaModel} and {@link MetaObject}s + * that hold their metadata. + * + * Since this model contains IFC types, the XKTLoaderPlugin will set the initial appearance of each object + * {@link Entity} according to its IFC type in {@link XKTLoaderPlugin#objectDefaults}. + * + * Read more about this example in the user guide on [Viewing BIM Models Offline](https://www.notion.so/xeokit/Viewing-an-IFC-Model-with-xeokit-c373e48bc4094ff5b6e5c5700ff580ee). + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_metadata_Schependomlaan)] + * + * ````javascript + * import {Viewer, XKTLoaderPlugin} from "xeokit-sdk.es.js"; + * + * //------------------------------------------------------------------------------------------------------------------ + * // 1. Create a Viewer, + * // 2. Arrange the camera + * //------------------------------------------------------------------------------------------------------------------ + * + * // 1 + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * // 2 + * viewer.camera.eye = [-2.56, 8.38, 8.27]; + * viewer.camera.look = [13.44, 3.31, -14.83]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * //------------------------------------------------------------------------------------------------------------------ + * // 1. Create a XKTLoaderPlugin, + * // 2. Load a building model and JSON IFC metadata + * //------------------------------------------------------------------------------------------------------------------ + * + * // 1 + * const xktLoader = new XKTLoaderPlugin(viewer); + * + * // 2 + * const model = xktLoader.load({ // Returns an Entity that represents the model + * id: "myModel", + * src: "./models/xkt/Schependomlaan.xkt", + * edges: true + * }); + * + * model.on("loaded", () => { + * + * //-------------------------------------------------------------------------------------------------------------- + * // 1. Find metadata on the third storey + * // 2. Select all the objects in the building's third storey + * // 3. Fit the camera to all the objects on the third storey + * //-------------------------------------------------------------------------------------------------------------- + * + * // 1 + * const metaModel = viewer.metaScene.metaModels["myModel"]; // MetaModel with ID "myModel" + * const metaObject + * = viewer.metaScene.metaObjects["0u4wgLe6n0ABVaiXyikbkA"]; // MetaObject with ID "0u4wgLe6n0ABVaiXyikbkA" + * + * const name = metaObject.name; // "01 eerste verdieping" + * const type = metaObject.type; // "IfcBuildingStorey" + * const parent = metaObject.parent; // MetaObject with type "IfcBuilding" + * const children = metaObject.children; // Array of child MetaObjects + * const objectId = metaObject.id; // "0u4wgLe6n0ABVaiXyikbkA" + * const objectIds = viewer.metaScene.getObjectIDsInSubtree(objectId); // IDs of leaf sub-objects + * const aabb = viewer.scene.getAABB(objectIds); // Axis-aligned boundary of the leaf sub-objects + * + * // 2 + * viewer.scene.setObjectsSelected(objectIds, true); + * + * // 3 + * viewer.cameraFlight.flyTo(aabb); + * }); + * + * // Find the model Entity by ID + * model = viewer.scene.models["myModel"]; + * + * // Destroy the model + * model.destroy(); + * ```` + * + * ## Loading XKT files containing textures + * + * XKTLoaderPlugin uses a {@link KTX2TextureTranscoder} to load textures in XKT files (XKT v10+). An XKTLoaderPlugin has its own + * default KTX2TextureTranscoder, configured to load the Basis Codec from the CDN. If we wish, we can override that with our own + * KTX2TextureTranscoder instance that's configured to load the Codec locally. + * + * In the example below, we'll create a {@link Viewer} and add an XKTLoaderPlugin + * configured with a KTX2TextureTranscoder that finds the Codec in our local file system. Then we'll use the + * XKTLoaderPlugin to load an XKT file that contains KTX2 textures, which the plugin will transcode using + * its KTX2TextureTranscoder. + * + * We'll configure our KTX2TextureTranscoder to load the Basis Codec from a local directory. If we were happy with loading the + * Codec from our CDN (ie. our app will always have an Internet connection) then we could just leave out the + * KTX2TextureTranscoder altogether, and let the XKTLoaderPlugin use its internal default KTX2TextureTranscoder, which is configured to + * load the Codec from the CDN. We'll stick with loading our own Codec, in case we want to run our app without an Internet connection. + * + * + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Textures_HousePlan)] + * + * ````javascript + * const viewer = new Viewer({ + * canvasId: "myCanvas", + * transparent: true + * }); + * + * viewer.camera.eye = [-2.56, 8.38, 8.27]; + * viewer.camera.look = [13.44, 3.31, -14.83]; + * viewer.camera.up = [0.10, 0.98, -0.14]; + * + * const textureTranscoder = new KTX2TextureTranscoder({ + * viewer, + * transcoderPath: "./../dist/basis/" // <------ Path to Basis Universal transcoder + * }); + * + * const xktLoader = new XKTLoaderPlugin(viewer, { + * textureTranscoder // <<------------- Transcodes KTX2 textures in XKT files + * }); + * + * const sceneModel = xktLoader.load({ + * id: "myModel", + * src: "./HousePlan.xkt" // <<------ XKT file with KTX2 textures + * }); + * ```` + * + * ## Transforming + * + * We have the option to rotate, scale and translate each *````.XKT````* model as we load it. + * + * This lets us load multiple models, or even multiple copies of the same model, and position them apart from each other. + * + * In the example below, we'll scale our model to half its size, rotate it 90 degrees about its local X-axis, then + * translate it 100 units along its X axis. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_Duplex_transform)] + * + * ````javascript + * xktLoader.load({ + * src: "./models/xkt/Duplex.ifc.xkt", + * rotation: [90,0,0], + * scale: [0.5, 0.5, 0.5], + * position: [100, 0, 0] + * }); + * ```` + * + * ## Including and excluding IFC types + * + * We can also load only those objects that have the specified IFC types. + * + * In the example below, we'll load only the objects that represent walls. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_includeTypes)] + * + * ````javascript + * const model2 = xktLoader.load({ + * id: "myModel2", + * src: "./models/xkt/OTCConferenceCenter.xkt", + * includeTypes: ["IfcWallStandardCase"] + * }); + * ```` + * + * We can also load only those objects that **don't** have the specified IFC types. + * + * In the example below, we'll load only the objects that do not represent empty space. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_excludeTypes)] + * + * ````javascript + * const model3 = xktLoader.load({ + * id: "myModel3", + * src: "./models/xkt/OTCConferenceCenter.xkt", + * excludeTypes: ["IfcSpace"] + * }); + * ```` + * + * ## Configuring initial IFC object appearances + * + * We can specify the custom initial appearance of loaded objects according to their IFC types. + * + * This is useful for things like: + * + * * setting the colors to our objects according to their IFC types, + * * automatically hiding ````IfcSpace```` objects, and + * * ensuring that ````IfcWindow```` objects are always transparent. + *
    + * In the example below, we'll load a model, while configuring ````IfcSpace```` elements to be always initially invisible, + * and ````IfcWindow```` types to be always translucent blue. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#BIMOffline_XKT_objectDefaults)] + * + * ````javascript + * const myObjectDefaults = { + * + * IfcSpace: { + * visible: false + * }, + * IfcWindow: { + * colorize: [0.337255, 0.303922, 0.870588], // Blue + * opacity: 0.3 + * }, + * + * //... + * + * DEFAULT: { + * colorize: [0.5, 0.5, 0.5] + * } + * }; + * + * const model4 = xktLoader.load({ + * id: "myModel4", + * src: "./models/xkt/Duplex.ifc.xkt", + * objectDefaults: myObjectDefaults // Use our custom initial default states for object Entities + * }); + * ```` + * + * When we don't customize the appearance of IFC types, as just above, then IfcSpace elements tend to obscure other + * elements, which can be confusing. + * + * It's often helpful to make IfcSpaces transparent and unpickable, like this: + * + * ````javascript + * const xktLoader = new XKTLoaderPlugin(viewer, { + * objectDefaults: { + * IfcSpace: { + * pickable: false, + * opacity: 0.2 + * } + * } + * }); + * ```` + * + * Alternatively, we could just make IfcSpaces invisible, which also makes them unpickable: + * + * ````javascript + * const xktLoader = new XKTLoaderPlugin(viewer, { + * objectDefaults: { + * IfcSpace: { + * visible: false + * } + * } + * }); + * ```` + * + * ## Configuring a custom data source + * + * By default, XKTLoaderPlugin will load *````.XKT````* files and metadata JSON over HTTP. + * + * In the example below, we'll customize the way XKTLoaderPlugin loads the files by configuring it with our own data source + * object. For simplicity, our custom data source example also uses HTTP, using a couple of xeokit utility functions. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_XKT_dataSource)] + * + * ````javascript + * import {utils} from "xeokit-sdk.es.js"; + * + * class MyDataSource { + * + * constructor() { + * } + * + * // Gets metamodel JSON + * getMetaModel(metaModelSrc, ok, error) { + * console.log("MyDataSource#getMetaModel(" + metaModelSrc + ", ... )"); + * utils.loadJSON(metaModelSrc, + * (json) => { + * ok(json); + * }, + * function (errMsg) { + * error(errMsg); + * }); + * } + * + * // Gets the contents of the given .XKT file in an arraybuffer + * getXKT(src, ok, error) { + * console.log("MyDataSource#getXKT(" + xKTSrc + ", ... )"); + * utils.loadArraybuffer(src, + * (arraybuffer) => { + * ok(arraybuffer); + * }, + * function (errMsg) { + * error(errMsg); + * }); + * } + * } + * + * const xktLoader2 = new XKTLoaderPlugin(viewer, { + * dataSource: new MyDataSource() + * }); + * + * const model5 = xktLoader2.load({ + * id: "myModel5", + * src: "./models/xkt/Duplex.ifc.xkt" + * }); + * ```` + * + * ## Loading multiple copies of a model, without object ID clashes + * + * Sometimes we need to load two or more instances of the same model, without having clashes + * between the IDs of the equivalent objects in the model instances. + * + * As shown in the example below, we do this by setting {@link XKTLoaderPlugin#globalizeObjectIds} ````true```` before we load our models. + * + * * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#TreeViewPlugin_Containment_MultipleModels)] + * + * ````javascript + * xktLoader.globalizeObjectIds = true; + * + * const model = xktLoader.load({ + * id: "model1", + * src: "./models/xkt/Schependomlaan.xkt" + * }); + * + * const model2 = xktLoader.load({ + * id: "model2", + * src: "./models/xkt/Schependomlaan.xkt" + * }); + * ```` + * + * For each {@link Entity} loaded by these two calls, {@link Entity#id} and {@link MetaObject#id} will get prefixed by + * the ID of their model, in order to avoid ID clashes between the two models. + * + * An Entity belonging to the first model will get an ID like this: + * + * ```` + * myModel1#0BTBFw6f90Nfh9rP1dlXrb + * ```` + * + * The equivalent Entity in the second model will get an ID like this: + * + * ```` + * myModel2#0BTBFw6f90Nfh9rP1dlXrb + * ```` + * + * Now, to update the visibility of both of those Entities collectively, using {@link Scene#setObjectsVisible}, we can + * supply just the IFC product ID part to that method: + * + * ````javascript + * myViewer.scene.setObjectVisibilities("0BTBFw6f90Nfh9rP1dlXrb", true); + * ```` + * + * The method, along with {@link Scene#setObjectsXRayed}, {@link Scene#setObjectsHighlighted} etc, will internally expand + * the given ID to refer to the instances of that Entity in both models. + * + * We can also, of course, reference each Entity directly, using its globalized ID: + * + * ````javascript + * myViewer.scene.setObjectVisibilities("myModel1#0BTBFw6f90Nfh9rP1dlXrb", true); + *```` + * + * @class XKTLoaderPlugin + */ +class XKTLoaderPlugin extends Plugin { + + /** + * @constructor + * + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="XKTLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {Object} [cfg.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. + * @param {Object} [cfg.dataSource] A custom data source through which the XKTLoaderPlugin can load model and metadata files. Defaults to an instance of {@link XKTDefaultDataSource}, which loads uover HTTP. + * @param {String[]} [cfg.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. + * @param {String[]} [cfg.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. + * @param {Boolean} [cfg.excludeUnclassifiedObjects=false] When loading metadata and this is ````true````, will only load {@link Entity}s that have {@link MetaObject}s (that are not excluded). This is useful when we don't want Entitys in the Scene that are not represented within IFC navigation components, such as {@link TreeViewPlugin}. + * @param {Boolean} [cfg.reuseGeometries=true] Indicates whether to enable geometry reuse (````true```` by default) or whether to internally expand + * all geometry instances into batches (````false````), and not use instancing to render them. Setting this ````false```` can significantly + * improve Viewer performance for models that have a lot of geometry reuse, but may also increase the amount of + * browser and GPU memory they require. See [#769](https://github.com/xeokit/xeokit-sdk/issues/769) for more info. + * @param {Number} [cfg.maxGeometryBatchSize=50000000] Maximum geometry batch size, as number of vertices. This is optionally supplied + * to limit the size of the batched geometry arrays that {@link VBOSceneModel} internally creates for batched geometries. + * A low value means less heap allocation/de-allocation while loading batched geometries, but more draw calls and + * slower rendering speed. A high value means larger heap allocation/de-allocation while loading, but less draw calls + * and faster rendering speed. It's recommended to keep this somewhere roughly between ````50000```` and ````50000000```. + * @param {KTX2TextureTranscoder} [cfg.textureTranscoder] Transcoder used internally to transcode KTX2 + * textures within the XKT. Only required when the XKT is version 10 or later, and contains KTX2 textures. + */ + constructor(viewer, cfg = {}) { + + super("XKTLoader", viewer, cfg); + + this._maxGeometryBatchSize = cfg.maxGeometryBatchSize; + + this.textureTranscoder = cfg.textureTranscoder; + this.dataSource = cfg.dataSource; + this.objectDefaults = cfg.objectDefaults; + this.includeTypes = cfg.includeTypes; + this.excludeTypes = cfg.excludeTypes; + this.excludeUnclassifiedObjects = cfg.excludeUnclassifiedObjects; + this.reuseGeometries = cfg.reuseGeometries; + } + + /** + * Gets the ````.xkt```` format versions supported by this XKTLoaderPlugin/ + * @returns {string[]} + */ + get supportedVersions() { + return Object.keys(parsers); + } + + /** + * Gets the texture transcoder. + * + * @type {TextureTranscoder} + */ + get textureTranscoder() { + return this._textureTranscoder; + } + + /** + * Sets the texture transcoder. + * + * @type {TextureTranscoder} + */ + set textureTranscoder(textureTranscoder) { + this._textureTranscoder = textureTranscoder; + } + + /** + * Gets the custom data source through which the XKTLoaderPlugin can load models and metadata. + * + * Default value is {@link XKTDefaultDataSource}, which loads via HTTP. + * + * @type {Object} + */ + get dataSource() { + return this._dataSource; + } + + /** + * Sets a custom data source through which the XKTLoaderPlugin can load models and metadata. + * + * Default value is {@link XKTDefaultDataSource}, which loads via HTTP. + * + * @type {Object} + */ + set dataSource(value) { + this._dataSource = value || new XKTDefaultDataSource(); + } + + /** + * Gets map of initial default states for each loaded {@link Entity} that represents an object. + * + * Default value is {@link IFCObjectDefaults}. + * + * @type {{String: Object}} + */ + get objectDefaults() { + return this._objectDefaults; + } + + /** + * Sets map of initial default states for each loaded {@link Entity} that represents an object. + * + * Default value is {@link IFCObjectDefaults}. + * + * @type {{String: Object}} + */ + set objectDefaults(value) { + this._objectDefaults = value || IFCObjectDefaults; + } + + /** + * Gets the whitelist of the IFC types loaded by this XKTLoaderPlugin. + * + * When loading models with metadata, causes this XKTLoaderPlugin to only load objects whose types are in this + * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. + * + * Default value is ````undefined````. + * + * @type {String[]} + */ + get includeTypes() { + return this._includeTypes; + } + + /** + * Sets the whitelist of the IFC types loaded by this XKTLoaderPlugin. + * + * When loading models with metadata, causes this XKTLoaderPlugin to only load objects whose types are in this + * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. + * + * Default value is ````undefined````. + * + * @type {String[]} + */ + set includeTypes(value) { + this._includeTypes = value; + } + + /** + * Gets the blacklist of IFC types that are never loaded by this XKTLoaderPlugin. + * + * When loading models with metadata, causes this XKTLoaderPlugin to **not** load objects whose types are in this + * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. + * + * Default value is ````undefined````. + * + * @type {String[]} + */ + get excludeTypes() { + return this._excludeTypes; + } + + /** + * Sets the blacklist of IFC types that are never loaded by this XKTLoaderPlugin. + * + * When loading models with metadata, causes this XKTLoaderPlugin to **not** load objects whose types are in this + * list. An object's type is indicated by its {@link MetaObject}'s {@link MetaObject#type}. + * + * Default value is ````undefined````. + * + * @type {String[]} + */ + set excludeTypes(value) { + this._excludeTypes = value; + } + + /** + * Gets whether we load objects that don't have IFC types. + * + * When loading models with metadata and this is ````true````, XKTLoaderPlugin will not load objects + * that don't have IFC types. + * + * Default value is ````false````. + * + * @type {Boolean} + */ + get excludeUnclassifiedObjects() { + return this._excludeUnclassifiedObjects; + } + + /** + * Sets whether we load objects that don't have IFC types. + * + * When loading models with metadata and this is ````true````, XKTLoaderPlugin will not load objects + * that don't have IFC types. + * + * Default value is ````false````. + * + * @type {Boolean} + */ + set excludeUnclassifiedObjects(value) { + this._excludeUnclassifiedObjects = !!value; + } + + /** + * Gets whether XKTLoaderPlugin globalizes each {@link Entity#id} and {@link MetaObject#id} as it loads a model. + * + * Default value is ````false````. + * + * @type {Boolean} + */ + get globalizeObjectIds() { + return this._globalizeObjectIds; + } + + /** + * Sets whether XKTLoaderPlugin globalizes each {@link Entity#id} and {@link MetaObject#id} as it loads a model. + * + * Set this ````true```` when you need to load multiple instances of the same model, to avoid ID clashes + * between the objects in the different instances. + * + * When we load a model with this set ````true````, then each {@link Entity#id} and {@link MetaObject#id} will be + * prefixed by the ID of the model, ie. ````#````. + * + * {@link Entity#originalSystemId} and {@link MetaObject#originalSystemId} will always hold the original, un-prefixed, ID values. + * + * Default value is ````false````. + * + * See the main {@link XKTLoaderPlugin} class documentation for usage info. + * + * @type {Boolean} + */ + set globalizeObjectIds(value) { + this._globalizeObjectIds = !!value; + } + + /** + * Gets whether XKTLoaderPlugin enables geometry reuse when loading models. + * + * Default value is ````true````. + * + * @type {Boolean} + */ + get reuseGeometries() { + return this._reuseGeometries; + } + + /** + * Sets whether XKTLoaderPlugin enables geometry reuse when loading models. + * + * Default value is ````true````. + * + * Geometry reuse saves memory, but can impact Viewer performance when there are many reused geometries. For + * this reason, we can set this ````false```` to disable geometry reuse for models loaded by this XKTLoaderPlugin + * (which will then "expand" the geometry instances into batches instead). + * + * The result will be be less WebGL draw calls (which are expensive), at the cost of increased memory footprint. + * + * See [#769](https://github.com/xeokit/xeokit-sdk/issues/769) for more info. + * + * @type {Boolean} + */ + set reuseGeometries(value) { + this._reuseGeometries = value !== false; + } + + /** + * Loads an ````.xkt```` model into this XKTLoaderPlugin's {@link Viewer}. + * + * Since xeokit/xeokit-sdk 1.9.0, XKTLoaderPlugin has supported XKT 8, which bundles the metamodel + * data (eg. an IFC element hierarchy) in the XKT file itself. For XKT 8, we therefore no longer need to + * load the metamodel data from a separate accompanying JSON file, as we did with previous XKT versions. + * However, if we do choose to specify a separate metamodel JSON file to load (eg. for backward compatibility + * in data pipelines), then that metamodel will be loaded and the metamodel in the XKT 8 file will be ignored. + * + * @param {*} params Loading parameters. + * @param {String} [params.id] ID to assign to the root {@link Entity#id}, unique among all components in the Viewer's {@link Scene}, generated automatically by default. + * @param {String} [params.src] Path to a *````.xkt````* file, as an alternative to the ````xkt```` parameter. + * @param {ArrayBuffer} [params.xkt] The *````.xkt````* file data, as an alternative to the ````src```` parameter. + * @param {String} [params.metaModelSrc] Path to an optional metadata file, as an alternative to the ````metaModelData```` parameter. + * @param {*} [params.metaModelData] JSON model metadata, as an alternative to the ````metaModelSrc```` parameter. + * @param {{String:Object}} [params.objectDefaults] Map of initial default states for each loaded {@link Entity} that represents an object. Default value is {@link IFCObjectDefaults}. + * @param {String[]} [params.includeTypes] When loading metadata, only loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. + * @param {String[]} [params.excludeTypes] When loading metadata, never loads objects that have {@link MetaObject}s with {@link MetaObject#type} values in this list. + * @param {Boolean} [params.edges=false] Whether or not xeokit renders the model with edges emphasized. + * @param {Number[]} [params.origin=[0,0,0]] The model's World-space double-precision 3D origin. Use this to position the model within xeokit's World coordinate system, using double-precision coordinates. + * @param {Number[]} [params.position=[0,0,0]] The model single-precision 3D position, relative to the ````origin```` parameter. + * @param {Number[]} [params.scale=[1,1,1]] The model's scale. + * @param {Number[]} [params.rotation=[0,0,0]] The model's orientation, given as Euler angles in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. Relative to ````origin````. + * @param {Boolean} [params.edges=false] Indicates if the model's edges are initially emphasized. + * @param {Boolean} [params.saoEnabled=true] Indicates if Scalable Ambient Obscurance (SAO) is enabled for the model. SAO is configured by the Scene's {@link SAO} component. Only works when {@link SAO#enabled} is also ````true```` + * @param {Boolean} [params.pbrEnabled=true] Indicates if physically-based rendering (PBR) is enabled for the model. Overrides ````colorTextureEnabled````. Only works when {@link Scene#pbrEnabled} is also ````true````. + * @param {Boolean} [params.colorTextureEnabled=true] Indicates if base color texture rendering is enabled for the model. Overridden by ````pbrEnabled````. Only works when {@link Scene#colorTextureEnabled} is also ````true````. + * @param {Number} [params.backfaces=false] When we set this ````true````, then we force rendering of backfaces for the model. When + * we leave this ````false````, then we allow the Viewer to decide when to render backfaces. In that case, the + * Viewer will hide backfaces on watertight meshes, show backfaces on open meshes, and always show backfaces on meshes when we slice them open with {@link SectionPlane}s. + * @param {Boolean} [params.excludeUnclassifiedObjects=false] When loading metadata and this is ````true````, will only load {@link Entity}s that have {@link MetaObject}s (that are not excluded). This is useful when we don't want Entitys in the Scene that are not represented within IFC navigation components, such as {@link TreeViewPlugin}. + * @param {Boolean} [params.globalizeObjectIds=false] Indicates whether to globalize each {@link Entity#id} and {@link MetaObject#id}, in case you need to prevent ID clashes with other models. See {@link XKTLoaderPlugin#globalizeObjectIds} for more info. + * @param {Boolean} [params.reuseGeometries=true] Indicates whether to enable geometry reuse (````true```` by default) or whether to expand + * all geometry instances into batches (````false````), and not use instancing to render them. Setting this ````false```` can significantly + * improve Viewer performance for models that have excessive geometry reuse, but may also increases the amount of + * browser and GPU memory used by the model. See [#769](https://github.com/xeokit/xeokit-sdk/issues/769) for more info. + * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. + */ + load(params = {}) { + + if (params.id && this.viewer.scene.components[params.id]) { + this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); + delete params.id; + } + + const sceneModel = new VBOSceneModel(this.viewer.scene, utils.apply(params, { + isModel: true, + textureTranscoder: this._textureTranscoder, + maxGeometryBatchSize: this._maxGeometryBatchSize, + origin: params.origin + })); + + const modelId = sceneModel.id; // In case ID was auto-generated + + if (!params.src && !params.xkt) { + this.error("load() param expected: src or xkt"); + return sceneModel; // Return new empty model + } + + const options = {}; + const includeTypes = params.includeTypes || this._includeTypes; + const excludeTypes = params.excludeTypes || this._excludeTypes; + const objectDefaults = params.objectDefaults || this._objectDefaults; + + options.reuseGeometries = (params.reuseGeometries !== null && params.reuseGeometries !== undefined ) ? params.reuseGeometries : (this._reuseGeometries !== false); + + if (includeTypes) { + options.includeTypesMap = {}; + for (let i = 0, len = includeTypes.length; i < len; i++) { + options.includeTypesMap[includeTypes[i]] = true; } - } - return count; } - function get_first_emval() { - for (var i = 5; i < emval_handle_array.length; ++i) { - if (emval_handle_array[i] !== void 0) { - return emval_handle_array[i]; + + if (excludeTypes) { + options.excludeTypesMap = {}; + for (let i = 0, len = excludeTypes.length; i < len; i++) { + options.excludeTypesMap[excludeTypes[i]] = true; } - } - return null; } - function init_emval() { - Module["count_emval_handles"] = count_emval_handles; - Module["get_first_emval"] = get_first_emval; + + if (objectDefaults) { + options.objectDefaults = objectDefaults; } - function __emval_register(value) { - switch (value) { - case void 0: { - return 1; - } - case null: { - return 2; - } - case true: { - return 3; - } - case false: { - return 4; + + options.excludeUnclassifiedObjects = (params.excludeUnclassifiedObjects !== undefined) ? (!!params.excludeUnclassifiedObjects) : this._excludeUnclassifiedObjects; + options.globalizeObjectIds = (params.globalizeObjectIds !== undefined) ? (!!params.globalizeObjectIds) : this._globalizeObjectIds; + + if (params.metaModelSrc || params.metaModelData) { + + const processMetaModelData = (metaModelData) => { + + const metaModel = this.viewer.metaScene.createMetaModel(modelId, metaModelData, { + includeTypes: includeTypes, + excludeTypes: excludeTypes, + globalizeObjectIds: this.globalizeObjectIds + }); + + if (!metaModel) { + return false; + } + + if (params.src) { + this._loadModel(params.src, params, options, sceneModel); + } else { + this._parseModel(params.xkt, params, options, sceneModel); + } + + sceneModel.once("destroyed", () => { + this.viewer.metaScene.destroyMetaModel(sceneModel.id); + }); + + return true; + }; + + if (params.metaModelSrc) { + + const metaModelSrc = params.metaModelSrc; + + this.viewer.scene.canvas.spinner.processes++; + + this._dataSource.getMetaModel(metaModelSrc, (metaModelData) => { + + if (sceneModel.destroyed) { + return; + } + + if (!processMetaModelData(metaModelData)) { + + this.error(`load(): Failed to load model metadata for model '${modelId} from '${metaModelSrc}' - metadata not valid`); + + sceneModel.fire("error", "Metadata not valid"); + } + + this.viewer.scene.canvas.spinner.processes--; + + }, (errMsg) => { + + this.error(`load(): Failed to load model metadata for model '${modelId} from '${metaModelSrc}' - ${errMsg}`); + + sceneModel.fire("error", `Failed to load model metadata from '${metaModelSrc}' - ${errMsg}`); + + this.viewer.scene.canvas.spinner.processes--; + }); + + } else if (params.metaModelData) { + + if (!processMetaModelData(params.metaModelData)) { + + this.error(`load(): Failed to load model metadata for model '${modelId} from '${params.metaModelSrc}' - metadata not valid`); + + sceneModel.fire("error", "Metadata not valid"); + } } - default: { - var handle = emval_free_list.length ? emval_free_list.pop() : emval_handle_array.length; - emval_handle_array[handle] = { refcount: 1, value }; - return handle; + + } else { + if (params.src) { + this._loadModel(params.src, params, options, sceneModel); + } else { + this._parseModel(params.xkt, params, options, sceneModel); } - } - } - function __embind_register_emval(rawType, name2) { - name2 = readLatin1String(name2); - registerType(rawType, { name: name2, "fromWireType": function(handle) { - var rv = emval_handle_array[handle].value; - __emval_decref(handle); - return rv; - }, "toWireType": function(destructors, value) { - return __emval_register(value); - }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: null }); - } - function enumReadValueFromPointer(name2, shift, signed) { - switch (shift) { - case 0: - return function(pointer) { - var heap = signed ? GROWABLE_HEAP_I8() : GROWABLE_HEAP_U8(); - return this["fromWireType"](heap[pointer >>> 0]); - }; - case 1: - return function(pointer) { - var heap = signed ? GROWABLE_HEAP_I16() : GROWABLE_HEAP_U16(); - return this["fromWireType"](heap[pointer >>> 1]); - }; - case 2: - return function(pointer) { - var heap = signed ? GROWABLE_HEAP_I32() : GROWABLE_HEAP_U32(); - return this["fromWireType"](heap[pointer >>> 2]); - }; - default: - throw new TypeError("Unknown integer type: " + name2); - } - } - function __embind_register_enum(rawType, name2, size, isSigned) { - var shift = getShiftFromSize(size); - name2 = readLatin1String(name2); - function ctor() { - } - ctor.values = {}; - registerType(rawType, { name: name2, constructor: ctor, "fromWireType": function(c) { - return this.constructor.values[c]; - }, "toWireType": function(destructors, c) { - return c.value; - }, "argPackAdvance": 8, "readValueFromPointer": enumReadValueFromPointer(name2, shift, isSigned), destructorFunction: null }); - exposePublicSymbol(name2, ctor); - } - function requireRegisteredType(rawType, humanName) { - var impl = registeredTypes[rawType]; - if (impl === void 0) { - throwBindingError(humanName + " has unknown type " + getTypeName(rawType)); - } - return impl; } - function __embind_register_enum_value(rawEnumType, name2, enumValue) { - var enumType = requireRegisteredType(rawEnumType, "enum"); - name2 = readLatin1String(name2); - var Enum = enumType.constructor; - var Value2 = Object.create(enumType.constructor.prototype, { value: { value: enumValue }, constructor: { value: createNamedFunction(enumType.name + "_" + name2, function() { - }) } }); - Enum.values[enumValue] = Value2; - Enum[name2] = Value2; + + return sceneModel; + } + + _loadModel(src, params, options, sceneModel) { + + const spinner = this.viewer.scene.canvas.spinner; + + spinner.processes++; + + this._dataSource.getXKT(params.src, (arrayBuffer) => { + this._parseModel(arrayBuffer, params, options, sceneModel); + spinner.processes--; + }, + (errMsg) => { + spinner.processes--; + this.error(errMsg); + sceneModel.fire("error", errMsg); + }); + } + + _parseModel(arrayBuffer, params, options, sceneModel) { + + if (sceneModel.destroyed) { + return; } - function _embind_repr(v) { - if (v === null) { - return "null"; - } - var t = typeof v; - if (t === "object" || t === "array" || t === "function") { - return v.toString(); - } else { - return "" + v; - } + + const dataView = new DataView(arrayBuffer); + const dataArray = new Uint8Array(arrayBuffer); + const xktVersion = dataView.getUint32(0, true); + const parser = parsers[xktVersion]; + + if (!parser) { + this.error("Unsupported .XKT file version: " + xktVersion + " - this XKTLoaderPlugin supports versions " + Object.keys(parsers)); + return; } - function floatReadValueFromPointer(name2, shift) { - switch (shift) { - case 2: - return function(pointer) { - return this["fromWireType"](GROWABLE_HEAP_F32()[pointer >> 2]); - }; - case 3: - return function(pointer) { - return this["fromWireType"](GROWABLE_HEAP_F64()[pointer >> 3]); - }; - default: - throw new TypeError("Unknown float type: " + name2); - } + + this.log("Loading .xkt V" + xktVersion); + + const numElements = dataView.getUint32(4, true); + const elements = []; + let byteOffset = (numElements + 2) * 4; + for (let i = 0; i < numElements; i++) { + const elementSize = dataView.getUint32((i + 2) * 4, true); + elements.push(dataArray.subarray(byteOffset, byteOffset + elementSize)); + byteOffset += elementSize; } - function __embind_register_float(rawType, name2, size) { - var shift = getShiftFromSize(size); - name2 = readLatin1String(name2); - registerType(rawType, { name: name2, "fromWireType": function(value) { - return value; - }, "toWireType": function(destructors, value) { - if (typeof value !== "number" && typeof value !== "boolean") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); + + parser.parse(this.viewer, options, elements, sceneModel); + + sceneModel.finalize(); + + this._createDefaultMetaModelIfNeeded(sceneModel, params, options); + + sceneModel.scene.once("tick", () => { + if (sceneModel.destroyed) { + return; } - return value; - }, "argPackAdvance": 8, "readValueFromPointer": floatReadValueFromPointer(name2, shift), destructorFunction: null }); - } - function __embind_register_function(name2, argCount, rawArgTypesAddr, signature, rawInvoker, fn) { - var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - name2 = readLatin1String(name2); - rawInvoker = embind__requireFunction(signature, rawInvoker); - exposePublicSymbol(name2, function() { - throwUnboundTypeError("Cannot call " + name2 + " due to unbound types", argTypes); - }, argCount - 1); - whenDependentTypesAreResolved([], argTypes, function(argTypes2) { - var invokerArgsArray = [argTypes2[0], null].concat(argTypes2.slice(1)); - replacePublicSymbol(name2, craftInvokerFunction(name2, invokerArgsArray, null, rawInvoker, fn), argCount - 1); - return []; - }); - } - function integerReadValueFromPointer(name2, shift, signed) { - switch (shift) { - case 0: - return signed ? function readS8FromPointer(pointer) { - return GROWABLE_HEAP_I8()[pointer]; - } : function readU8FromPointer(pointer) { - return GROWABLE_HEAP_U8()[pointer]; - }; - case 1: - return signed ? function readS16FromPointer(pointer) { - return GROWABLE_HEAP_I16()[pointer >> 1]; - } : function readU16FromPointer(pointer) { - return GROWABLE_HEAP_U16()[pointer >> 1]; - }; - case 2: - return signed ? function readS32FromPointer(pointer) { - return GROWABLE_HEAP_I32()[pointer >> 2]; - } : function readU32FromPointer(pointer) { - return GROWABLE_HEAP_U32()[pointer >> 2]; - }; - default: - throw new TypeError("Unknown integer type: " + name2); - } - } - function __embind_register_integer(primitiveType, name2, size, minRange, maxRange) { - name2 = readLatin1String(name2); - if (maxRange === -1) { - maxRange = 4294967295; - } - var shift = getShiftFromSize(size); - var fromWireType = function(value) { - return value; - }; - if (minRange === 0) { - var bitshift = 32 - 8 * size; - fromWireType = function(value) { - return value << bitshift >>> bitshift; + sceneModel.scene.fire("modelLoaded", sceneModel.id); // FIXME: Assumes listeners know order of these two events + sceneModel.fire("loaded", true, false); // Don't forget the event, for late subscribers + }); + } + + _createDefaultMetaModelIfNeeded(sceneModel, params, options) { + + const metaModelId = sceneModel.id; + + if (!this.viewer.metaScene.metaModels[metaModelId]) { + + const metaModelData = { + metaObjects: [] }; - } - var isUnsignedType = name2.indexOf("unsigned") != -1; - registerType(primitiveType, { name: name2, "fromWireType": fromWireType, "toWireType": function(destructors, value) { - if (typeof value !== "number" && typeof value !== "boolean") { - throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); - } - if (value < minRange || value > maxRange) { - throw new TypeError('Passing a number "' + _embind_repr(value) + '" from JS side to C/C++ side to an argument of type "' + name2 + '", which is outside the valid range [' + minRange + ", " + maxRange + "]!"); - } - return isUnsignedType ? value >>> 0 : value | 0; - }, "argPackAdvance": 8, "readValueFromPointer": integerReadValueFromPointer(name2, shift, minRange !== 0), destructorFunction: null }); - } - function __embind_register_memory_view(rawType, dataTypeIndex, name2) { - var typeMapping = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; - var TA = typeMapping[dataTypeIndex]; - function decodeMemoryView(handle) { - handle = handle >> 2; - var heap = GROWABLE_HEAP_U32(); - var size = heap[handle >>> 0]; - var data = heap[handle + 1 >>> 0]; - return new TA(buffer, data, size); - } - name2 = readLatin1String(name2); - registerType(rawType, { name: name2, "fromWireType": decodeMemoryView, "argPackAdvance": 8, "readValueFromPointer": decodeMemoryView }, { ignoreDuplicateRegistrations: true }); - } - function __embind_register_std_string(rawType, name2) { - name2 = readLatin1String(name2); - var stdStringIsUTF8 = name2 === "std::string"; - registerType(rawType, { name: name2, "fromWireType": function(value) { - var length = GROWABLE_HEAP_U32()[value >> 2]; - var str; - if (stdStringIsUTF8) { - var decodeStartPtr = value + 4; - for (var i = 0; i <= length; ++i) { - var currentBytePtr = value + 4 + i; - if (i == length || GROWABLE_HEAP_U8()[currentBytePtr] == 0) { - var maxRead = currentBytePtr - decodeStartPtr; - var stringSegment = UTF8ToString(decodeStartPtr, maxRead); - if (str === void 0) { - str = stringSegment; - } else { - str += String.fromCharCode(0); - str += stringSegment; - } - decodeStartPtr = currentBytePtr + 1; + + metaModelData.metaObjects.push({ + id: metaModelId, + type: "default", + name: metaModelId, + parent: null + }); + + const entityList = sceneModel.entityList; + + for (let i = 0, len = entityList.length; i < len; i++) { + const entity = entityList[i]; + if (entity.isObject) { + metaModelData.metaObjects.push({ + id: entity.id, + type: "default", + name: entity.id, + parent: metaModelId + }); } - } - } else { - var a = new Array(length); - for (var i = 0; i < length; ++i) { - a[i] = String.fromCharCode(GROWABLE_HEAP_U8()[value + 4 + i]); - } - str = a.join(""); - } - _free(value); - return str; - }, "toWireType": function(destructors, value) { - if (value instanceof ArrayBuffer) { - value = new Uint8Array(value); - } - var getLength; - var valueIsOfTypeString = typeof value === "string"; - if (!(valueIsOfTypeString || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int8Array)) { - throwBindingError("Cannot pass non-string to std::string"); - } - if (stdStringIsUTF8 && valueIsOfTypeString) { - getLength = function() { - return lengthBytesUTF8(value); - }; - } else { - getLength = function() { - return value.length; - }; } - var length = getLength(); - var ptr = _malloc(4 + length + 1); - ptr >>>= 0; - GROWABLE_HEAP_U32()[ptr >> 2] = length; - if (stdStringIsUTF8 && valueIsOfTypeString) { - stringToUTF8(value, ptr + 4, length + 1); - } else { - if (valueIsOfTypeString) { - for (var i = 0; i < length; ++i) { - var charCode = value.charCodeAt(i); - if (charCode > 255) { - _free(ptr); - throwBindingError("String has UTF-16 code units that do not fit in 8 bits"); - } - GROWABLE_HEAP_U8()[ptr + 4 + i] = charCode; - } - } else { - for (var i = 0; i < length; ++i) { - GROWABLE_HEAP_U8()[ptr + 4 + i] = value[i]; + + const src = params.src; + + this.viewer.metaScene.createMetaModel(metaModelId, metaModelData, { + + includeTypes: options.includeTypes, + excludeTypes: options.excludeTypes, + globalizeObjectIds: options.globalizeObjectIds, + + getProperties: async (propertiesId) => { + return await this._dataSource.getProperties(src, propertiesId); } - } - } - if (destructors !== null) { - destructors.push(_free, ptr); - } - return ptr; - }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: function(ptr) { - _free(ptr); - } }); + }); + + sceneModel.once("destroyed", () => { + this.viewer.metaScene.destroyMetaModel(metaModelId); + }); } - function __embind_register_std_wstring(rawType, charSize, name2) { - name2 = readLatin1String(name2); - var decodeString, encodeString, getHeap, lengthBytesUTF, shift; - if (charSize === 2) { - decodeString = UTF16ToString; - encodeString = stringToUTF16; - lengthBytesUTF = lengthBytesUTF16; - getHeap = function() { - return GROWABLE_HEAP_U16(); - }; - shift = 1; - } else if (charSize === 4) { - decodeString = UTF32ToString; - encodeString = stringToUTF32; - lengthBytesUTF = lengthBytesUTF32; - getHeap = function() { - return GROWABLE_HEAP_U32(); - }; - shift = 2; - } - registerType(rawType, { name: name2, "fromWireType": function(value) { - var length = GROWABLE_HEAP_U32()[value >> 2]; - var HEAP = getHeap(); - var str; - var decodeStartPtr = value + 4; - for (var i = 0; i <= length; ++i) { - var currentBytePtr = value + 4 + i * charSize; - if (i == length || HEAP[currentBytePtr >>> shift] == 0) { - var maxReadBytes = currentBytePtr - decodeStartPtr; - var stringSegment = decodeString(decodeStartPtr, maxReadBytes); - if (str === void 0) { - str = stringSegment; - } else { - str += String.fromCharCode(0); - str += stringSegment; - } - decodeStartPtr = currentBytePtr + charSize; - } - } - _free(value); - return str; - }, "toWireType": function(destructors, value) { - if (!(typeof value === "string")) { - throwBindingError("Cannot pass non-string to C++ string type " + name2); - } - var length = lengthBytesUTF(value); - var ptr = _malloc(4 + length + charSize); - ptr >>>= 0; - GROWABLE_HEAP_U32()[ptr >> 2] = length >> shift; - encodeString(value, ptr + 4, length + charSize); - if (destructors !== null) { - destructors.push(_free, ptr); - } - return ptr; - }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: function(ptr) { - _free(ptr); - } }); + } +} + +/* + Copyright (c) 2013 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @private + * @type {{}} + */ +var zipLib = {}; + +(function (obj) { + + var ERR_BAD_FORMAT = "File format is not recognized."; + var ERR_CRC = "CRC failed."; + var ERR_ENCRYPTED = "File contains encrypted entry."; + var ERR_ZIP64 = "File is using Zip64 (4gb+ file size)."; + var ERR_READ = "Error while reading zip file."; + var ERR_WRITE = "Error while writing zip file."; + var ERR_WRITE_DATA = "Error while writing file data."; + var ERR_READ_DATA = "Error while reading file data."; + var ERR_DUPLICATED_NAME = "File already exists."; + var CHUNK_SIZE = 512 * 1024; + + var TEXT_PLAIN = "text/plain"; + + var appendABViewSupported; + try { + appendABViewSupported = new Blob([new DataView(new ArrayBuffer(0))]).size === 0; + } catch (e) { + } + + function Crc32() { + this.crc = -1; + } + + Crc32.prototype.append = function append(data) { + var crc = this.crc | 0, table = this.table; + for (var offset = 0, len = data.length | 0; offset < len; offset++) + crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xFF]; + this.crc = crc; + }; + Crc32.prototype.get = function get() { + return ~this.crc; + }; + Crc32.prototype.table = (function () { + var i, j, t, table = []; // Uint32Array is actually slower than [] + for (i = 0; i < 256; i++) { + t = i; + for (j = 0; j < 8; j++) + if (t & 1) + t = (t >>> 1) ^ 0xEDB88320; + else + t = t >>> 1; + table[i] = t; } - function __embind_register_value_array(rawType, name2, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { - tupleRegistrations[rawType] = { name: readLatin1String(name2), rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), elements: [] }; + return table; + })(); + + // "no-op" codec + function NOOP() { + } + + NOOP.prototype.append = function append(bytes, onprogress) { + return bytes; + }; + NOOP.prototype.flush = function flush() { + }; + + function blobSlice(blob, index, length) { + if (index < 0 || length < 0 || index + length > blob.size) + throw new RangeError('offset:' + index + ', length:' + length + ', size:' + blob.size); + if (blob.slice) + return blob.slice(index, index + length); + else if (blob.webkitSlice) + return blob.webkitSlice(index, index + length); + else if (blob.mozSlice) + return blob.mozSlice(index, index + length); + else if (blob.msSlice) + return blob.msSlice(index, index + length); + } + + function getDataHelper(byteLength, bytes) { + var dataBuffer, dataArray; + dataBuffer = new ArrayBuffer(byteLength); + dataArray = new Uint8Array(dataBuffer); + if (bytes) + dataArray.set(bytes, 0); + return { + buffer: dataBuffer, + array: dataArray, + view: new DataView(dataBuffer) + }; + } + + // Readers + function Reader() { + } + + function TextReader(text) { + var that = this, blobReader; + + function init(callback, onerror) { + var blob = new Blob([text], { + type: TEXT_PLAIN + }); + blobReader = new BlobReader(blob); + blobReader.init(function () { + that.size = blobReader.size; + callback(); + }, onerror); } - function __embind_register_value_array_element(rawTupleType, getterReturnType, getterSignature, getter, getterContext, setterArgumentType, setterSignature, setter, setterContext) { - tupleRegistrations[rawTupleType].elements.push({ getterReturnType, getter: embind__requireFunction(getterSignature, getter), getterContext, setterArgumentType, setter: embind__requireFunction(setterSignature, setter), setterContext }); + + function readUint8Array(index, length, callback, onerror) { + blobReader.readUint8Array(index, length, callback, onerror); } - function __embind_register_value_object(rawType, name2, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { - structRegistrations[rawType] = { name: readLatin1String(name2), rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), fields: [] }; + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + + TextReader.prototype = new Reader(); + TextReader.prototype.constructor = TextReader; + + function Data64URIReader(dataURI) { + var that = this, dataStart; + + function init(callback) { + var dataEnd = dataURI.length; + while (dataURI.charAt(dataEnd - 1) == "=") + dataEnd--; + dataStart = dataURI.indexOf(",") + 1; + that.size = Math.floor((dataEnd - dataStart) * 0.75); + callback(); } - function __embind_register_value_object_field(structType, fieldName, getterReturnType, getterSignature, getter, getterContext, setterArgumentType, setterSignature, setter, setterContext) { - structRegistrations[structType].fields.push({ fieldName: readLatin1String(fieldName), getterReturnType, getter: embind__requireFunction(getterSignature, getter), getterContext, setterArgumentType, setter: embind__requireFunction(setterSignature, setter), setterContext }); + + function readUint8Array(index, length, callback) { + var i, data = getDataHelper(length); + var start = Math.floor(index / 3) * 4; + var end = Math.ceil((index + length) / 3) * 4; + var bytes = obj.atob(dataURI.substring(start + dataStart, end + dataStart)); + var delta = index - Math.floor(start / 4) * 3; + for (i = delta; i < delta + length; i++) + data.array[i - delta] = bytes.charCodeAt(i); + callback(data.array); } - function __embind_register_void(rawType, name2) { - name2 = readLatin1String(name2); - registerType(rawType, { isVoid: true, name: name2, "argPackAdvance": 0, "fromWireType": function() { - return void 0; - }, "toWireType": function(destructors, o) { - return void 0; - } }); + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + + Data64URIReader.prototype = new Reader(); + Data64URIReader.prototype.constructor = Data64URIReader; + + function BlobReader(blob) { + var that = this; + + function init(callback) { + that.size = blob.size; + callback(); } - function __emscripten_notify_thread_queue(targetThreadId, mainThreadId) { - if (targetThreadId == mainThreadId) { - postMessage({ "cmd": "processQueuedMainThreadWork" }); - } else if (ENVIRONMENT_IS_PTHREAD) { - postMessage({ "targetThread": targetThreadId, "cmd": "processThreadQueue" }); - } else { - var pthread = PThread.pthreads[targetThreadId]; - var worker = pthread && pthread.worker; - if (!worker) { - return; + + function readUint8Array(index, length, callback, onerror) { + var reader = new FileReader(); + reader.onload = function (e) { + callback(new Uint8Array(e.target.result)); + }; + reader.onerror = onerror; + try { + reader.readAsArrayBuffer(blobSlice(blob, index, length)); + } catch (e) { + onerror(e); } - worker.postMessage({ "cmd": "processThreadQueue" }); - } - return 1; - } - function requireHandle(handle) { - if (!handle) { - throwBindingError("Cannot use deleted val. handle = " + handle); - } - return emval_handle_array[handle].value; - } - function __emval_as(handle, returnType, destructorsRef) { - handle = requireHandle(handle); - returnType = requireRegisteredType(returnType, "emval::as"); - var destructors = []; - var rd = __emval_register(destructors); - GROWABLE_HEAP_I32()[destructorsRef >> 2] = rd; - return returnType["toWireType"](destructors, handle); } - function __emval_lookupTypes(argCount, argTypes) { - var a = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - a[i] = requireRegisteredType(GROWABLE_HEAP_I32()[(argTypes >> 2) + i], "parameter " + i); - } - return a; + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + + BlobReader.prototype = new Reader(); + BlobReader.prototype.constructor = BlobReader; + + // Writers + + function Writer() { + } + + Writer.prototype.getData = function (callback) { + callback(this.data); + }; + + function TextWriter(encoding) { + var that = this, blob; + + function init(callback) { + blob = new Blob([], { + type: TEXT_PLAIN + }); + callback(); } - function __emval_call(handle, argCount, argTypes, argv) { - handle = requireHandle(handle); - var types = __emval_lookupTypes(argCount, argTypes); - var args = new Array(argCount); - for (var i = 0; i < argCount; ++i) { - var type = types[i]; - args[i] = type["readValueFromPointer"](argv); - argv += type["argPackAdvance"]; - } - var rv = handle.apply(void 0, args); - return __emval_register(rv); + + function writeUint8Array(array, callback) { + blob = new Blob([blob, appendABViewSupported ? array : array.buffer], { + type: TEXT_PLAIN + }); + callback(); } - var emval_symbols = {}; - function getStringOrSymbol(address) { - var symbol = emval_symbols[address]; - if (symbol === void 0) { - return readLatin1String(address); - } else { - return symbol; - } + + function getData(callback, onerror) { + var reader = new FileReader(); + reader.onload = function (e) { + callback(e.target.result); + }; + reader.onerror = onerror; + reader.readAsText(blob, encoding); } - function emval_get_global() { - if (typeof globalThis === "object") { - return globalThis; - } - return function() { - return Function; - }()("return this")(); + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + + TextWriter.prototype = new Writer(); + TextWriter.prototype.constructor = TextWriter; + + function Data64URIWriter(contentType) { + var that = this, data = "", pending = ""; + + function init(callback) { + data += "data:" + (contentType || "") + ";base64,"; + callback(); } - function __emval_get_global(name2) { - if (name2 === 0) { - return __emval_register(emval_get_global()); - } else { - name2 = getStringOrSymbol(name2); - return __emval_register(emval_get_global()[name2]); - } + + function writeUint8Array(array, callback) { + var i, delta = pending.length, dataString = pending; + pending = ""; + for (i = 0; i < (Math.floor((delta + array.length) / 3) * 3) - delta; i++) + dataString += String.fromCharCode(array[i]); + for (; i < array.length; i++) + pending += String.fromCharCode(array[i]); + if (dataString.length > 2) + data += obj.btoa(dataString); + else + pending = dataString; + callback(); } - function __emval_get_property(handle, key2) { - handle = requireHandle(handle); - key2 = requireHandle(key2); - return __emval_register(handle[key2]); + + function getData(callback) { + callback(data + obj.btoa(pending)); } - function __emval_incref(handle) { - if (handle > 4) { - emval_handle_array[handle].refcount += 1; - } + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + + Data64URIWriter.prototype = new Writer(); + Data64URIWriter.prototype.constructor = Data64URIWriter; + + function BlobWriter(contentType) { + var blob, that = this; + + function init(callback) { + blob = new Blob([], { + type: contentType + }); + callback(); } - function __emval_instanceof(object, constructor) { - object = requireHandle(object); - constructor = requireHandle(constructor); - return object instanceof constructor; + + function writeUint8Array(array, callback) { + blob = new Blob([blob, appendABViewSupported ? array : array.buffer], { + type: contentType + }); + callback(); } - function __emval_is_number(handle) { - handle = requireHandle(handle); - return typeof handle === "number"; + + function getData(callback) { + callback(blob); } - function __emval_new_array() { - return __emval_register([]); + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + + BlobWriter.prototype = new Writer(); + BlobWriter.prototype.constructor = BlobWriter; + + /** + * inflate/deflate core functions + * @param worker {Worker} web worker for the task. + * @param initialMessage {Object} initial message to be sent to the worker. should contain + * sn(serial number for distinguishing multiple tasks sent to the worker), and codecClass. + * This function may add more properties before sending. + */ + function launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror) { + var chunkIndex = 0, index, outputSize, sn = initialMessage.sn, crc; + + function onflush() { + worker.removeEventListener('message', onmessage, false); + onend(outputSize, crc); } - function __emval_new_cstring(v) { - return __emval_register(getStringOrSymbol(v)); + + function onmessage(event) { + var message = event.data, data = message.data, err = message.error; + if (err) { + err.toString = function () { + return 'Error: ' + this.message; + }; + onreaderror(err); + return; + } + if (message.sn !== sn) + return; + if (typeof message.codecTime === 'number') + worker.codecTime += message.codecTime; // should be before onflush() + if (typeof message.crcTime === 'number') + worker.crcTime += message.crcTime; + + switch (message.type) { + case 'append': + if (data) { + outputSize += data.length; + writer.writeUint8Array(data, function () { + step(); + }, onwriteerror); + } else + step(); + break; + case 'flush': + crc = message.crc; + if (data) { + outputSize += data.length; + writer.writeUint8Array(data, function () { + onflush(); + }, onwriteerror); + } else + onflush(); + break; + case 'progress': + if (onprogress) + onprogress(index + message.loaded, size); + break; + case 'importScripts': //no need to handle here + case 'newTask': + case 'echo': + break; + default: + console.warn('zip.js:launchWorkerProcess: unknown message: ', message); + } } - function __emval_new_object() { - return __emval_register({}); + + function step() { + index = chunkIndex * CHUNK_SIZE; + // use `<=` instead of `<`, because `size` may be 0. + if (index <= size) { + reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function (array) { + if (onprogress) + onprogress(index, size); + var msg = index === 0 ? initialMessage : {sn: sn}; + msg.type = 'append'; + msg.data = array; + + // posting a message with transferables will fail on IE10 + try { + worker.postMessage(msg, [array.buffer]); + } catch (ex) { + worker.postMessage(msg); // retry without transferables + } + chunkIndex++; + }, onreaderror); + } else { + worker.postMessage({ + sn: sn, + type: 'flush' + }); + } } - function __emval_run_destructors(handle) { - var destructors = emval_handle_array[handle].value; - runDestructors(destructors); - __emval_decref(handle); + + outputSize = 0; + worker.addEventListener('message', onmessage, false); + step(); + } + + function launchProcess(process, reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror) { + var chunkIndex = 0, index, outputSize = 0, + crcInput = crcType === 'input', + crcOutput = crcType === 'output', + crc = new Crc32(); + + function step() { + var outputData; + index = chunkIndex * CHUNK_SIZE; + if (index < size) + reader.readUint8Array(offset + index, Math.min(CHUNK_SIZE, size - index), function (inputData) { + var outputData; + try { + outputData = process.append(inputData, function (loaded) { + if (onprogress) + onprogress(index + loaded, size); + }); + } catch (e) { + onreaderror(e); + return; + } + if (outputData) { + outputSize += outputData.length; + writer.writeUint8Array(outputData, function () { + chunkIndex++; + setTimeout(step, 1); + }, onwriteerror); + if (crcOutput) + crc.append(outputData); + } else { + chunkIndex++; + setTimeout(step, 1); + } + if (crcInput) + crc.append(inputData); + if (onprogress) + onprogress(index, size); + }, onreaderror); + else { + try { + outputData = process.flush(); + } catch (e) { + onreaderror(e); + return; + } + if (outputData) { + if (crcOutput) + crc.append(outputData); + outputSize += outputData.length; + writer.writeUint8Array(outputData, function () { + onend(outputSize, crc.get()); + }, onwriteerror); + } else + onend(outputSize, crc.get()); + } } - function __emval_set_property(handle, key2, value) { - handle = requireHandle(handle); - key2 = requireHandle(key2); - value = requireHandle(value); - handle[key2] = value; + + step(); + } + + function inflate(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { + var crcType = computeCrc32 ? 'output' : 'none'; + if (obj.zip.useWebWorkers) { + var initialMessage = { + sn: sn, + codecClass: 'Inflater', + crcType: crcType, + }; + launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror); + } else + launchProcess(new obj.zip.Inflater(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror); + } + + function deflate(worker, sn, reader, writer, level, onend, onprogress, onreaderror, onwriteerror) { + var crcType = 'input'; + if (obj.zip.useWebWorkers) { + var initialMessage = { + sn: sn, + options: {level: level}, + codecClass: 'Deflater', + crcType: crcType, + }; + launchWorkerProcess(worker, initialMessage, reader, writer, 0, reader.size, onprogress, onend, onreaderror, onwriteerror); + } else + launchProcess(new obj.zip.Deflater(), reader, writer, 0, reader.size, crcType, onprogress, onend, onreaderror, onwriteerror); + } + + function copy(worker, sn, reader, writer, offset, size, computeCrc32, onend, onprogress, onreaderror, onwriteerror) { + var crcType = 'input'; + if (obj.zip.useWebWorkers && computeCrc32) { + var initialMessage = { + sn: sn, + codecClass: 'NOOP', + crcType: crcType, + }; + launchWorkerProcess(worker, initialMessage, reader, writer, offset, size, onprogress, onend, onreaderror, onwriteerror); + } else + launchProcess(new NOOP(), reader, writer, offset, size, crcType, onprogress, onend, onreaderror, onwriteerror); + } + + // ZipReader + + function decodeASCII(str) { + var i, out = "", charCode, extendedASCII = ['\u00C7', '\u00FC', '\u00E9', '\u00E2', '\u00E4', '\u00E0', '\u00E5', '\u00E7', '\u00EA', '\u00EB', + '\u00E8', '\u00EF', '\u00EE', '\u00EC', '\u00C4', '\u00C5', '\u00C9', '\u00E6', '\u00C6', '\u00F4', '\u00F6', '\u00F2', '\u00FB', '\u00F9', + '\u00FF', '\u00D6', '\u00DC', '\u00F8', '\u00A3', '\u00D8', '\u00D7', '\u0192', '\u00E1', '\u00ED', '\u00F3', '\u00FA', '\u00F1', '\u00D1', + '\u00AA', '\u00BA', '\u00BF', '\u00AE', '\u00AC', '\u00BD', '\u00BC', '\u00A1', '\u00AB', '\u00BB', '_', '_', '_', '\u00A6', '\u00A6', + '\u00C1', '\u00C2', '\u00C0', '\u00A9', '\u00A6', '\u00A6', '+', '+', '\u00A2', '\u00A5', '+', '+', '-', '-', '+', '-', '+', '\u00E3', + '\u00C3', '+', '+', '-', '-', '\u00A6', '-', '+', '\u00A4', '\u00F0', '\u00D0', '\u00CA', '\u00CB', '\u00C8', 'i', '\u00CD', '\u00CE', + '\u00CF', '+', '+', '_', '_', '\u00A6', '\u00CC', '_', '\u00D3', '\u00DF', '\u00D4', '\u00D2', '\u00F5', '\u00D5', '\u00B5', '\u00FE', + '\u00DE', '\u00DA', '\u00DB', '\u00D9', '\u00FD', '\u00DD', '\u00AF', '\u00B4', '\u00AD', '\u00B1', '_', '\u00BE', '\u00B6', '\u00A7', + '\u00F7', '\u00B8', '\u00B0', '\u00A8', '\u00B7', '\u00B9', '\u00B3', '\u00B2', '_', ' ']; + for (i = 0; i < str.length; i++) { + charCode = str.charCodeAt(i) & 0xFF; + if (charCode > 127) + out += extendedASCII[charCode - 128]; + else + out += String.fromCharCode(charCode); } - function __emval_take_value(type, argv) { - type = requireRegisteredType(type, "_emval_take_value"); - var v = type["readValueFromPointer"](argv); - return __emval_register(v); + return out; + } + + function decodeUTF8(string) { + return decodeURIComponent(escape(string)); + } + + function getString(bytes) { + var i, str = ""; + for (i = 0; i < bytes.length; i++) + str += String.fromCharCode(bytes[i]); + return str; + } + + function getDate(timeRaw) { + var date = (timeRaw & 0xffff0000) >> 16, time = timeRaw & 0x0000ffff; + try { + return new Date(1980 + ((date & 0xFE00) >> 9), ((date & 0x01E0) >> 5) - 1, date & 0x001F, (time & 0xF800) >> 11, (time & 0x07E0) >> 5, + (time & 0x001F) * 2, 0); + } catch (e) { } - function _abort() { - abort(); + } + + function readCommonHeader(entry, data, index, centralDirectory, onerror) { + entry.version = data.view.getUint16(index, true); + entry.bitFlag = data.view.getUint16(index + 2, true); + entry.compressionMethod = data.view.getUint16(index + 4, true); + entry.lastModDateRaw = data.view.getUint32(index + 6, true); + entry.lastModDate = getDate(entry.lastModDateRaw); + if ((entry.bitFlag & 0x01) === 0x01) { + onerror(ERR_ENCRYPTED); + return; } - function _emscripten_asm_const_int(code, sigPtr, argbuf) { - var args = readAsmConstArgs(sigPtr, argbuf); - return ASM_CONSTS[code].apply(null, args); + if (centralDirectory || (entry.bitFlag & 0x0008) != 0x0008) { + entry.crc32 = data.view.getUint32(index + 10, true); + entry.compressedSize = data.view.getUint32(index + 14, true); + entry.uncompressedSize = data.view.getUint32(index + 18, true); } - function _emscripten_check_blocking_allowed() { - if (ENVIRONMENT_IS_NODE) - return; - if (ENVIRONMENT_IS_WORKER) + if (entry.compressedSize === 0xFFFFFFFF || entry.uncompressedSize === 0xFFFFFFFF) { + onerror(ERR_ZIP64); return; - warnOnce("Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread"); } - function _emscripten_conditional_set_current_thread_status(expectedStatus, newStatus) { + entry.filenameLength = data.view.getUint16(index + 22, true); + entry.extraFieldLength = data.view.getUint16(index + 24, true); + } + + function createZipReader(reader, callback, onerror) { + var inflateSN = 0; + + function Entry() { } - function _emscripten_futex_wait(addr, val, timeout) { - if (addr <= 0 || addr > GROWABLE_HEAP_I8().length || addr & true) - return -28; - if (!ENVIRONMENT_IS_WEB) { - var ret = Atomics.wait(GROWABLE_HEAP_I32(), addr >> 2, val, timeout); - if (ret === "timed-out") - return -73; - if (ret === "not-equal") - return -6; - if (ret === "ok") - return 0; - throw "Atomics.wait returned an unexpected value " + ret; - } else { - if (Atomics.load(GROWABLE_HEAP_I32(), addr >> 2) != val) { - return -6; + + Entry.prototype.getData = function (writer, onend, onprogress, checkCrc32) { + var that = this; + + function testCrc32(crc32) { + var dataCrc32 = getDataHelper(4); + dataCrc32.view.setUint32(0, crc32); + return that.crc32 == dataCrc32.view.getUint32(0); } - var tNow = performance.now(); - var tEnd = tNow + timeout; - var lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), PThread.mainThreadFutex >> 2, addr); - while (1) { - tNow = performance.now(); - if (tNow > tEnd) { - lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), PThread.mainThreadFutex >> 2, 0); - return -73; - } - lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), PThread.mainThreadFutex >> 2, 0); - if (lastAddr == 0) { - break; - } - _emscripten_main_thread_process_queued_calls(); - if (Atomics.load(GROWABLE_HEAP_I32(), addr >> 2) != val) { - return -6; - } - lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), PThread.mainThreadFutex >> 2, addr); + + function getWriterData(uncompressedSize, crc32) { + if (checkCrc32 && !testCrc32(crc32)) + onerror(ERR_CRC); + else + writer.getData(function (data) { + onend(data); + }); } - return 0; - } - } - function _emscripten_is_main_browser_thread() { - return __pthread_is_main_browser_thread | 0; - } - function _emscripten_is_main_runtime_thread() { - return __pthread_is_main_runtime_thread | 0; - } - function _emscripten_memcpy_big(dest, src, num) { - GROWABLE_HEAP_U8().copyWithin(dest, src, src + num); - } - function _emscripten_proxy_to_main_thread_js(index, sync) { - var numCallArgs = arguments.length - 2; - var stack = stackSave(); - var args = stackAlloc(numCallArgs * 8); - var b = args >> 3; - for (var i = 0; i < numCallArgs; i++) { - GROWABLE_HEAP_F64()[b + i] = arguments[2 + i]; - } - var ret = _emscripten_run_in_main_runtime_thread_js(index, numCallArgs, args, sync); - stackRestore(stack); - return ret; - } - var _emscripten_receive_on_main_thread_js_callArgs = []; - var readAsmConstArgsArray = []; - function readAsmConstArgs(sigPtr, buf) { - readAsmConstArgsArray.length = 0; - var ch; - buf >>= 2; - while (ch = GROWABLE_HEAP_U8()[sigPtr++]) { - var double = ch < 105; - if (double && buf & 1) - buf++; - readAsmConstArgsArray.push(double ? GROWABLE_HEAP_F64()[buf++ >> 1] : GROWABLE_HEAP_I32()[buf]); - ++buf; - } - return readAsmConstArgsArray; - } - function _emscripten_receive_on_main_thread_js(index, numCallArgs, args) { - _emscripten_receive_on_main_thread_js_callArgs.length = numCallArgs; - var b = args >> 3; - for (var i = 0; i < numCallArgs; i++) { - _emscripten_receive_on_main_thread_js_callArgs[i] = GROWABLE_HEAP_F64()[b + i]; - } - var isEmAsmConst = index < 0; - var func = !isEmAsmConst ? proxiedFunctionTable[index] : ASM_CONSTS[-index - 1]; - return func.apply(null, _emscripten_receive_on_main_thread_js_callArgs); - } - function _emscripten_get_heap_size() { - return GROWABLE_HEAP_U8().length; - } - function emscripten_realloc_buffer(size) { - try { - wasmMemory.grow(size - buffer.byteLength + 65535 >>> 16); - updateGlobalBufferAndViews(wasmMemory.buffer); - return 1; - } catch (e) { - } - } - function _emscripten_resize_heap(requestedSize) { - requestedSize = requestedSize >>> 0; - var oldSize = _emscripten_get_heap_size(); - if (requestedSize <= oldSize) { - return false; - } - var maxHeapSize = 4294967296; - if (requestedSize > maxHeapSize) { - return false; - } - var minHeapSize = 16777216; - for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { - var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); - overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296); - var newSize = Math.min(maxHeapSize, alignUp(Math.max(minHeapSize, requestedSize, overGrownHeapSize), 65536)); - var replacement = emscripten_realloc_buffer(newSize); - if (replacement) { - return true; + + function onreaderror(err) { + onerror(err || ERR_READ_DATA); } - } - return false; - } - var JSEvents = { inEventHandler: 0, removeAllEventListeners: function() { - for (var i = JSEvents.eventHandlers.length - 1; i >= 0; --i) { - JSEvents._removeHandler(i); - } - JSEvents.eventHandlers = []; - JSEvents.deferredCalls = []; - }, registerRemoveEventListeners: function() { - if (!JSEvents.removeEventListenersRegistered) { - JSEvents.removeEventListenersRegistered = true; - } - }, deferredCalls: [], deferCall: function(targetFunction, precedence, argsList) { - function arraysHaveEqualContent(arrA, arrB) { - if (arrA.length != arrB.length) - return false; - for (var i2 in arrA) { - if (arrA[i2] != arrB[i2]) - return false; - } - return true; - } - for (var i in JSEvents.deferredCalls) { - var call = JSEvents.deferredCalls[i]; - if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { - return; - } - } - JSEvents.deferredCalls.push({ targetFunction, precedence, argsList }); - JSEvents.deferredCalls.sort(function(x, y) { - return x.precedence < y.precedence; - }); - }, removeDeferredCalls: function(targetFunction) { - for (var i = 0; i < JSEvents.deferredCalls.length; ++i) { - if (JSEvents.deferredCalls[i].targetFunction == targetFunction) { - JSEvents.deferredCalls.splice(i, 1); - --i; + + function onwriteerror(err) { + onerror(err || ERR_WRITE_DATA); } - } - }, canPerformEventHandlerRequests: function() { - return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; - }, runDeferredCalls: function() { - if (!JSEvents.canPerformEventHandlerRequests()) { - return; - } - for (var i = 0; i < JSEvents.deferredCalls.length; ++i) { - var call = JSEvents.deferredCalls[i]; - JSEvents.deferredCalls.splice(i, 1); - --i; - call.targetFunction.apply(null, call.argsList); - } - }, eventHandlers: [], removeAllHandlersOnTarget: function(target, eventTypeString) { - for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { - if (JSEvents.eventHandlers[i].target == target && (!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) { - JSEvents._removeHandler(i--); + + reader.readUint8Array(that.offset, 30, function (bytes) { + var data = getDataHelper(bytes.length, bytes), dataOffset; + if (data.view.getUint32(0) != 0x504b0304) { + onerror(ERR_BAD_FORMAT); + return; + } + readCommonHeader(that, data, 4, false, onerror); + dataOffset = that.offset + 30 + that.filenameLength + that.extraFieldLength; + writer.init(function () { + if (that.compressionMethod === 0) + copy(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); + else + inflate(that._worker, inflateSN++, reader, writer, dataOffset, that.compressedSize, checkCrc32, getWriterData, onprogress, onreaderror, onwriteerror); + }, onwriteerror); + }, onreaderror); + }; + + function seekEOCDR(eocdrCallback) { + // "End of central directory record" is the last part of a zip archive, and is at least 22 bytes long. + // Zip file comment is the last part of EOCDR and has max length of 64KB, + // so we only have to search the last 64K + 22 bytes of a archive for EOCDR signature (0x06054b50). + var EOCDR_MIN = 22; + if (reader.size < EOCDR_MIN) { + onerror(ERR_BAD_FORMAT); + return; } - } - }, _removeHandler: function(i) { - var h = JSEvents.eventHandlers[i]; - h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture); - JSEvents.eventHandlers.splice(i, 1); - }, registerOrRemoveHandler: function(eventHandler) { - var jsEventHandler = function jsEventHandler2(event) { - ++JSEvents.inEventHandler; - JSEvents.currentEventHandler = eventHandler; - JSEvents.runDeferredCalls(); - eventHandler.handlerFunc(event); - JSEvents.runDeferredCalls(); - --JSEvents.inEventHandler; - }; - if (eventHandler.callbackfunc) { - eventHandler.eventListenerFunc = jsEventHandler; - eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture); - JSEvents.eventHandlers.push(eventHandler); - JSEvents.registerRemoveEventListeners(); - } else { - for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { - if (JSEvents.eventHandlers[i].target == eventHandler.target && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { - JSEvents._removeHandler(i--); - } + var ZIP_COMMENT_MAX = 256 * 256, EOCDR_MAX = EOCDR_MIN + ZIP_COMMENT_MAX; + + // In most cases, the EOCDR is EOCDR_MIN bytes long + doSeek(EOCDR_MIN, function () { + // If not found, try within EOCDR_MAX bytes + doSeek(Math.min(EOCDR_MAX, reader.size), function () { + onerror(ERR_BAD_FORMAT); + }); + }); + + // seek last length bytes of file for EOCDR + function doSeek(length, eocdrNotFoundCallback) { + reader.readUint8Array(reader.size - length, length, function (bytes) { + for (var i = bytes.length - EOCDR_MIN; i >= 0; i--) { + if (bytes[i] === 0x50 && bytes[i + 1] === 0x4b && bytes[i + 2] === 0x05 && bytes[i + 3] === 0x06) { + eocdrCallback(new DataView(bytes.buffer, i, EOCDR_MIN)); + return; + } + } + eocdrNotFoundCallback(); + }, function () { + onerror(ERR_READ); + }); } - } - }, queueEventHandlerOnThread_iiii: function(targetThread, eventHandlerFunc, eventTypeId, eventData, userData) { - var stackTop = stackSave(); - var varargs = stackAlloc(12); - GROWABLE_HEAP_I32()[varargs >> 2] = eventTypeId; - GROWABLE_HEAP_I32()[varargs + 4 >> 2] = eventData; - GROWABLE_HEAP_I32()[varargs + 8 >> 2] = userData; - __emscripten_call_on_thread(0, targetThread, 637534208, eventHandlerFunc, eventData, varargs); - stackRestore(stackTop); - }, getTargetThreadForEventCallback: function(targetThread) { - switch (targetThread) { - case 1: - return 0; - case 2: - return PThread.currentProxiedOperationCallerThread; - default: - return targetThread; - } - }, getNodeNameForTarget: function(target) { - if (!target) - return ""; - if (target == window) - return "#window"; - if (target == screen) - return "#screen"; - return target && target.nodeName ? target.nodeName : ""; - }, fullscreenEnabled: function() { - return document.fullscreenEnabled || document.webkitFullscreenEnabled; - } }; - function stringToNewUTF8(jsString) { - var length = lengthBytesUTF8(jsString) + 1; - var cString = _malloc(length); - stringToUTF8(jsString, cString, length); - return cString; } - function _emscripten_set_offscreencanvas_size_on_target_thread_js(targetThread, targetCanvas, width, height) { - var stackTop = stackSave(); - var varargs = stackAlloc(12); - var targetCanvasPtr = 0; - if (targetCanvas) { - targetCanvasPtr = stringToNewUTF8(targetCanvas); - } - GROWABLE_HEAP_I32()[varargs >> 2] = targetCanvasPtr; - GROWABLE_HEAP_I32()[varargs + 4 >> 2] = width; - GROWABLE_HEAP_I32()[varargs + 8 >> 2] = height; - __emscripten_call_on_thread(0, targetThread, 657457152, 0, targetCanvasPtr, varargs); - stackRestore(stackTop); + + var zipReader = { + getEntries: function (callback) { + var worker = this._worker; + // look for End of central directory record + seekEOCDR(function (dataView) { + var datalength, fileslength; + datalength = dataView.getUint32(16, true); + fileslength = dataView.getUint16(8, true); + if (datalength < 0 || datalength >= reader.size) { + onerror(ERR_BAD_FORMAT); + return; + } + reader.readUint8Array(datalength, reader.size - datalength, function (bytes) { + var i, index = 0, entries = [], entry, filename, comment, data = getDataHelper(bytes.length, bytes); + for (i = 0; i < fileslength; i++) { + entry = new Entry(); + entry._worker = worker; + if (data.view.getUint32(index) != 0x504b0102) { + onerror(ERR_BAD_FORMAT); + return; + } + readCommonHeader(entry, data, index + 6, true, onerror); + entry.commentLength = data.view.getUint16(index + 32, true); + entry.directory = ((data.view.getUint8(index + 38) & 0x10) == 0x10); + entry.offset = data.view.getUint32(index + 42, true); + filename = getString(data.array.subarray(index + 46, index + 46 + entry.filenameLength)); + entry.filename = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(filename) : decodeASCII(filename); + if (!entry.directory && entry.filename.charAt(entry.filename.length - 1) == "/") + entry.directory = true; + comment = getString(data.array.subarray(index + 46 + entry.filenameLength + entry.extraFieldLength, index + 46 + + entry.filenameLength + entry.extraFieldLength + entry.commentLength)); + entry.comment = ((entry.bitFlag & 0x0800) === 0x0800) ? decodeUTF8(comment) : decodeASCII(comment); + entries.push(entry); + index += 46 + entry.filenameLength + entry.extraFieldLength + entry.commentLength; + } + callback(entries); + }, function () { + onerror(ERR_READ); + }); + }); + }, + close: function (callback) { + if (this._worker) { + this._worker.terminate(); + this._worker = null; + } + if (callback) + callback(); + }, + _worker: null + }; + + if (!obj.zip.useWebWorkers) + callback(zipReader); + else { + createWorker('inflater', + function (worker) { + zipReader._worker = worker; + callback(zipReader); + }, + function (err) { + onerror(err); + } + ); } - function _emscripten_set_offscreencanvas_size_on_target_thread(targetThread, targetCanvas, width, height) { - targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : ""; - _emscripten_set_offscreencanvas_size_on_target_thread_js(targetThread, targetCanvas, width, height); + } + + // ZipWriter + + function encodeUTF8(string) { + return unescape(encodeURIComponent(string)); + } + + function getBytes(str) { + var i, array = []; + for (i = 0; i < str.length; i++) + array.push(str.charCodeAt(i)); + return array; + } + + function createZipWriter(writer, callback, onerror, dontDeflate) { + var files = {}, filenames = [], datalength = 0; + var deflateSN = 0; + + function onwriteerror(err) { + onerror(err || ERR_WRITE); } - function maybeCStringToJsString(cString) { - return cString > 2 ? UTF8ToString(cString) : cString; + + function onreaderror(err) { + onerror(err || ERR_READ_DATA); } - var specialHTMLTargets = [0, typeof document !== "undefined" ? document : 0, typeof window !== "undefined" ? window : 0]; - function findEventTarget(target) { - target = maybeCStringToJsString(target); - var domElement = specialHTMLTargets[target] || (typeof document !== "undefined" ? document.querySelector(target) : void 0); - return domElement; + + var zipWriter = { + add: function (name, reader, onend, onprogress, options) { + var header, filename, date; + var worker = this._worker; + + function writeHeader(callback) { + var data; + date = options.lastModDate || new Date(); + header = getDataHelper(26); + files[name] = { + headerArray: header.array, + directory: options.directory, + filename: filename, + offset: datalength, + comment: getBytes(encodeUTF8(options.comment || "")) + }; + header.view.setUint32(0, 0x14000808); + if (options.version) + header.view.setUint8(0, options.version); + if (!dontDeflate && options.level !== 0 && !options.directory) + header.view.setUint16(4, 0x0800); + header.view.setUint16(6, (((date.getHours() << 6) | date.getMinutes()) << 5) | date.getSeconds() / 2, true); + header.view.setUint16(8, ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << 5) | date.getDate(), true); + header.view.setUint16(22, filename.length, true); + data = getDataHelper(30 + filename.length); + data.view.setUint32(0, 0x504b0304); + data.array.set(header.array, 4); + data.array.set(filename, 30); + datalength += data.array.length; + writer.writeUint8Array(data.array, callback, onwriteerror); + } + + function writeFooter(compressedLength, crc32) { + var footer = getDataHelper(16); + datalength += compressedLength || 0; + footer.view.setUint32(0, 0x504b0708); + if (typeof crc32 != "undefined") { + header.view.setUint32(10, crc32, true); + footer.view.setUint32(4, crc32, true); + } + if (reader) { + footer.view.setUint32(8, compressedLength, true); + header.view.setUint32(14, compressedLength, true); + footer.view.setUint32(12, reader.size, true); + header.view.setUint32(18, reader.size, true); + } + writer.writeUint8Array(footer.array, function () { + datalength += 16; + onend(); + }, onwriteerror); + } + + function writeFile() { + options = options || {}; + name = name.trim(); + if (options.directory && name.charAt(name.length - 1) != "/") + name += "/"; + if (files.hasOwnProperty(name)) { + onerror(ERR_DUPLICATED_NAME); + return; + } + filename = getBytes(encodeUTF8(name)); + filenames.push(name); + writeHeader(function () { + if (reader) + if (dontDeflate || options.level === 0) + copy(worker, deflateSN++, reader, writer, 0, reader.size, true, writeFooter, onprogress, onreaderror, onwriteerror); + else + deflate(worker, deflateSN++, reader, writer, options.level, writeFooter, onprogress, onreaderror, onwriteerror); + else + writeFooter(); + }); + } + + if (reader) + reader.init(writeFile, onreaderror); + else + writeFile(); + }, + close: function (callback) { + if (this._worker) { + this._worker.terminate(); + this._worker = null; + } + + var data, length = 0, index = 0, indexFilename, file; + for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { + file = files[filenames[indexFilename]]; + length += 46 + file.filename.length + file.comment.length; + } + data = getDataHelper(length + 22); + for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { + file = files[filenames[indexFilename]]; + data.view.setUint32(index, 0x504b0102); + data.view.setUint16(index + 4, 0x1400); + data.array.set(file.headerArray, index + 6); + data.view.setUint16(index + 32, file.comment.length, true); + if (file.directory) + data.view.setUint8(index + 38, 0x10); + data.view.setUint32(index + 42, file.offset, true); + data.array.set(file.filename, index + 46); + data.array.set(file.comment, index + 46 + file.filename.length); + index += 46 + file.filename.length + file.comment.length; + } + data.view.setUint32(index, 0x504b0506); + data.view.setUint16(index + 8, filenames.length, true); + data.view.setUint16(index + 10, filenames.length, true); + data.view.setUint32(index + 12, length, true); + data.view.setUint32(index + 16, datalength, true); + writer.writeUint8Array(data.array, function () { + writer.getData(callback); + }, onwriteerror); + }, + _worker: null + }; + + if (!obj.zip.useWebWorkers) + callback(zipWriter); + else { + createWorker('deflater', + function (worker) { + zipWriter._worker = worker; + callback(zipWriter); + }, + function (err) { + onerror(err); + } + ); } - function findCanvasEventTarget(target) { - return findEventTarget(target); + } + + function resolveURLs(urls) { + var a = document.createElement('a'); + return urls.map(function (url) { + a.href = url; + return a.href; + }); + } + + var DEFAULT_WORKER_SCRIPTS = { + deflater: ['z-worker.js', 'deflate.js'], + inflater: ['z-worker.js', 'inflate.js'] + }; + + function createWorker(type, callback, onerror) { + if (obj.zip.workerScripts !== null && obj.zip.workerScriptsPath !== null) { + onerror(new Error('Either zip.workerScripts or zip.workerScriptsPath may be set, not both.')); + return; } - function _emscripten_set_canvas_element_size_calling_thread(target, width, height) { - var canvas = findCanvasEventTarget(target); - if (!canvas) - return -4; - if (canvas.canvasSharedPtr) { - GROWABLE_HEAP_I32()[canvas.canvasSharedPtr >> 2] = width; - GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 4 >> 2] = height; - } - if (canvas.offscreenCanvas || !canvas.controlTransferredOffscreen) { - if (canvas.offscreenCanvas) - canvas = canvas.offscreenCanvas; - var autoResizeViewport = false; - if (canvas.GLctxObject && canvas.GLctxObject.GLctx) { - var prevViewport = canvas.GLctxObject.GLctx.getParameter(2978); - autoResizeViewport = prevViewport[0] === 0 && prevViewport[1] === 0 && prevViewport[2] === canvas.width && prevViewport[3] === canvas.height; + var scripts; + if (obj.zip.workerScripts) { + scripts = obj.zip.workerScripts[type]; + if (!Array.isArray(scripts)) { + onerror(new Error('zip.workerScripts.' + type + ' is not an array!')); + return; } - canvas.width = width; - canvas.height = height; - if (autoResizeViewport) { - canvas.GLctxObject.GLctx.viewport(0, 0, width, height); + scripts = resolveURLs(scripts); + } else { + scripts = DEFAULT_WORKER_SCRIPTS[type].slice(0); + scripts[0] = (obj.zip.workerScriptsPath || '') + scripts[0]; + } + var worker = new Worker(scripts[0]); + // record total consumed time by inflater/deflater/crc32 in this worker + worker.codecTime = worker.crcTime = 0; + worker.postMessage({type: 'importScripts', scripts: scripts.slice(1)}); + worker.addEventListener('message', onmessage); + function onmessage(ev) { + var msg = ev.data; + if (msg.error) { + worker.terminate(); // should before onerror(), because onerror() may throw. + onerror(msg.error); + return; + } + if (msg.type === 'importScripts') { + worker.removeEventListener('message', onmessage); + worker.removeEventListener('error', errorHandler); + callback(worker); } - } else if (canvas.canvasSharedPtr) { - var targetThread = GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 8 >> 2]; - _emscripten_set_offscreencanvas_size_on_target_thread(targetThread, target, width, height); - return 1; - } else { - return -4; - } - return 0; } - function _emscripten_set_canvas_element_size_main_thread(target, width, height) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(4, 1, target, width, height); - return _emscripten_set_canvas_element_size_calling_thread(target, width, height); + + // catch entry script loading error and other unhandled errors + worker.addEventListener('error', errorHandler); + function errorHandler(err) { + worker.terminate(); + onerror(err); } - function _emscripten_set_canvas_element_size(target, width, height) { - var canvas = findCanvasEventTarget(target); - if (canvas) { - return _emscripten_set_canvas_element_size_calling_thread(target, width, height); - } else { - return _emscripten_set_canvas_element_size_main_thread(target, width, height); - } + } + + function onerror_default(error) { + console.error(error); + } + + obj.zip = { + Reader: Reader, + Writer: Writer, + BlobReader: BlobReader, + Data64URIReader: Data64URIReader, + TextReader: TextReader, + BlobWriter: BlobWriter, + Data64URIWriter: Data64URIWriter, + TextWriter: TextWriter, + createReader: function (reader, callback, onerror) { + onerror = onerror || onerror_default; + + reader.init(function () { + createZipReader(reader, callback, onerror); + }, onerror); + }, + createWriter: function (writer, callback, onerror, dontDeflate) { + onerror = onerror || onerror_default; + dontDeflate = !!dontDeflate; + + writer.init(function () { + createZipWriter(writer, callback, onerror, dontDeflate); + }, onerror); + }, + useWebWorkers: true, + /** + * Directory containing the default worker scripts (z-worker.js, deflate.js, and inflate.js), relative to current base url. + * E.g.: zip.workerScripts = './'; + */ + workerScriptsPath: null, + /** + * Advanced option to control which scripts are loaded in the Web worker. If this option is specified, then workerScriptsPath must not be set. + * workerScripts.deflater/workerScripts.inflater should be arrays of urls to scripts for deflater/inflater, respectively. + * Scripts in the array are executed in order, and the first one should be z-worker.js, which is used to start the worker. + * All urls are relative to current base url. + * E.g.: + * zip.workerScripts = { + * deflater: ['z-worker.js', 'deflate.js'], + * inflater: ['z-worker.js', 'inflate.js'] + * }; + */ + workerScripts: null, + }; + +})(zipLib); + +/* + Copyright (c) 2013 Gildas Lormeau. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + + 3. The names of the authors may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT, + INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @private + */ +const zipExt = function(zipObj) { + + var ERR_HTTP_RANGE = "HTTP Range not supported."; + + var Reader = zipObj.Reader; + var Writer = zipObj.Writer; + + var ZipDirectoryEntry; + + var appendABViewSupported; + try { + appendABViewSupported = new Blob([new DataView(new ArrayBuffer(0))]).size === 0; + } catch (e) { + } + + function isHttpFamily(url) { + var a = document.createElement("a"); + a.href = url; + return a.protocol === "http:" || a.protocol === "https:"; + } + + function HttpReader(url) { + var that = this; + + function getData(callback, onerror) { + var request; + if (!that.data) { + request = new XMLHttpRequest(); + request.addEventListener("load", function () { + if (!that.size) + that.size = Number(request.getResponseHeader("Content-Length")) || Number(request.response.byteLength); + that.data = new Uint8Array(request.response); + callback(); + }, false); + request.addEventListener("error", onerror, false); + request.open("GET", url); + request.responseType = "arraybuffer"; + request.send(); + } else + callback(); + } + + function init(callback, onerror) { + if (!isHttpFamily(url)) { + // For schemas other than http(s), HTTP HEAD may be unavailable, + // so use HTTP GET instead. + getData(callback, onerror); + return; + } + var request = new XMLHttpRequest(); + request.addEventListener("load", function () { + that.size = Number(request.getResponseHeader("Content-Length")); + // If response header doesn't return size then prefetch the content. + if (!that.size) { + getData(callback, onerror); + } else { + callback(); + } + }, false); + request.addEventListener("error", onerror, false); + request.open("HEAD", url); + request.send(); + } + + function readUint8Array(index, length, callback, onerror) { + getData(function () { + callback(new Uint8Array(that.data.subarray(index, index + length))); + }, onerror); + } + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + + HttpReader.prototype = new Reader(); + HttpReader.prototype.constructor = HttpReader; + + function HttpRangeReader(url) { + var that = this; + + function init(callback, onerror) { + var request = new XMLHttpRequest(); + request.addEventListener("load", function () { + that.size = Number(request.getResponseHeader("Content-Length")); + if (request.getResponseHeader("Accept-Ranges") == "bytes") + callback(); + else + onerror(ERR_HTTP_RANGE); + }, false); + request.addEventListener("error", onerror, false); + request.open("HEAD", url); + request.send(); + } + + function readArrayBuffer(index, length, callback, onerror) { + var request = new XMLHttpRequest(); + request.open("GET", url); + request.responseType = "arraybuffer"; + request.setRequestHeader("Range", "bytes=" + index + "-" + (index + length - 1)); + request.addEventListener("load", function () { + callback(request.response); + }, false); + request.addEventListener("error", onerror, false); + request.send(); + } + + function readUint8Array(index, length, callback, onerror) { + readArrayBuffer(index, length, function (arraybuffer) { + callback(new Uint8Array(arraybuffer)); + }, onerror); + } + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + + HttpRangeReader.prototype = new Reader(); + HttpRangeReader.prototype.constructor = HttpRangeReader; + + function ArrayBufferReader(arrayBuffer) { + var that = this; + + function init(callback, onerror) { + that.size = arrayBuffer.byteLength; + callback(); + } + + function readUint8Array(index, length, callback, onerror) { + callback(new Uint8Array(arrayBuffer.slice(index, index + length))); + } + + that.size = 0; + that.init = init; + that.readUint8Array = readUint8Array; + } + + ArrayBufferReader.prototype = new Reader(); + ArrayBufferReader.prototype.constructor = ArrayBufferReader; + + function ArrayBufferWriter() { + var array, that = this; + + function init(callback, onerror) { + array = new Uint8Array(); + callback(); + } + + function writeUint8Array(arr, callback, onerror) { + var tmpArray = new Uint8Array(array.length + arr.length); + tmpArray.set(array); + tmpArray.set(arr, array.length); + array = tmpArray; + callback(); + } + + function getData(callback) { + callback(array.buffer); + } + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + + ArrayBufferWriter.prototype = new Writer(); + ArrayBufferWriter.prototype.constructor = ArrayBufferWriter; + + function FileWriter(fileEntry, contentType) { + var writer, that = this; + + function init(callback, onerror) { + fileEntry.createWriter(function (fileWriter) { + writer = fileWriter; + callback(); + }, onerror); + } + + function writeUint8Array(array, callback, onerror) { + var blob = new Blob([appendABViewSupported ? array : array.buffer], { + type: contentType + }); + writer.onwrite = function () { + writer.onwrite = null; + callback(); + }; + writer.onerror = onerror; + writer.write(blob); + } + + function getData(callback) { + fileEntry.file(callback); + } + + that.init = init; + that.writeUint8Array = writeUint8Array; + that.getData = getData; + } + + FileWriter.prototype = new Writer(); + FileWriter.prototype.constructor = FileWriter; + + zipObj.FileWriter = FileWriter; + zipObj.HttpReader = HttpReader; + zipObj.HttpRangeReader = HttpRangeReader; + zipObj.ArrayBufferReader = ArrayBufferReader; + zipObj.ArrayBufferWriter = ArrayBufferWriter; + + if (zipObj.fs) { + ZipDirectoryEntry = zipObj.fs.ZipDirectoryEntry; + ZipDirectoryEntry.prototype.addHttpContent = function (name, URL, useRangeHeader) { + function addChild(parent, name, params, directory) { + if (parent.directory) + return directory ? new ZipDirectoryEntry(parent.fs, name, params, parent) : new zipObj.fs.ZipFileEntry(parent.fs, name, params, parent); + else + throw "Parent entry is not a directory."; + } + + return addChild(this, name, { + data: URL, + Reader: useRangeHeader ? HttpRangeReader : HttpReader + }); + }; + ZipDirectoryEntry.prototype.importHttpContent = function (URL, useRangeHeader, onend, onerror) { + this.importZip(useRangeHeader ? new HttpRangeReader(URL) : new HttpReader(URL), onend, onerror); + }; + zipObj.fs.FS.prototype.importHttpContent = function (URL, useRangeHeader, onend, onerror) { + this.entries = []; + this.root = new ZipDirectoryEntry(this); + this.root.importHttpContent(URL, useRangeHeader, onend, onerror); + }; + } +}; + +const zip = zipLib.zip; +zipExt(zip); + +const supportedSchemas = ["4.2"]; + +/** + * @private + */ +class XML3DSceneGraphLoader { + + constructor(plugin, cfg = {}) { + + /** + * Supported 3DXML schema versions + * @property supportedSchemas + * @type {string[]} + */ + this.supportedSchemas = supportedSchemas; + + this._xrayOpacity = 0.7; + this._src = null; + this._options = cfg; + + /** + * Default viewpoint, containing eye, look and up vectors. + * Only defined if found in the 3DXML file. + * @property viewpoint + * @type {Number[]} + */ + this.viewpoint = null; + + if (!cfg.workerScriptsPath) { + plugin.error("Config expected: workerScriptsPath"); + return } - function _emscripten_set_current_thread_status(newStatus) { + zip.workerScriptsPath = cfg.workerScriptsPath; + + this.src = cfg.src; + this.xrayOpacity = 0.7; + this.displayEffect = cfg.displayEffect; + this.createMetaModel = cfg.createMetaModel; + } + + load(plugin, modelNode, src, options, ok, error) { + + switch (options.materialType) { + case "MetallicMaterial": + modelNode._defaultMaterial = new MetallicMaterial(modelNode, { + baseColor: [1, 1, 1], + metallic: 0.6, + roughness: 0.6 + }); + break; + + case "SpecularMaterial": + modelNode._defaultMaterial = new SpecularMaterial(modelNode, { + diffuse: [1, 1, 1], + specular: math.vec3([1.0, 1.0, 1.0]), + glossiness: 0.5 + }); + break; + + default: + modelNode._defaultMaterial = new PhongMaterial(modelNode, { + reflectivity: 0.75, + shiness: 100, + diffuse: [1, 1, 1] + }); } - function __webgl_enable_ANGLE_instanced_arrays(ctx) { - var ext = ctx.getExtension("ANGLE_instanced_arrays"); - if (ext) { - ctx["vertexAttribDivisor"] = function(index, divisor) { - ext["vertexAttribDivisorANGLE"](index, divisor); - }; - ctx["drawArraysInstanced"] = function(mode, first, count, primcount) { - ext["drawArraysInstancedANGLE"](mode, first, count, primcount); - }; - ctx["drawElementsInstanced"] = function(mode, count, type, indices, primcount) { - ext["drawElementsInstancedANGLE"](mode, count, type, indices, primcount); + + modelNode._wireframeMaterial = new LambertMaterial(modelNode, { + color: [0, 0, 0], + lineWidth: 2 + }); + + var spinner = modelNode.scene.canvas.spinner; + spinner.processes++; + + load3DXML(plugin, modelNode, src, options, function () { + spinner.processes--; + if (ok) { + ok(); + } + modelNode.fire("loaded", true, false); + }, + function (msg) { + spinner.processes--; + modelNode.error(msg); + if (error) { + error(msg); + } + /** + Fired whenever this XML3D fails to load the 3DXML file + specified by {@link XML3D/src}. + @event error + @param msg {String} Description of the error + */ + modelNode.fire("error", msg); + }, + function (err) { + console.log("Error, Will Robinson: " + err); + }); + } +} + +var load3DXML = (function () { + return function (plugin, modelNode, src, options, ok, error) { + loadZIP(src, function (zip) { // OK + parse3DXML(plugin, zip, options, modelNode, ok, error); + }, + error); + }; +})(); + +var parse3DXML = (function () { + return function (plugin, zip, options, modelNode, ok) { + var ctx = { + plugin: plugin, + zip: zip, + edgeThreshold: 30, // Guess at degrees of normal deviation between adjacent tris below which we remove edge between them + materialType: options.materialType, + scene: modelNode.scene, + modelNode: modelNode, + info: { + references: {} + }, + materials: {} + }; + + if (options.createMetaModel) { + ctx.metaModelData = { + modelId: modelNode.id, + metaObjects: [{ + name: modelNode.id, + type: "Default", + id: modelNode.id + }] }; - return 1; - } } - function __webgl_enable_OES_vertex_array_object(ctx) { - var ext = ctx.getExtension("OES_vertex_array_object"); - if (ext) { - ctx["createVertexArray"] = function() { - return ext["createVertexArrayOES"](); - }; - ctx["deleteVertexArray"] = function(vao) { - ext["deleteVertexArrayOES"](vao); - }; - ctx["bindVertexArray"] = function(vao) { - ext["bindVertexArrayOES"](vao); - }; - ctx["isVertexArray"] = function(vao) { - return ext["isVertexArrayOES"](vao); - }; - return 1; - } + modelNode.scene.loading++; // Disables (re)compilation + + parseDocument(ctx, function () { + if (ctx.metaModelData) { + plugin.viewer.metaScene.createMetaModel(modelNode.id, ctx.metaModelData); + } + modelNode.scene.loading--; // Re-enables (re)compilation + ok(); + }); + }; + + function parseDocument(ctx, ok) { + ctx.zip.getFile("Manifest.xml", function (xmlDoc, json) { + var node = json; + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Manifest": + parseManifest(ctx, child, ok); + break; + } + } + }); + } + + function parseManifest(ctx, manifest, ok) { + var children = manifest.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Root": + var rootFileSrc = child.children[0]; + ctx.zip.getFile(rootFileSrc, function (xmlDoc, json) { + parseRoot(ctx, json, ok); + }); + break; + } } - function __webgl_enable_WEBGL_draw_buffers(ctx) { - var ext = ctx.getExtension("WEBGL_draw_buffers"); - if (ext) { - ctx["drawBuffers"] = function(n, bufs) { - ext["drawBuffersWEBGL"](n, bufs); - }; - return 1; - } + } + + function parseRoot(ctx, node, ok) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Model_3dxml": + parseModel(ctx, child, ok); + break; + } } - function __webgl_enable_WEBGL_multi_draw(ctx) { - return !!(ctx.multiDrawWebgl = ctx.getExtension("WEBGL_multi_draw")); - } - var GL = { counter: 1, buffers: [], programs: [], framebuffers: [], renderbuffers: [], textures: [], uniforms: [], shaders: [], vaos: [], contexts: {}, offscreenCanvases: {}, timerQueriesEXT: [], programInfos: {}, stringCache: {}, unpackAlignment: 4, recordError: function recordError(errorCode) { - if (!GL.lastError) { - GL.lastError = errorCode; - } - }, getNewId: function(table) { - var ret = GL.counter++; - for (var i = table.length; i < ret; i++) { - table[i] = null; - } - return ret; - }, getSource: function(shader, count, string, length) { - var source = ""; - for (var i = 0; i < count; ++i) { - var len = length ? GROWABLE_HEAP_I32()[length + i * 4 >> 2] : -1; - source += UTF8ToString(GROWABLE_HEAP_I32()[string + i * 4 >> 2], len < 0 ? void 0 : len); - } - return source; - }, createContext: function(canvas, webGLContextAttributes) { - var ctx = canvas.getContext("webgl", webGLContextAttributes); - if (!ctx) - return 0; - var handle = GL.registerContext(ctx, webGLContextAttributes); - return handle; - }, registerContext: function(ctx, webGLContextAttributes) { - var handle = _malloc(8); - GROWABLE_HEAP_I32()[handle + 4 >> 2] = _pthread_self(); - var context = { handle, attributes: webGLContextAttributes, version: webGLContextAttributes.majorVersion, GLctx: ctx }; - if (ctx.canvas) - ctx.canvas.GLctxObject = context; - GL.contexts[handle] = context; - if (typeof webGLContextAttributes.enableExtensionsByDefault === "undefined" || webGLContextAttributes.enableExtensionsByDefault) { - GL.initExtensions(context); - } - return handle; - }, makeContextCurrent: function(contextHandle) { - GL.currentContext = GL.contexts[contextHandle]; - Module.ctx = GLctx = GL.currentContext && GL.currentContext.GLctx; - return !(contextHandle && !GLctx); - }, getContext: function(contextHandle) { - return GL.contexts[contextHandle]; - }, deleteContext: function(contextHandle) { - if (GL.currentContext === GL.contexts[contextHandle]) - GL.currentContext = null; - if (typeof JSEvents === "object") - JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); - if (GL.contexts[contextHandle] && GL.contexts[contextHandle].GLctx.canvas) - GL.contexts[contextHandle].GLctx.canvas.GLctxObject = void 0; - _free(GL.contexts[contextHandle].handle); - GL.contexts[contextHandle] = null; - }, initExtensions: function(context) { - if (!context) - context = GL.currentContext; - if (context.initExtensionsDone) - return; - context.initExtensionsDone = true; - var GLctx2 = context.GLctx; - __webgl_enable_ANGLE_instanced_arrays(GLctx2); - __webgl_enable_OES_vertex_array_object(GLctx2); - __webgl_enable_WEBGL_draw_buffers(GLctx2); - GLctx2.disjointTimerQueryExt = GLctx2.getExtension("EXT_disjoint_timer_query"); - __webgl_enable_WEBGL_multi_draw(GLctx2); - var automaticallyEnabledExtensions = ["OES_texture_float", "OES_texture_half_float", "OES_standard_derivatives", "OES_vertex_array_object", "WEBGL_compressed_texture_s3tc", "WEBGL_depth_texture", "OES_element_index_uint", "EXT_texture_filter_anisotropic", "EXT_frag_depth", "WEBGL_draw_buffers", "ANGLE_instanced_arrays", "OES_texture_float_linear", "OES_texture_half_float_linear", "EXT_blend_minmax", "EXT_shader_texture_lod", "EXT_texture_norm16", "WEBGL_compressed_texture_pvrtc", "EXT_color_buffer_half_float", "WEBGL_color_buffer_float", "EXT_sRGB", "WEBGL_compressed_texture_etc1", "EXT_disjoint_timer_query", "WEBGL_compressed_texture_etc", "WEBGL_compressed_texture_astc", "EXT_color_buffer_float", "WEBGL_compressed_texture_s3tc_srgb", "EXT_disjoint_timer_query_webgl2", "WEBKIT_WEBGL_compressed_texture_pvrtc"]; - var exts = GLctx2.getSupportedExtensions() || []; - exts.forEach(function(ext) { - if (automaticallyEnabledExtensions.indexOf(ext) != -1) { - GLctx2.getExtension(ext); - } - }); - }, populateUniformTable: function(program) { - var p = GL.programs[program]; - var ptable = GL.programInfos[program] = { uniforms: {}, maxUniformLength: 0, maxAttributeLength: -1, maxUniformBlockNameLength: -1 }; - var utable = ptable.uniforms; - var numUniforms = GLctx.getProgramParameter(p, 35718); - for (var i = 0; i < numUniforms; ++i) { - var u = GLctx.getActiveUniform(p, i); - var name2 = u.name; - ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name2.length + 1); - if (name2.slice(-1) == "]") { - name2 = name2.slice(0, name2.lastIndexOf("[")); - } - var loc = GLctx.getUniformLocation(p, name2); - if (loc) { - var id = GL.getNewId(GL.uniforms); - utable[name2] = [u.size, id]; - GL.uniforms[id] = loc; - for (var j = 1; j < u.size; ++j) { - var n = name2 + "[" + j + "]"; - loc = GLctx.getUniformLocation(p, n); - id = GL.getNewId(GL.uniforms); - GL.uniforms[id] = loc; - } + } + + function parseModel(ctx, node, ok) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Header": + parseHeader(ctx, child); + break; + case "ProductStructure": + parseProductStructure(ctx, child, ok); + break; + case "DefaultView": + parseDefaultView(ctx, child); + break; } - } - } }; - var __emscripten_webgl_power_preferences = ["default", "low-power", "high-performance"]; - function _emscripten_webgl_do_create_context(target, attributes) { - var a = attributes >> 2; - var powerPreference = GROWABLE_HEAP_I32()[a + (24 >> 2)]; - var contextAttributes = { "alpha": !!GROWABLE_HEAP_I32()[a + (0 >> 2)], "depth": !!GROWABLE_HEAP_I32()[a + (4 >> 2)], "stencil": !!GROWABLE_HEAP_I32()[a + (8 >> 2)], "antialias": !!GROWABLE_HEAP_I32()[a + (12 >> 2)], "premultipliedAlpha": !!GROWABLE_HEAP_I32()[a + (16 >> 2)], "preserveDrawingBuffer": !!GROWABLE_HEAP_I32()[a + (20 >> 2)], "powerPreference": __emscripten_webgl_power_preferences[powerPreference], "failIfMajorPerformanceCaveat": !!GROWABLE_HEAP_I32()[a + (28 >> 2)], majorVersion: GROWABLE_HEAP_I32()[a + (32 >> 2)], minorVersion: GROWABLE_HEAP_I32()[a + (36 >> 2)], enableExtensionsByDefault: GROWABLE_HEAP_I32()[a + (40 >> 2)], explicitSwapControl: GROWABLE_HEAP_I32()[a + (44 >> 2)], proxyContextToMainThread: GROWABLE_HEAP_I32()[a + (48 >> 2)], renderViaOffscreenBackBuffer: GROWABLE_HEAP_I32()[a + (52 >> 2)] }; - var canvas = findCanvasEventTarget(target); - if (!canvas) { - return 0; - } - if (contextAttributes.explicitSwapControl) { - return 0; - } - var contextHandle = GL.createContext(canvas, contextAttributes); - return contextHandle; } - function _emscripten_webgl_create_context(a0, a1) { - return _emscripten_webgl_do_create_context(a0, a1); + } + + function parseHeader(ctx, node) { + var children = node.children; + var metaData = {}; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "SchemaVersion": + metaData.schemaVersion = child.children[0]; + if (!isSchemaVersionSupported(ctx, metaData.schemaVersion)) { + ctx.plugin.error("Schema version not supported: " + metaData.schemaVersion + " - supported versions are: " + supportedSchemas.join(",")); + } + break; + case "Title": + metaData.title = child.children[0]; + break; + case "Author": + metaData.author = child.children[0]; + break; + case "Created": + metaData.created = child.children[0]; + break; + } } - var ENV = {}; - function getExecutableName() { - return thisProgram || "./this.program"; + ctx.modelNode.meta = metaData; + } + + function isSchemaVersionSupported(ctx, schemaVersion) { + for (var i = 0, len = supportedSchemas.length; i < len; i++) { + if (schemaVersion === supportedSchemas[i]) { + return true; + } } - function getEnvStrings() { - if (!getEnvStrings.strings) { - var lang = (typeof navigator === "object" && navigator.languages && navigator.languages[0] || "C").replace("-", "_") + ".UTF-8"; - var env = { "USER": "web_user", "LOGNAME": "web_user", "PATH": "/", "PWD": "/", "HOME": "/home/web_user", "LANG": lang, "_": getExecutableName() }; - for (var x in ENV) { - env[x] = ENV[x]; + return false; + } + + function parseProductStructure(ctx, productStructureNode, ok) { + + parseReferenceReps(ctx, productStructureNode, function (referenceReps) { + + // Parse out an intermediate scene DAG representation, that we can then + // recursive descend through to build a xeokit Object hierarchy. + + var children = productStructureNode.children; + + var reference3Ds = {}; + var instanceReps = {}; + var instance3Ds = {}; + + // Map all the elements + + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + + case "Reference3D": + reference3Ds[child.id] = { + type: "Reference3D", + id: child.id, + name: child.name, + instance3Ds: {}, + instanceReps: {} + }; + break; + + case "InstanceRep": + var isAggregatedBy; + var isInstanceOf; + var relativeMatrix; + for (var j = 0, lenj = child.children.length; j < lenj; j++) { + var child2 = child.children[j]; + switch (child2.type) { + case "IsAggregatedBy": + isAggregatedBy = child2.children[0]; + break; + case "IsInstanceOf": + isInstanceOf = child2.children[0]; + break; + } + } + instanceReps[child.id] = { + type: "InstanceRep", + id: child.id, + name: child.name, + isAggregatedBy: isAggregatedBy, + isInstanceOf: isInstanceOf, + referenceReps: {} + }; + break; + + case "Instance3D": + var isAggregatedBy; + var isInstanceOf; + var relativeMatrix; + for (var j = 0, lenj = child.children.length; j < lenj; j++) { + var child2 = child.children[j]; + switch (child2.type) { + case "IsAggregatedBy": + isAggregatedBy = child2.children[0]; + break; + case "IsInstanceOf": + isInstanceOf = child2.children[0]; + break; + case "RelativeMatrix": + relativeMatrix = child2.children[0]; + break; + } + } + instance3Ds[child.id] = { + type: "Instance3D", + id: child.id, + name: child.name, + isAggregatedBy: isAggregatedBy, + isInstanceOf: isInstanceOf, + relativeMatrix: relativeMatrix, + reference3Ds: {} + }; + break; + } } - var strings = []; - for (var x in env) { - strings.push(x + "=" + env[x]); + + // Connect Reference3Ds to the Instance3Ds they aggregate + + for (var id in instance3Ds) { + var instance3D = instance3Ds[id]; + var reference3D = reference3Ds[instance3D.isAggregatedBy]; + if (reference3D) { + reference3D.instance3Ds[instance3D.id] = instance3D; + } else { + alert("foo"); + } } - getEnvStrings.strings = strings; - } - return getEnvStrings.strings; - } - function _environ_get(__environ, environ_buf) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(5, 1, __environ, environ_buf); - try { - var bufSize = 0; - getEnvStrings().forEach(function(string, i) { - var ptr = environ_buf + bufSize; - GROWABLE_HEAP_I32()[__environ + i * 4 >> 2] = ptr; - writeAsciiToMemory(string, ptr); - bufSize += string.length + 1; - }); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _environ_sizes_get(penviron_count, penviron_buf_size) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(6, 1, penviron_count, penviron_buf_size); - try { - var strings = getEnvStrings(); - GROWABLE_HEAP_I32()[penviron_count >> 2] = strings.length; - var bufSize = 0; - strings.forEach(function(string) { - bufSize += string.length + 1; - }); - GROWABLE_HEAP_I32()[penviron_buf_size >> 2] = bufSize; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_close(fd) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(7, 1, fd); - try { - var stream = SYSCALLS.getStreamFromFD(fd); - FS.close(stream); - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_read(fd, iov, iovcnt, pnum) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(8, 1, fd, iov, iovcnt, pnum); - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = SYSCALLS.doReadv(stream, iov, iovcnt); - GROWABLE_HEAP_I32()[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(9, 1, fd, offset_low, offset_high, whence, newOffset); - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var HIGH_OFFSET = 4294967296; - var offset = offset_high * HIGH_OFFSET + (offset_low >>> 0); - var DOUBLE_LIMIT = 9007199254740992; - if (offset <= -DOUBLE_LIMIT || offset >= DOUBLE_LIMIT) { - return -61; + + // Connect Instance3Ds to the Reference3Ds they instantiate + + for (var id in instance3Ds) { + var instance3D = instance3Ds[id]; + var reference3D = reference3Ds[instance3D.isInstanceOf]; + instance3D.reference3Ds[reference3D.id] = reference3D; + reference3D.instance3D = instance3D; } - FS.llseek(stream, offset, whence); - tempI64 = [stream.position >>> 0, (tempDouble = stream.position, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[newOffset >> 2] = tempI64[0], GROWABLE_HEAP_I32()[newOffset + 4 >> 2] = tempI64[1]; - if (stream.getdents && offset === 0 && whence === 0) - stream.getdents = null; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } - } - function _fd_write(fd, iov, iovcnt, pnum) { - if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(10, 1, fd, iov, iovcnt, pnum); - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = SYSCALLS.doWritev(stream, iov, iovcnt); - GROWABLE_HEAP_I32()[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) - abort(e); - return e.errno; - } + + // Connect InstanceReps to the ReferenceReps they instantiate + + for (var id in instanceReps) { + var instanceRep = instanceReps[id]; + var referenceRep = referenceReps[instanceRep.isInstanceOf]; + if (referenceRep) { + instanceRep.referenceReps[referenceRep.id] = referenceRep; + } + } + + // Connect Reference3Ds to the InstanceReps they aggregate + + for (var id in instanceReps) { + var instanceRep = instanceReps[id]; + var reference3D = reference3Ds[instanceRep.isAggregatedBy]; + if (reference3D) { + reference3D.instanceReps[instanceRep.id] = instanceRep; + } + } + + function parseReference3D(ctx, reference3D, group) { + //ctx.plugin.log("parseReference3D( " + reference3D.id + " )"); + for (var id in reference3D.instance3Ds) { + parseInstance3D(ctx, reference3D.instance3Ds[id], group); + } + for (var id in reference3D.instanceReps) { + parseInstanceRep(ctx, reference3D.instanceReps[id], group); + } + } + + function parseInstance3D(ctx, instance3D, group) { + //ctx.plugin.log("parseInstance3D( " + instance3D.id + " )"); + + if (instance3D.relativeMatrix) { + var matrix = parseFloatArray(instance3D.relativeMatrix, 12); + var translate = [matrix[9], matrix[10], matrix[11]]; + var mat3 = matrix.slice(0, 9); // Rotation matrix + var mat4 = math.mat3ToMat4(mat3, math.identityMat4()); // Convert rotation matrix to 4x4 + var childGroup = new Node$1(ctx.modelNode, { + position: translate + }); + if (ctx.metaModelData) { + ctx.metaModelData.metaObjects.push({ + id: childGroup.id, + type: "Default", + name: instance3D.name, + parent: group ? group.id : ctx.modelNode.id + }); + } + if (group) { + group.addChild(childGroup, true); + } else { + ctx.modelNode.addChild(childGroup, true); + } + group = childGroup; + childGroup = new Node$1(ctx.modelNode, { + matrix: mat4 + }); + if (ctx.metaModelData) { + ctx.metaModelData.metaObjects.push({ + id: childGroup.id, + type: "Default", + name: instance3D.name, + parent: group ? group.id : ctx.modelNode.id + }); + } + group.addChild(childGroup, true); + group = childGroup; + } else { + var childGroup = new Node$1(ctx.modelNode, {}); + if (ctx.metaModelData) { + ctx.metaModelData.metaObjects.push({ + id: childGroup.id, + type: "Default", + name: instance3D.name, + parent: group ? group.id : ctx.modelNode.id + }); + } + if (group) { + group.addChild(childGroup, true); + } else { + ctx.modelNode.addChild(childGroup, true); + } + group = childGroup; + } + for (var id in instance3D.reference3Ds) { + parseReference3D(ctx, instance3D.reference3Ds[id], group); + } + } + + function parseInstanceRep(ctx, instanceRep, group) { + //ctx.plugin.log("parseInstanceRep( " + instanceRep.id + " )"); + if (instanceRep.referenceReps) { + for (var id in instanceRep.referenceReps) { + var referenceRep = instanceRep.referenceReps[id]; + for (var id2 in referenceRep) { + if (id2 === "id") { + continue; // HACK + } + var meshCfg = referenceRep[id2]; + var lines = meshCfg.geometry.primitive === "lines"; + var material = lines ? ctx.modelNode._wireframeMaterial : (meshCfg.materialId ? ctx.materials[meshCfg.materialId] : null); + var colorize = meshCfg.color; + var mesh = new Mesh(ctx.modelNode, { + isObject: true, + geometry: meshCfg.geometry, + material: material || ctx.modelNode._defaultMaterial, + colorize: colorize, + backfaces: false + }); + if (ctx.metaModelData) { + ctx.metaModelData.metaObjects.push({ + id: mesh.id, + type: "Default", + name: instanceRep.name, + parent: group ? group.id : ctx.modelNode.id + }); + } + if (group) { + group.addChild(mesh, true); + } else { + ctx.modelNode.addChild(mesh, true); + } + mesh.colorize = colorize; // HACK: Mesh has inherited modelNode's colorize state, so we need to restore it (we'd better not modify colorize on the modelNode). + } + } + } + } + + // Find the root Reference3D + + for (var id in reference3Ds) { + var reference3D = reference3Ds[id]; + if (!reference3D.instance3D) { + parseReference3D(ctx, reference3D, null); // HACK: Assuming that root has id == "1" + ok(); + return; + } + } + + alert("No root Reference3D element found in this modelNode - can't load."); + + ok(); + }); + } + + function parseIntArray(str) { + var parts = str.trim().split(" "); + var result = new Int32Array(parts.length); + for (var i = 0; i < parts.length; i++) { + result[i] = parseInt(parts[i]); } - function _pthread_cleanup_push(routine, arg) { - PThread.threadExitHandlers.push(function() { - wasmTable.get(routine)(arg); - }); + return result; + } + + function parseReferenceReps(ctx, node, ok) { + var referenceReps = {}; + var children = node.children; + var numToLoad = 0; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + if (child.type === "ReferenceRep") { + numToLoad++; + } } - function spawnThread(threadParams) { - if (ENVIRONMENT_IS_PTHREAD) - throw "Internal Error! spawnThread() can only ever be called from main application thread!"; - var worker = PThread.getNewWorker(); - if (worker.pthread !== void 0) - throw "Internal error!"; - if (!threadParams.pthread_ptr) - throw "Internal error, no pthread ptr!"; - PThread.runningWorkers.push(worker); - var tlsMemory = _malloc(128 * 4); - for (var i = 0; i < 128; ++i) { - GROWABLE_HEAP_I32()[tlsMemory + i * 4 >> 2] = 0; - } - var stackHigh = threadParams.stackBase + threadParams.stackSize; - var pthread = PThread.pthreads[threadParams.pthread_ptr] = { worker, stackBase: threadParams.stackBase, stackSize: threadParams.stackSize, allocatedOwnStack: threadParams.allocatedOwnStack, thread: threadParams.pthread_ptr, threadInfoStruct: threadParams.pthread_ptr }; - var tis = pthread.threadInfoStruct >> 2; - Atomics.store(GROWABLE_HEAP_U32(), tis + (0 >> 2), 0); - Atomics.store(GROWABLE_HEAP_U32(), tis + (4 >> 2), 0); - Atomics.store(GROWABLE_HEAP_U32(), tis + (8 >> 2), 0); - Atomics.store(GROWABLE_HEAP_U32(), tis + (68 >> 2), threadParams.detached); - Atomics.store(GROWABLE_HEAP_U32(), tis + (104 >> 2), tlsMemory); - Atomics.store(GROWABLE_HEAP_U32(), tis + (48 >> 2), 0); - Atomics.store(GROWABLE_HEAP_U32(), tis + (40 >> 2), pthread.threadInfoStruct); - Atomics.store(GROWABLE_HEAP_U32(), tis + (44 >> 2), 42); - Atomics.store(GROWABLE_HEAP_U32(), tis + (108 >> 2), threadParams.stackSize); - Atomics.store(GROWABLE_HEAP_U32(), tis + (84 >> 2), threadParams.stackSize); - Atomics.store(GROWABLE_HEAP_U32(), tis + (80 >> 2), stackHigh); - Atomics.store(GROWABLE_HEAP_U32(), tis + (108 + 8 >> 2), stackHigh); - Atomics.store(GROWABLE_HEAP_U32(), tis + (108 + 12 >> 2), threadParams.detached); - Atomics.store(GROWABLE_HEAP_U32(), tis + (108 + 20 >> 2), threadParams.schedPolicy); - Atomics.store(GROWABLE_HEAP_U32(), tis + (108 + 24 >> 2), threadParams.schedPrio); - var global_libc = _emscripten_get_global_libc(); - var global_locale = global_libc + 40; - Atomics.store(GROWABLE_HEAP_U32(), tis + (176 >> 2), global_locale); - worker.pthread = pthread; - var msg = { "cmd": "run", "start_routine": threadParams.startRoutine, "arg": threadParams.arg, "threadInfoStruct": threadParams.pthread_ptr, "selfThreadId": threadParams.pthread_ptr, "parentThreadId": threadParams.parent_pthread_ptr, "stackBase": threadParams.stackBase, "stackSize": threadParams.stackSize }; - worker.runPthread = function() { - msg.time = performance.now(); - worker.postMessage(msg, threadParams.transferList); - }; - if (worker.loaded) { - worker.runPthread(); - delete worker.runPthread; - } + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "ReferenceRep": + if (child.associatedFile) { + var src = stripURN(child.associatedFile); + (function () { + var childId = child.id; + ctx.zip.getFile(src, function (xmlDoc, json) { + + var materialIds = xmlDoc.getElementsByTagName("MaterialId"); + + loadCATMaterialRefDocuments(ctx, materialIds, function () { + + // ctx.plugin.log("reference loaded: " + src); + var referenceRep = { + id: childId + }; + parse3DRepDocument(ctx, json, referenceRep); + referenceReps[childId] = referenceRep; + if (--numToLoad === 0) { + ok(referenceReps); + } + }); + }, + function (error) { + // TODO: + }); + })(); + } + break; + } } - function _pthread_getschedparam(thread, policy, schedparam) { - if (!policy && !schedparam) - return ERRNO_CODES.EINVAL; - if (!thread) { - err("pthread_getschedparam called with a null thread pointer!"); - return ERRNO_CODES.ESRCH; - } - var self2 = GROWABLE_HEAP_I32()[thread + 12 >> 2]; - if (self2 !== thread) { - err("pthread_getschedparam attempted on thread " + thread + ", which does not point to a valid thread, or does not exist anymore!"); - return ERRNO_CODES.ESRCH; - } - var schedPolicy = Atomics.load(GROWABLE_HEAP_U32(), thread + 108 + 20 >> 2); - var schedPrio = Atomics.load(GROWABLE_HEAP_U32(), thread + 108 + 24 >> 2); - if (policy) - GROWABLE_HEAP_I32()[policy >> 2] = schedPolicy; - if (schedparam) - GROWABLE_HEAP_I32()[schedparam >> 2] = schedPrio; - return 0; + } + + + function parseDefaultView(ctx, node) { + // ctx.plugin.log("parseDefaultView"); + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Viewpoint": + var children2 = child.children; + ctx.modelNode.viewpoint = {}; + for (var i2 = 0, len2 = children2.length; i2 < len2; i2++) { + var child2 = children2[i]; + switch (child2.type) { + case "Position": + ctx.modelNode.viewpoint.eye = parseFloatArray(child2.children[0], 3); + break; + case "Sight": + ctx.modelNode.viewpoint.look = parseFloatArray(child2.children[0], 3); + break; + case "Up": + ctx.modelNode.viewpoint.up = parseFloatArray(child2.children[0], 3); + break; + } + } + break; + } } - function _pthread_self() { - return __pthread_ptr | 0; + } + + function parse3DRepDocument(ctx, node, result) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "XMLRepresentation": + parseXMLRepresentation(ctx, child, result); + break; + } } - Module["_pthread_self"] = _pthread_self; - function _pthread_create(pthread_ptr, attr, start_routine, arg) { - if (typeof SharedArrayBuffer === "undefined") { - err("Current environment does not support SharedArrayBuffer, pthreads are not available!"); - return 6; - } - if (!pthread_ptr) { - err("pthread_create called with a null thread pointer!"); - return 28; - } - var transferList = []; - var error = 0; - if (ENVIRONMENT_IS_PTHREAD && (transferList.length === 0 || error)) { - return _emscripten_sync_run_in_main_thread_4(687865856, pthread_ptr, attr, start_routine, arg); - } - var stackSize = 0; - var stackBase = 0; - var detached = 0; - var schedPolicy = 0; - var schedPrio = 0; - if (attr) { - stackSize = GROWABLE_HEAP_I32()[attr >> 2]; - stackSize += 81920; - stackBase = GROWABLE_HEAP_I32()[attr + 8 >> 2]; - detached = GROWABLE_HEAP_I32()[attr + 12 >> 2] !== 0; - var inheritSched = GROWABLE_HEAP_I32()[attr + 16 >> 2] === 0; - if (inheritSched) { - var prevSchedPolicy = GROWABLE_HEAP_I32()[attr + 20 >> 2]; - var prevSchedPrio = GROWABLE_HEAP_I32()[attr + 24 >> 2]; - var parentThreadPtr = PThread.currentProxiedOperationCallerThread ? PThread.currentProxiedOperationCallerThread : _pthread_self(); - _pthread_getschedparam(parentThreadPtr, attr + 20, attr + 24); - schedPolicy = GROWABLE_HEAP_I32()[attr + 20 >> 2]; - schedPrio = GROWABLE_HEAP_I32()[attr + 24 >> 2]; - GROWABLE_HEAP_I32()[attr + 20 >> 2] = prevSchedPolicy; - GROWABLE_HEAP_I32()[attr + 24 >> 2] = prevSchedPrio; - } else { - schedPolicy = GROWABLE_HEAP_I32()[attr + 20 >> 2]; - schedPrio = GROWABLE_HEAP_I32()[attr + 24 >> 2]; + } + + function parseXMLRepresentation(ctx, node, result) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Root": + parse3DRepRoot(ctx, child, result); + break; } - } else { - stackSize = 2097152; - } - var allocatedOwnStack = stackBase == 0; - if (allocatedOwnStack) { - stackBase = _memalign(16, stackSize); - } else { - stackBase -= stackSize; - assert(stackBase > 0); - } - var threadInfoStruct2 = _malloc(232); - for (var i = 0; i < 232 >> 2; ++i) - GROWABLE_HEAP_U32()[(threadInfoStruct2 >> 2) + i] = 0; - GROWABLE_HEAP_I32()[pthread_ptr >> 2] = threadInfoStruct2; - GROWABLE_HEAP_I32()[threadInfoStruct2 + 12 >> 2] = threadInfoStruct2; - var headPtr = threadInfoStruct2 + 156; - GROWABLE_HEAP_I32()[headPtr >> 2] = headPtr; - var threadParams = { stackBase, stackSize, allocatedOwnStack, schedPolicy, schedPrio, detached, startRoutine: start_routine, pthread_ptr: threadInfoStruct2, parent_pthread_ptr: _pthread_self(), arg, transferList }; - if (ENVIRONMENT_IS_PTHREAD) { - threadParams.cmd = "spawnThread"; - postMessage(threadParams, transferList); - } else { - spawnThread(threadParams); - } - return 0; } - function _setTempRet0($i) { + } + + function parse3DRepRoot(ctx, node, result) { + switch (node["xsi:type"]) { + } + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Rep": + parse3DRepRep(ctx, child, result); + break; + } } - function __isLeapYear(year) { - return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + } + + function parse3DRepRep(ctx, node, result) { + switch (node["xsi:type"]) { + } + var meshesResult = { + edgeThreshold: ctx.edgeThreshold || 30, + compressGeometry: true + }; + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Rep": + parse3DRepRep(ctx, child, result); + break; + case "Edges": + // Ignoring edges because we auto-generate our own using xeokit + break; + case "Faces": + meshesResult.primitive = "triangles"; + parseFaces(ctx, child, meshesResult); + break; + case "VertexBuffer": + parseVertexBuffer(ctx, child, meshesResult); + break; + case "SurfaceAttributes": + parseSurfaceAttributes(ctx, child, meshesResult); + break; + } } - function __arraySum(array, index) { - var sum = 0; - for (var i = 0; i <= index; sum += array[i++]) { - } - return sum; + if (meshesResult.positions) { + var geometry = new ReadableGeometry(ctx.modelNode, meshesResult); + result[geometry.id] = { + geometry: geometry, + color: meshesResult.color || [1.0, 1.0, 1.0, 1.0], + materialId: meshesResult.materialId + }; } - var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - function __addDays(date, days) { - var newDate = new Date(date.getTime()); - while (days > 0) { - var leap = __isLeapYear(newDate.getFullYear()); - var currentMonth = newDate.getMonth(); - var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth]; - if (days > daysInCurrentMonth - newDate.getDate()) { - days -= daysInCurrentMonth - newDate.getDate() + 1; - newDate.setDate(1); - if (currentMonth < 11) { - newDate.setMonth(currentMonth + 1); - } else { - newDate.setMonth(0); - newDate.setFullYear(newDate.getFullYear() + 1); - } - } else { - newDate.setDate(newDate.getDate() + days); - return newDate; + } + + function parseFaces(ctx, node, result) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Face": + parseFace(ctx, child, result); + break; } - } - return newDate; } - function _strftime(s, maxsize, format, tm) { - var tm_zone = GROWABLE_HEAP_I32()[tm + 40 >> 2]; - var date = { tm_sec: GROWABLE_HEAP_I32()[tm >> 2], tm_min: GROWABLE_HEAP_I32()[tm + 4 >> 2], tm_hour: GROWABLE_HEAP_I32()[tm + 8 >> 2], tm_mday: GROWABLE_HEAP_I32()[tm + 12 >> 2], tm_mon: GROWABLE_HEAP_I32()[tm + 16 >> 2], tm_year: GROWABLE_HEAP_I32()[tm + 20 >> 2], tm_wday: GROWABLE_HEAP_I32()[tm + 24 >> 2], tm_yday: GROWABLE_HEAP_I32()[tm + 28 >> 2], tm_isdst: GROWABLE_HEAP_I32()[tm + 32 >> 2], tm_gmtoff: GROWABLE_HEAP_I32()[tm + 36 >> 2], tm_zone: tm_zone ? UTF8ToString(tm_zone) : "" }; - var pattern = UTF8ToString(format); - var EXPANSION_RULES_1 = { "%c": "%a %b %d %H:%M:%S %Y", "%D": "%m/%d/%y", "%F": "%Y-%m-%d", "%h": "%b", "%r": "%I:%M:%S %p", "%R": "%H:%M", "%T": "%H:%M:%S", "%x": "%m/%d/%y", "%X": "%H:%M:%S", "%Ec": "%c", "%EC": "%C", "%Ex": "%m/%d/%y", "%EX": "%H:%M:%S", "%Ey": "%y", "%EY": "%Y", "%Od": "%d", "%Oe": "%e", "%OH": "%H", "%OI": "%I", "%Om": "%m", "%OM": "%M", "%OS": "%S", "%Ou": "%u", "%OU": "%U", "%OV": "%V", "%Ow": "%w", "%OW": "%W", "%Oy": "%y" }; - for (var rule in EXPANSION_RULES_1) { - pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_1[rule]); - } - var WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; - var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; - function leadingSomething(value, digits, character) { - var str = typeof value === "number" ? value.toString() : value || ""; - while (str.length < digits) { - str = character[0] + str; - } - return str; - } - function leadingNulls(value, digits) { - return leadingSomething(value, digits, "0"); - } - function compareByDay(date1, date2) { - function sgn(value) { - return value < 0 ? -1 : value > 0 ? 1 : 0; - } - var compare; - if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) { - if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) { - compare = sgn(date1.getDate() - date2.getDate()); - } - } - return compare; - } - function getFirstWeekStartDate(janFourth) { - switch (janFourth.getDay()) { - case 0: - return new Date(janFourth.getFullYear() - 1, 11, 29); - case 1: - return janFourth; - case 2: - return new Date(janFourth.getFullYear(), 0, 3); - case 3: - return new Date(janFourth.getFullYear(), 0, 2); - case 4: - return new Date(janFourth.getFullYear(), 0, 1); - case 5: - return new Date(janFourth.getFullYear() - 1, 11, 31); - case 6: - return new Date(janFourth.getFullYear() - 1, 11, 30); - } - } - function getWeekBasedYear(date2) { - var thisDate = __addDays(new Date(date2.tm_year + 1900, 0, 1), date2.tm_yday); - var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4); - var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4); - var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear); - var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear); - if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) { - if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) { - return thisDate.getFullYear() + 1; - } else { - return thisDate.getFullYear(); - } - } else { - return thisDate.getFullYear() - 1; - } - } - var EXPANSION_RULES_2 = { "%a": function(date2) { - return WEEKDAYS[date2.tm_wday].substring(0, 3); - }, "%A": function(date2) { - return WEEKDAYS[date2.tm_wday]; - }, "%b": function(date2) { - return MONTHS[date2.tm_mon].substring(0, 3); - }, "%B": function(date2) { - return MONTHS[date2.tm_mon]; - }, "%C": function(date2) { - var year = date2.tm_year + 1900; - return leadingNulls(year / 100 | 0, 2); - }, "%d": function(date2) { - return leadingNulls(date2.tm_mday, 2); - }, "%e": function(date2) { - return leadingSomething(date2.tm_mday, 2, " "); - }, "%g": function(date2) { - return getWeekBasedYear(date2).toString().substring(2); - }, "%G": function(date2) { - return getWeekBasedYear(date2); - }, "%H": function(date2) { - return leadingNulls(date2.tm_hour, 2); - }, "%I": function(date2) { - var twelveHour = date2.tm_hour; - if (twelveHour == 0) - twelveHour = 12; - else if (twelveHour > 12) - twelveHour -= 12; - return leadingNulls(twelveHour, 2); - }, "%j": function(date2) { - return leadingNulls(date2.tm_mday + __arraySum(__isLeapYear(date2.tm_year + 1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date2.tm_mon - 1), 3); - }, "%m": function(date2) { - return leadingNulls(date2.tm_mon + 1, 2); - }, "%M": function(date2) { - return leadingNulls(date2.tm_min, 2); - }, "%n": function() { - return "\n"; - }, "%p": function(date2) { - if (date2.tm_hour >= 0 && date2.tm_hour < 12) { - return "AM"; - } else { - return "PM"; + } + + function parseFace(ctx, node, result) { + var strips = node.strips; + if (strips) { + // Triangle strips + var arrays = parseIntArrays(strips); + if (arrays.length > 0) { + result.primitive = "triangles"; + var indices = []; + for (var i = 0, len = arrays.length; i < len; i++) { + var array = convertTriangleStrip(arrays[i]); + for (var j = 0, lenj = array.length; j < lenj; j++) { + indices.push(array[j]); + } + } + result.indices = indices; // TODO } - }, "%S": function(date2) { - return leadingNulls(date2.tm_sec, 2); - }, "%t": function() { - return " "; - }, "%u": function(date2) { - return date2.tm_wday || 7; - }, "%U": function(date2) { - var janFirst = new Date(date2.tm_year + 1900, 0, 1); - var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7 - janFirst.getDay()); - var endDate = new Date(date2.tm_year + 1900, date2.tm_mon, date2.tm_mday); - if (compareByDay(firstSunday, endDate) < 0) { - var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth() - 1) - 31; - var firstSundayUntilEndJanuary = 31 - firstSunday.getDate(); - var days = firstSundayUntilEndJanuary + februaryFirstUntilEndMonth + endDate.getDate(); - return leadingNulls(Math.ceil(days / 7), 2); + } else { + // Triangle meshes + var triangles = node.triangles; + if (triangles) { + result.primitive = "triangles"; + result.indices = parseIntArray(triangles); } - return compareByDay(firstSunday, janFirst) === 0 ? "01" : "00"; - }, "%V": function(date2) { - var janFourthThisYear = new Date(date2.tm_year + 1900, 0, 4); - var janFourthNextYear = new Date(date2.tm_year + 1901, 0, 4); - var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear); - var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear); - var endDate = __addDays(new Date(date2.tm_year + 1900, 0, 1), date2.tm_yday); - if (compareByDay(endDate, firstWeekStartThisYear) < 0) { - return "53"; + } + // Material + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "SurfaceAttributes": + parseSurfaceAttributes(ctx, child, result); + break; } - if (compareByDay(firstWeekStartNextYear, endDate) <= 0) { - return "01"; + } + } + + function convertTriangleStrip(indices) { + var indices2 = []; + for (var i = 0, len = indices.length; i < len - 2; i++) { + { + if (i & 1) { // + indices2.push(indices[i]); + indices2.push(indices[i + 2]); + indices2.push(indices[i + 1]); + } else { + indices2.push(indices[i]); + indices2.push(indices[i + 1]); + indices2.push(indices[i + 2]); + } } - var daysDifference; - if (firstWeekStartThisYear.getFullYear() < date2.tm_year + 1900) { - daysDifference = date2.tm_yday + 32 - firstWeekStartThisYear.getDate(); - } else { - daysDifference = date2.tm_yday + 1 - firstWeekStartThisYear.getDate(); + } + return indices2; + } + + function parseVertexBuffer(ctx, node, result) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Positions": + result.positions = parseFloatArray(child.children[0], 3); + break; + case "Normals": + result.normals = parseFloatArray(child.children[0], 3); + break; + case "TextureCoordinates": // TODO: Support dimension and channel? + result.uv = parseFloatArray(child.children[0], 2); + break; } - return leadingNulls(Math.ceil(daysDifference / 7), 2); - }, "%w": function(date2) { - return date2.tm_wday; - }, "%W": function(date2) { - var janFirst = new Date(date2.tm_year, 0, 1); - var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7 - janFirst.getDay() + 1); - var endDate = new Date(date2.tm_year + 1900, date2.tm_mon, date2.tm_mday); - if (compareByDay(firstMonday, endDate) < 0) { - var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth() - 1) - 31; - var firstMondayUntilEndJanuary = 31 - firstMonday.getDate(); - var days = firstMondayUntilEndJanuary + februaryFirstUntilEndMonth + endDate.getDate(); - return leadingNulls(Math.ceil(days / 7), 2); + } + } + + function parseIntArrays(str) { + var coordStrings = str.split(","); + var array = []; + for (var i = 0, len = coordStrings.length; i < len; i++) { + var coordStr = coordStrings[i].trim(); + if (coordStr.length > 0) { + var elemStrings = coordStr.trim().split(" "); + var arr = new Int16Array(elemStrings.length); + var arrIdx = 0; + for (var j = 0, lenj = elemStrings.length; j < lenj; j++) { + if (elemStrings[j] !== "") { + arr[arrIdx++] = parseInt(elemStrings[j]); + } + } + array.push(arr); } - return compareByDay(firstMonday, janFirst) === 0 ? "01" : "00"; - }, "%y": function(date2) { - return (date2.tm_year + 1900).toString().substring(2); - }, "%Y": function(date2) { - return date2.tm_year + 1900; - }, "%z": function(date2) { - var off = date2.tm_gmtoff; - var ahead = off >= 0; - off = Math.abs(off) / 60; - off = off / 60 * 100 + off % 60; - return (ahead ? "+" : "-") + String("0000" + off).slice(-4); - }, "%Z": function(date2) { - return date2.tm_zone; - }, "%%": function() { - return "%"; - } }; - for (var rule in EXPANSION_RULES_2) { - if (pattern.indexOf(rule) >= 0) { - pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_2[rule](date)); + } + return array; + } + + function parseFloatArray(str, numElems) { + str = str.split(","); + var arr = new Float32Array(str.length * numElems); + var arrIdx = 0; + for (var i = 0, len = str.length; i < len; i++) { + var value = str[i]; + value = value.split(" "); + for (var j = 0, lenj = value.length; j < lenj; j++) { + if (value[j] !== "") { + arr[arrIdx++] = parseFloat(value[j]); + } } - } - var bytes = intArrayFromString(pattern, false); - if (bytes.length > maxsize) { - return 0; - } - writeArrayToMemory(bytes, s); - return bytes.length - 1; } - function _strftime_l(s, maxsize, format, tm) { - return _strftime(s, maxsize, format, tm); + return arr; + } + + function parseIntArray(str) { + str = str.trim().split(" "); + var arr = new Int32Array(str.length); + for (var i = 0, len = str.length; i < len; i++) { + var value = str[i]; + arr[i] = parseInt(value); } - if (!ENVIRONMENT_IS_PTHREAD) - PThread.initMainThreadBlock(); - var FSNode = function(parent, name2, mode, rdev) { - if (!parent) { - parent = this; - } - this.parent = parent; - this.mount = parent.mount; - this.mounted = null; - this.id = FS.nextInode++; - this.name = name2; - this.mode = mode; - this.node_ops = {}; - this.stream_ops = {}; - this.rdev = rdev; - }; - var readMode = 292 | 73; - var writeMode = 146; - Object.defineProperties(FSNode.prototype, { read: { get: function() { - return (this.mode & readMode) === readMode; - }, set: function(val) { - val ? this.mode |= readMode : this.mode &= ~readMode; - } }, write: { get: function() { - return (this.mode & writeMode) === writeMode; - }, set: function(val) { - val ? this.mode |= writeMode : this.mode &= ~writeMode; - } }, isFolder: { get: function() { - return FS.isDir(this.mode); - } }, isDevice: { get: function() { - return FS.isChrdev(this.mode); - } } }); - FS.FSNode = FSNode; - FS.staticInit(); - Module["FS_createPath"] = FS.createPath; - Module["FS_createDataFile"] = FS.createDataFile; - Module["FS_createPreloadedFile"] = FS.createPreloadedFile; - Module["FS_createLazyFile"] = FS.createLazyFile; - Module["FS_createDevice"] = FS.createDevice; - Module["FS_unlink"] = FS.unlink; - InternalError = Module["InternalError"] = extendError(Error, "InternalError"); - embind_init_charCodes(); - BindingError = Module["BindingError"] = extendError(Error, "BindingError"); - init_ClassHandle(); - init_RegisteredPointer(); - init_embind(); - UnboundTypeError = Module["UnboundTypeError"] = extendError(Error, "UnboundTypeError"); - init_emval(); - var GLctx; - var proxiedFunctionTable = [null, _atexit, ___sys_ioctl, ___sys_open, _emscripten_set_canvas_element_size_main_thread, _environ_get, _environ_sizes_get, _fd_close, _fd_read, _fd_seek, _fd_write]; - function intArrayFromString(stringy, dontAddNull, length) { - var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; - var u8array = new Array(len); - var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); - if (dontAddNull) - u8array.length = numBytesWritten; - return u8array; + return arr; + } + + function parseSurfaceAttributes(ctx, node, result) { + result.color = [1, 1, 1, 1]; + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Color": + result.color[0] = child.red; + result.color[1] = child.green; + result.color[2] = child.blue; + result.color[3] = child.alpha; + break; + case "MaterialApplication": + var children2 = child.children; + for (var j = 0, lenj = children2.length; j < lenj; j++) { + var child2 = children2[j]; + switch (child2.type) { + case "MaterialId": + var materialId = getIDFromURI(child2.id); + var material = ctx.materials[materialId]; + if (!material) { + ctx.plugin.error("material not found: " + materialId); + } + result.materialId = materialId; + break; + } + } + break; + } } - if (!ENVIRONMENT_IS_PTHREAD) - __ATINIT__.push({ func: function() { - ___wasm_call_ctors(); - } }); - var asmLibraryArg = { "p": ___assert_fail, "H": ___cxa_allocate_exception, "G": ___cxa_throw, "ha": ___sys_ioctl, "ia": ___sys_open, "na": __embind_finalize_value_array, "w": __embind_finalize_value_object, "ka": __embind_register_bool, "z": __embind_register_class, "y": __embind_register_class_constructor, "e": __embind_register_class_function, "ja": __embind_register_emval, "ma": __embind_register_enum, "E": __embind_register_enum_value, "N": __embind_register_float, "i": __embind_register_function, "u": __embind_register_integer, "q": __embind_register_memory_view, "O": __embind_register_std_string, "F": __embind_register_std_wstring, "oa": __embind_register_value_array, "l": __embind_register_value_array_element, "x": __embind_register_value_object, "h": __embind_register_value_object_field, "la": __embind_register_void, "$": __emscripten_notify_thread_queue, "s": __emval_as, "P": __emval_call, "b": __emval_decref, "Z": __emval_get_global, "t": __emval_get_property, "o": __emval_incref, "ba": __emval_instanceof, "Q": __emval_is_number, "I": __emval_new_array, "j": __emval_new_cstring, "A": __emval_new_object, "r": __emval_run_destructors, "m": __emval_set_property, "g": __emval_take_value, "K": _abort, "fa": _clock_gettime, "B": _emscripten_asm_const_int, "aa": _emscripten_check_blocking_allowed, "J": _emscripten_conditional_set_current_thread_status, "k": _emscripten_futex_wait, "n": _emscripten_futex_wake, "d": _emscripten_get_now, "D": _emscripten_is_main_browser_thread, "C": _emscripten_is_main_runtime_thread, "U": _emscripten_memcpy_big, "W": _emscripten_receive_on_main_thread_js, "v": _emscripten_resize_heap, "X": _emscripten_set_canvas_element_size, "f": _emscripten_set_current_thread_status, "Y": _emscripten_webgl_create_context, "da": _environ_get, "ea": _environ_sizes_get, "M": _fd_close, "ga": _fd_read, "R": _fd_seek, "L": _fd_write, "T": initPthreadsJS, "a": wasmMemory || Module["wasmMemory"], "V": _pthread_cleanup_push, "_": _pthread_create, "c": _pthread_self, "S": _setTempRet0, "ca": _strftime_l }; - createWasm(); - var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() { - return (___wasm_call_ctors = Module["___wasm_call_ctors"] = Module["asm"]["qa"]).apply(null, arguments); - }; - Module["_main"] = function() { - return (Module["_main"] = Module["asm"]["ra"]).apply(null, arguments); - }; - var _malloc = Module["_malloc"] = function() { - return (_malloc = Module["_malloc"] = Module["asm"]["sa"]).apply(null, arguments); - }; - var _free = Module["_free"] = function() { - return (_free = Module["_free"] = Module["asm"]["ta"]).apply(null, arguments); - }; - var ___getTypeName = Module["___getTypeName"] = function() { - return (___getTypeName = Module["___getTypeName"] = Module["asm"]["ua"]).apply(null, arguments); - }; - Module["___embind_register_native_and_builtin_types"] = function() { - return (Module["___embind_register_native_and_builtin_types"] = Module["asm"]["va"]).apply(null, arguments); - }; - var ___errno_location = Module["___errno_location"] = function() { - return (___errno_location = Module["___errno_location"] = Module["asm"]["wa"]).apply(null, arguments); - }; - var _emscripten_get_global_libc = Module["_emscripten_get_global_libc"] = function() { - return (_emscripten_get_global_libc = Module["_emscripten_get_global_libc"] = Module["asm"]["xa"]).apply(null, arguments); - }; - Module["___em_js__initPthreadsJS"] = function() { - return (Module["___em_js__initPthreadsJS"] = Module["asm"]["ya"]).apply(null, arguments); - }; - var stackSave = Module["stackSave"] = function() { - return (stackSave = Module["stackSave"] = Module["asm"]["za"]).apply(null, arguments); - }; - var stackRestore = Module["stackRestore"] = function() { - return (stackRestore = Module["stackRestore"] = Module["asm"]["Aa"]).apply(null, arguments); - }; - var stackAlloc = Module["stackAlloc"] = function() { - return (stackAlloc = Module["stackAlloc"] = Module["asm"]["Ba"]).apply(null, arguments); - }; - var _emscripten_stack_set_limits = Module["_emscripten_stack_set_limits"] = function() { - return (_emscripten_stack_set_limits = Module["_emscripten_stack_set_limits"] = Module["asm"]["Ca"]).apply(null, arguments); - }; - var _memalign = Module["_memalign"] = function() { - return (_memalign = Module["_memalign"] = Module["asm"]["Da"]).apply(null, arguments); - }; - Module["_emscripten_main_browser_thread_id"] = function() { - return (Module["_emscripten_main_browser_thread_id"] = Module["asm"]["Ea"]).apply(null, arguments); - }; - var ___pthread_tsd_run_dtors = Module["___pthread_tsd_run_dtors"] = function() { - return (___pthread_tsd_run_dtors = Module["___pthread_tsd_run_dtors"] = Module["asm"]["Fa"]).apply(null, arguments); - }; - var _emscripten_main_thread_process_queued_calls = Module["_emscripten_main_thread_process_queued_calls"] = function() { - return (_emscripten_main_thread_process_queued_calls = Module["_emscripten_main_thread_process_queued_calls"] = Module["asm"]["Ga"]).apply(null, arguments); - }; - Module["_emscripten_current_thread_process_queued_calls"] = function() { - return (Module["_emscripten_current_thread_process_queued_calls"] = Module["asm"]["Ha"]).apply(null, arguments); - }; - var _emscripten_register_main_browser_thread_id = Module["_emscripten_register_main_browser_thread_id"] = function() { - return (_emscripten_register_main_browser_thread_id = Module["_emscripten_register_main_browser_thread_id"] = Module["asm"]["Ia"]).apply(null, arguments); - }; - var _do_emscripten_dispatch_to_thread = Module["_do_emscripten_dispatch_to_thread"] = function() { - return (_do_emscripten_dispatch_to_thread = Module["_do_emscripten_dispatch_to_thread"] = Module["asm"]["Ja"]).apply(null, arguments); - }; - Module["_emscripten_async_run_in_main_thread"] = function() { - return (Module["_emscripten_async_run_in_main_thread"] = Module["asm"]["Ka"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread"] = function() { - return (Module["_emscripten_sync_run_in_main_thread"] = Module["asm"]["La"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_0"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_0"] = Module["asm"]["Ma"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_1"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_1"] = Module["asm"]["Na"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_2"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_2"] = Module["asm"]["Oa"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_xprintf_varargs"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_xprintf_varargs"] = Module["asm"]["Pa"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_3"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_3"] = Module["asm"]["Qa"]).apply(null, arguments); - }; - var _emscripten_sync_run_in_main_thread_4 = Module["_emscripten_sync_run_in_main_thread_4"] = function() { - return (_emscripten_sync_run_in_main_thread_4 = Module["_emscripten_sync_run_in_main_thread_4"] = Module["asm"]["Ra"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_5"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_5"] = Module["asm"]["Sa"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_6"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_6"] = Module["asm"]["Ta"]).apply(null, arguments); - }; - Module["_emscripten_sync_run_in_main_thread_7"] = function() { - return (Module["_emscripten_sync_run_in_main_thread_7"] = Module["asm"]["Ua"]).apply(null, arguments); - }; - var _emscripten_run_in_main_runtime_thread_js = Module["_emscripten_run_in_main_runtime_thread_js"] = function() { - return (_emscripten_run_in_main_runtime_thread_js = Module["_emscripten_run_in_main_runtime_thread_js"] = Module["asm"]["Va"]).apply(null, arguments); - }; - var __emscripten_call_on_thread = Module["__emscripten_call_on_thread"] = function() { - return (__emscripten_call_on_thread = Module["__emscripten_call_on_thread"] = Module["asm"]["Wa"]).apply(null, arguments); - }; - Module["_emscripten_tls_init"] = function() { - return (Module["_emscripten_tls_init"] = Module["asm"]["Xa"]).apply(null, arguments); - }; - Module["dynCall_jiji"] = function() { - return (Module["dynCall_jiji"] = Module["asm"]["Ya"]).apply(null, arguments); - }; - Module["dynCall_viijii"] = function() { - return (Module["dynCall_viijii"] = Module["asm"]["Za"]).apply(null, arguments); - }; - Module["dynCall_iiiiiijj"] = function() { - return (Module["dynCall_iiiiiijj"] = Module["asm"]["_a"]).apply(null, arguments); - }; - Module["dynCall_iiiiij"] = function() { - return (Module["dynCall_iiiiij"] = Module["asm"]["$a"]).apply(null, arguments); - }; - Module["dynCall_iiiiijj"] = function() { - return (Module["dynCall_iiiiijj"] = Module["asm"]["ab"]).apply(null, arguments); - }; - var _main_thread_futex = Module["_main_thread_futex"] = 51928; - Module["addRunDependency"] = addRunDependency; - Module["removeRunDependency"] = removeRunDependency; - Module["FS_createPath"] = FS.createPath; - Module["FS_createDataFile"] = FS.createDataFile; - Module["FS_createPreloadedFile"] = FS.createPreloadedFile; - Module["FS_createLazyFile"] = FS.createLazyFile; - Module["FS_createDevice"] = FS.createDevice; - Module["FS_unlink"] = FS.unlink; - Module["FS"] = FS; - Module["PThread"] = PThread; - Module["PThread"] = PThread; - Module["_pthread_self"] = _pthread_self; - Module["wasmMemory"] = wasmMemory; - Module["ExitStatus"] = ExitStatus; - var calledRun; - function ExitStatus(status) { - this.name = "ExitStatus"; - this.message = "Program terminated with exit(" + status + ")"; - this.status = status; + } +})(); + +function loadCATMaterialRefDocuments(ctx, materialIds, ok) { + var loaded = {}; + + function load(i, done) { + if (i >= materialIds.length) { + ok(); + return; } - dependenciesFulfilled = function runCaller() { - if (!calledRun) - run(); - if (!calledRun) - dependenciesFulfilled = runCaller; - }; - function callMain(args) { - var entryFunction = Module["_main"]; - var argc = 0; - var argv = 0; - try { - var ret = entryFunction(argc, argv); - exit(ret, true); - } catch (e) { - if (e instanceof ExitStatus) { - return; - } else if (e == "unwind") { - noExitRuntime = true; - return; - } else { - var toLog = e; - if (e && typeof e === "object" && e.stack) { - toLog = [e, e.stack]; - } - err("exception thrown: " + toLog); - quit_(1, e); + var materialId = materialIds[i]; + var src = materialId.id; + var colonIdx = src.lastIndexOf(":"); + if (colonIdx > 0) { + src = src.substring(colonIdx + 1); + } + var hashIdx = src.lastIndexOf("#"); + if (hashIdx > 0) { + src = src.substring(0, hashIdx); + } + if (!loaded[src]) { + loadCATMaterialRefDocument(ctx, src, function () { + loaded[src] = true; + load(i + 1); + }); + } else { + load(i + 1); + } + } + + load(0); +} + +function loadCATMaterialRefDocument(ctx, src, ok) { // Loads CATMaterialRef.3dxml + ctx.zip.getFile(src, function (xmlDoc, json) { + parseCATMaterialRefDocument(ctx, json, ok); + }); +} + +function parseCATMaterialRefDocument(ctx, node, ok) { // Parse CATMaterialRef.3dxml + // ctx.plugin.log("parseCATMaterialRefDocument"); + var children = node.children; + var child; + for (var i = 0, len = children.length; i < len; i++) { + child = children[i]; + if (child.type === "Model_3dxml") { + parseModel_3dxml(ctx, child, ok); + } + } +} + +function parseModel_3dxml(ctx, node, ok) { // Parse CATMaterialRef.3dxml + // ctx.plugin.log("parseModel_3dxml"); + var children = node.children; + var child; + for (var i = 0, len = children.length; i < len; i++) { + child = children[i]; + if (child.type === "CATMaterialRef") { + parseCATMaterialRef(ctx, child, ok); + } + } +} + +function parseCATMaterialRef(ctx, node, ok) { + var domainToReferenceMap = {}; + var children = node.children; + var numToLoad = 0; + for (var j = 0, lenj = children.length; j < lenj; j++) { + var child2 = children[j]; + switch (child2.type) { + case "MaterialDomainInstance": + var isAggregatedBy; + var isInstanceOf; + for (var k = 0, lenk = child2.children.length; k < lenk; k++) { + var child3 = child2.children[k]; + switch (child3.type) { + case "IsAggregatedBy": + isAggregatedBy = child3.children[0]; + break; + case "IsInstanceOf": + isInstanceOf = child3.children[0]; + break; + } + } + domainToReferenceMap[isInstanceOf] = isAggregatedBy; + break; + } + } + for (var j = 0, lenj = children.length; j < lenj; j++) { + var child2 = children[j]; + switch (child2.type) { + case "MaterialDomain": + numToLoad++; + break; + } + } + // Now load them + for (var j = 0, lenj = children.length; j < lenj; j++) { + var child2 = children[j]; + switch (child2.type) { + case "MaterialDomain": + if (child2.associatedFile) { + (function () { + var childId = child2.id; + var src = stripURN(child2.associatedFile); + ctx.zip.getFile(src, function (xmlDoc, json) { + // ctx.plugin.log("Material def loaded: " + src); + ctx.materials[domainToReferenceMap[childId]] = parseMaterialDefDocument(ctx, json); + + if (--numToLoad === 0) { + // console.log("All ReferenceReps loaded."); + ok(); + } + }, + function (error) { + // TODO: + }); + })(); + } + break; + } + } +} + +function parseMaterialDefDocument(ctx, node) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "Osm": + return parseMaterialDefDocumentOsm(ctx, child); + } + } +} + +function parseMaterialDefDocumentOsm(ctx, node) { + var children = node.children; + for (var i = 0, len = children.length; i < len; i++) { + var child = children[i]; + switch (child.type) { + case "RenderingRootFeature": + //.. + break; + case "Feature": + + if (child.Alias === "RenderingFeature") { + // Parse the coefficients, then parse the colors, scaling those by their coefficients. + var coeffs = {}; + var materialCfg = {}; + var children2 = child.children; + var j; + var lenj; + var child2; + for (j = 0, lenj = children2.length; j < lenj; j++) { + child2 = children2[j]; + switch (child2.Name) { + case "AmbientCoef": + coeffs.ambient = parseFloat(child2.Value); + break; + case "DiffuseCoef": + coeffs.diffuse = parseFloat(child2.Value); + break; + case "EmissiveCoef": + coeffs.emissive = parseFloat(child2.Value); + break; + case "SpecularExponent": + coeffs.specular = parseFloat(child2.Value); + break; + } + } + for (j = 0, lenj = children2.length; j < lenj; j++) { + child2 = children2[j]; + switch (child2.Name) { + case "AmbientColor": + materialCfg.ambient = parseRGB(child2.Value, coeffs.ambient); + break; + case "DiffuseColor": + materialCfg.diffuse = parseRGB(child2.Value, coeffs.diffuse); + break; + case "EmissiveColor": + materialCfg.emissive = parseRGB(child2.Value, coeffs.emissive); + break; + case "SpecularColor": + materialCfg.specular = parseRGB(child2.Value, coeffs.specular); + break; + case "Transparency": + var alpha = 1.0 - parseFloat(child2.Value); // GOTCHA: Degree of transparency, not degree of opacity + if (alpha < 1.0) { + materialCfg.alpha = alpha; + materialCfg.alphaMode = "blend"; + } + break; + } + } + + var material; + + switch (ctx.materialType) { + case "MetallicMaterial": + material = new MetallicMaterial(ctx.modelNode, { + baseColor: materialCfg.diffuse, + metallic: 0.7, + roughness: 0.5, + emissive: materialCfg.emissive, + alpha: materialCfg.alpha, + alphaMode: materialCfg.alphaMode + }); + break; + + case "SpecularMaterial": + material = new SpecularMaterial(ctx.modelNode, { + diffuse: materialCfg.diffuse, + specular: materialCfg.specular, + glossiness: 0.5, + emissive: materialCfg.emissive, + alpha: materialCfg.alpha, + alphaMode: materialCfg.alphaMode + }); + break; + + default: + material = new PhongMaterial(ctx.modelNode, { + reflectivity: 0.5, + ambient: materialCfg.ambient, + diffuse: materialCfg.diffuse, + specular: materialCfg.specular, + // shininess: node.shine, + emissive: materialCfg.emissive, + alphaMode: materialCfg.alphaMode, + alpha: node.alpha + }); + } + return material; + } + break; + } + } +} + +function parseRGB(str, coeff) { + coeff = (coeff !== undefined) ? coeff : 0.5; + var openBracketIndex = str.indexOf("["); + var closeBracketIndex = str.indexOf("]"); + str = str.substring(openBracketIndex + 1, closeBracketIndex - openBracketIndex); + str = str.split(","); + var arr = new Float32Array(str.length); + var arrIdx = 0; + for (var i = 0, len = str.length; i < len; i++) { + var value = str[i]; + value = value.trim().split(" "); + for (var j = 0, lenj = value.length; j < lenj; j++) { + if (value[j] !== "") { + arr[arrIdx++] = parseFloat(value[j]) * coeff; } - } finally { - } } - function run(args) { - if (runDependencies > 0) { - return; - } - preRun(); - if (runDependencies > 0) + } + return arr; +} + + +//---------------------------------------------------------------------------------------------------- + +/** + * Wraps zip.js to provide an in-memory ZIP archive representing the 3DXML file bundle. + * + * Allows us to pluck each file from it as XML and JSON. + * + * @constructor + */ +var ZIP = function () { + + var reader; + var files = {}; + + /** + Loads this ZIP + + @param src + @param ok + @param error + */ + this.load = function (src, ok, error) { + zip.createReader(new zip.HttpReader(src), function (reader) { + reader.getEntries(function (entries) { + if (entries.length > 0) { + for (var i = 0, len = entries.length; i < len; i++) { + var entry = entries[i]; + files[entry.filename] = entry; + } + } + ok(); + }); + }, error); + }; + + /** + Gets a file as XML and JSON from this ZIP + @param src + @param ok + @param error + */ + this.getFile = function (src, ok, error) { + var entry = files[src]; + if (!entry) { + var errMsg = "ZIP entry not found: " + src; + console.error(errMsg); + if (error) { + error(errMsg); + } return; - function doRun() { - if (calledRun) - return; - calledRun = true; - Module["calledRun"] = true; - if (ABORT) - return; - initRuntime(); - preMain(); - readyPromiseResolve(Module); - if (Module["onRuntimeInitialized"]) - Module["onRuntimeInitialized"](); - if (shouldRunNow) - callMain(); - postRun(); - } - if (Module["setStatus"]) { - Module["setStatus"]("Running..."); - setTimeout(function() { - setTimeout(function() { - Module["setStatus"](""); - }, 1); - doRun(); - }, 1); - } else { - doRun(); - } } - Module["run"] = run; - function exit(status, implicit) { - if (implicit && noExitRuntime && status === 0) { - return; - } - if (noExitRuntime) ; else { - PThread.terminateAllThreads(); - if (Module["onExit"]) - Module["onExit"](status); - ABORT = true; - } - quit_(status, new ExitStatus(status)); + entry.getData(new zip.TextWriter(), function (text) { + + // Parse to XML + var parser = new DOMParser(); + var xmlDoc = parser.parseFromString(text, "text/xml"); + + // Parse to JSON + var json = xmlToJSON(xmlDoc, {}); + + ok(xmlDoc, json); + }); + }; + + function xmlToJSON(node, attributeRenamer) { + if (node.nodeType === node.TEXT_NODE) { + var v = node.nodeValue; + if (v.match(/^\s+$/) === null) { + return v; + } + } else if (node.nodeType === node.ELEMENT_NODE || + node.nodeType === node.DOCUMENT_NODE) { + var json = {type: node.nodeName, children: []}; + if (node.nodeType === node.ELEMENT_NODE) { + for (var j = 0; j < node.attributes.length; j++) { + var attribute = node.attributes[j]; + var nm = attributeRenamer[attribute.nodeName] || attribute.nodeName; + json[nm] = attribute.nodeValue; + } + } + for (var i = 0; i < node.childNodes.length; i++) { + var item = node.childNodes[i]; + var j = xmlToJSON(item, attributeRenamer); + if (j) json.children.push(j); + } + return json; } - if (Module["preInit"]) { - if (typeof Module["preInit"] == "function") - Module["preInit"] = [Module["preInit"]]; - while (Module["preInit"].length > 0) { - Module["preInit"].pop()(); - } + } + + /** + Disposes of this ZIP + */ + this.destroy = function () { + reader.close(function () { + // onclose callback + }); + }; +}; + +function + +loadZIP(src, ok, err) { + var zip = new ZIP(); + zip.load(src, function () { + ok(zip); + }, function (errMsg) { + err("Error loading ZIP archive: " + errMsg); + }); +} + +function + +stripURN(str) { + var subStr = "urn:3DXML:"; + return (str.indexOf(subStr) === 0) ? str.substring(subStr.length) : str; +} + + +function + +getIDFromURI(str) { + var hashIdx = str.lastIndexOf("#"); + return hashIdx !== -1 ? str.substring(hashIdx + 1) : str; +} + +/** + * {@link Viewer} plugin that loads models from [3DXML](https://en.wikipedia.org/wiki/3DXML) files. + * + * [](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_TreeView) + * + * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_TreeView)] + * + * ## Overview + * + * * Currently supports 3DXML V4.2. + * * Creates an {@link Entity} representing each model it loads, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models}. + * * Creates an {@link Entity} for each object within the model, which will have {@link Entity#isObject} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}. + * * When loading, can set the World-space position, scale and rotation of each model within World space, along with initial properties for all the model's {@link Entity}s. + * * Can optionally load a {@link MetaModel} to classify the objects within the model, from which you can create a tree view using the {@link TreeViewPlugin}. + *
    + * Note that the name of this plugin is intentionally munged to "XML3D" because a JavaScript class name cannot begin with a numeral. + * + * An 3DXML model is a zip archive that bundles multiple XML files and assets. Internally, the XML3DLoaderPlugin uses the + * [zip.js](https://gildas-lormeau.github.io/zip.js/) library to unzip them before loading. The zip.js library uses + * [Web workers](https://www.w3.org/TR/workers/) for fast unzipping, so XML3DLoaderPlugin requires that we configure it + * with a ````workerScriptsPath```` property specifying the directory where zip.js keeps its Web worker script. See + * the example for how to do that. + * + * ## Usage + * + * In the example below, we'll use an XML3DLoaderPlugin to load a 3DXML model. When the model has loaded, + * we'll use the {@link CameraFlightAnimation} to fly the {@link Camera} to look at boundary of the model. We'll + * then get the model's {@link Entity} from the {@link Scene} and highlight the whole model. + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_Widget)] + * + * ````javascript + * // Create a xeokit Viewer + * const viewer = new Viewer({ + * canvasId: "myCanvas" + * }); + * + * // Add an XML3DLoaderPlugin to the Viewer + * var plugin = new XML3DLoaderPlugin(viewer, { + * id: "XML3DLoader", // Default value + * workerScriptsPath : "../../src/plugins/XML3DLoader/zipjs/" // Path to zip.js workers dir + * }); + * + * // Load the 3DXML model + * var model = plugin.load({ // Model is an Entity + * id: "myModel", + * src: "./models/xml3d/3dpreview.3dxml", + * scale: [0.1, 0.1, 0.1], + * rotate: [90, 0, 0], + * translate: [100,0,0], + * edges: true + * }); + * + * // When the model has loaded, fit it to view + * model.on("loaded", function() { + * viewer.cameraFlight.flyTo(model); + * }); + * + * // Update properties of the model via the entity + * model.highlighted = true; + * + * // Find the model Entity by ID + * model = viewer.scene.models["myModel"]; + * + * // Destroy the model + * model.destroy(); + * ```` + * ## Loading MetaModels + * + * We have the option to load a {@link MetaModel} that contains a hierarchy of {@link MetaObject}s that classifes the objects within + * our 3DXML model. + * + * This is useful for building a tree view to navigate the objects, using {@link TreeViewPlugin}. + * + * Let's load the model again, this time creating a MetaModel: + * + * ````javascript + * var model = plugin.load({ + * id: "myModel", + * src: "./models/xml3d/3dpreview.3dxml", + * scale: [0.1, 0.1, 0.1], + * rotate: [90, 0, 0], + * translate: [100,0,0], + * edges: true, + * + * createMetaModel: true // <<-------- Create a MetaModel + * }); + * ```` + * + * The MetaModel can then be found on the {@link Viewer}'s {@link MetaScene}, using the model's ID: + * + * ````javascript + * const metaModel = viewer.metaScene.metaModels["myModel"]; + * ```` + * + * Now we can use {@link TreeViewPlugin} to create a tree view to navigate our model's objects: + * + * ````javascript + * import {TreeViewPlugin} from "xeokit-sdk.es.js""xeokit-sdk.es.js"; + * + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("myTreeViewContainer") + * }); + * + * const treeView = new TreeViewPlugin(viewer, { + * containerElement: document.getElementById("treeViewContainer"), + * autoExpandDepth: 3, // Initially expand tree three storeys deep + * hierarchy: "containment", + * autoAddModels: false + * }); + * + * model.on("loaded", () => { + * treeView.addModel(model.id); + * }); + * ```` + * + * Note that only the TreeViewPlugin "containment" hierarchy makes sense for an XML3D model. A "types" hierarchy + * does not make sense because XML3DLoaderPlugin will set each {@link MetaObject#type} to "Default", and "storeys" + * does not make sense because that requires some of the MetaObject#type values to be "IfcBuildingStorey". + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_TreeView)] + * + * ## Material Type + * + * Although 3DXML only supports Phong materials, XML3DLoaderPlugin is able to convert them to physically-based materials. + * + * The plugin supports three material types: + * + * | Material Type | Material Components Loaded | Description | Example | + * |:--------:|:----:|:-----:|:-----:| + * | "PhongMaterial" (default) | {@link PhongMaterial} | Non-physically-correct Blinn-Phong shading model | [Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Phong) | + * | "MetallicMaterial" | {@link MetallicMaterial} | Physically-accurate specular-glossiness shading model | [Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Metallic) | + * | "SpecularMaterial" | {@link SpecularMaterial} | Physically-accurate metallic-roughness shading model | [Run example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Specular) | + * + *
    + * Let's load our model again, this time converting the 3DXML Blinn-Phong materials to {@link SpecularMaterial}s: + * + * ````javascript + * var model = plugin.load({ // Model is an Entity + * id: "myModel", + * src: "./models/xml3d/3dpreview.3dxml", + * materialtype: "SpecularMaterial": true" + * }); + * ```` + * + * * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/#loading_3DXML_materialType_Specular)] + * + * @class XML3DLoaderPlugin + */ + +class XML3DLoaderPlugin extends Plugin { + + /** + * @constructor + * @param {Viewer} viewer The Viewer. + * @param {Object} cfg Plugin configuration. + * @param {String} [cfg.id="XML3DLoader"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}. + * @param {String} cfg.workerScriptsPath Path to the directory that contains the + * bundled [zip.js](https://gildas-lormeau.github.io/zip.js/) archive, which is a dependency of this plugin. This directory + * contains the script that is used by zip.js to instantiate Web workers, which assist with unzipping the 3DXML, which is a ZIP archive. + * @param {String} [cfg.materialType="PhongMaterial"] What type of materials to create while loading: "MetallicMaterial" to create {@link MetallicMaterial}s, "SpecularMaterial" to create {@link SpecularMaterial}s or "PhongMaterial" to create {@link PhongMaterial}s. As it loads XML3D's Phong materials, the XMLLoaderPlugin will do its best approximate conversion of those to the specified workflow. + * @param {Boolean} [cfg.createMetaModel=false] When true, will create a {@link MetaModel} for the model in {@link MetaScene#metaModels}. + */ + constructor(viewer, cfg = {}) { + + super("XML3DLoader", viewer, cfg); + + if (!cfg.workerScriptsPath) { + this.error("Config expected: workerScriptsPath"); + return } - var shouldRunNow = true; - if (Module["noInitialRun"]) - shouldRunNow = false; - if (!ENVIRONMENT_IS_PTHREAD) - noExitRuntime = true; - if (!ENVIRONMENT_IS_PTHREAD) { - run(); - } else { - PThread.initWorker(); + + this._workerScriptsPath = cfg.workerScriptsPath; + + /** + * @private + */ + this._loader = new XML3DSceneGraphLoader(this, cfg); + + /** + * Supported 3DXML schema versions + * @property supportedSchemas + * @type {string[]} + */ + this.supportedSchemas = this._loader.supportedSchemas; + } + + /** + * Loads a 3DXML model from a file into this XML3DLoaderPlugin's {@link Viewer}. + * + * Creates a tree of {@link Entity}s within the Viewer's {@link Scene} that represents the model. + * + * @param {*} params Loading parameters. + * @param {String} params.id ID to assign to the model's root {@link Entity}, unique among all components in the Viewer's {@link Scene}. + * @param {String} [params.src] Path to a 3DXML file. + * @param {Boolean} [params.edges=false] Whether or not xeokit renders the {@link Entity} with edges emphasized. + * @param {Number[]} [params.position=[0,0,0]] The model's World-space 3D position. + * @param {Number[]} [params.scale=[1,1,1]] The model's World-space scale. + * @param {Number[]} [params.rotation=[0,0,0]] The model's World-space rotation, as Euler angles given in degrees, for each of the X, Y and Z axis. + * @param {Number[]} [params.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] The model's world transform matrix. Overrides the position, scale and rotation parameters. + * @param {Boolean} [params.backfaces=false] When true, allows visible backfaces, wherever specified in the 3DXML. When false, ignores backfaces. + * @param {Number} [params.edgeThreshold=20] When xraying, highlighting, selecting or edging, this is the threshold angle between normals of adjacent triangles, below which their shared wireframe edge is not drawn. + * @param {String} [params.materialType="PhongMaterial"] What type of materials to create while loading: "MetallicMaterial" to create {@link MetallicMaterial}s, "SpecularMaterial" to create {@link SpecularMaterial}s or "PhongMaterial" to create {@link PhongMaterial}s. As it loads XML3D's Phong materials, the XMLLoaderPlugin will do its best approximate conversion of those to the specified workflow. + * @param {Boolean} [params.createMetaModel=false] When true, will create a {@link MetaModel} for the model in {@link MetaScene#metaModels}. + * @returns {Entity} Entity representing the model, which will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id} in {@link Scene#models} + */ + load(params = {}) { + + params.workerScriptsPath = this._workerScriptsPath; + + if (params.id && this.viewer.scene.components[params.id]) { + this.error("Component with this ID already exists in viewer: " + params.id + " - will autogenerate this ID"); + delete params.id; } - return WebIFCWasm3.ready; - }; - }(); - if (typeof exports === "object" && typeof module === "object") - module.exports = WebIFCWasm2; - else if (typeof define === "function" && define["amd"]) - define([], function() { - return WebIFCWasm2; - }); - else if (typeof exports === "object") - exports["WebIFCWasm"] = WebIFCWasm2; + + const modelNode = new Node$1(this.viewer.scene, utils.apply(params, { + isModel: true + })); + + const src = params.src; + + if (!src) { + this.error("load() param expected: src"); + return modelNode; // Return new empty model + } + + this._loader.load(this, modelNode, src, params); + + return modelNode; + } +} + +var __defProp = Object.defineProperty; +var __getOwnPropSymbols = Object.getOwnPropertySymbols; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __propIsEnum = Object.prototype.propertyIsEnumerable; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __spreadValues = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + if (__getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(b)) { + if (__propIsEnum.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + } + return a; +}; +var __require = (x) => { + if (typeof require !== "undefined") + return require(x); + throw new Error('Dynamic require of "' + x + '" is not supported'); +}; +var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __async = (__this, __arguments, generator) => { + return new Promise((resolve, reject) => { + var fulfilled = (value) => { + try { + step(generator.next(value)); + } catch (e) { + reject(e); + } + }; + var rejected = (value) => { + try { + step(generator.throw(value)); + } catch (e) { + reject(e); + } + }; + var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); + step((generator = generator.apply(__this, __arguments)).next()); + }); +}; + +// (disabled):crypto +var require_crypto = __commonJS({ + "(disabled):crypto"() { } }); -// dist/web-ifc.js -var require_web_ifc = __commonJS({ - "dist/web-ifc.js"(exports, module) { +// dist/web-ifc-mt.js +var require_web_ifc_mt = __commonJS({ + "dist/web-ifc-mt.js"(exports, module) { var WebIFCWasm2 = function() { var _scriptDir = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : void 0; if (typeof __filename !== "undefined") _scriptDir = _scriptDir || __filename; return function(WebIFCWasm3) { WebIFCWasm3 = WebIFCWasm3 || {}; + function GROWABLE_HEAP_I8() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAP8; + } + function GROWABLE_HEAP_U8() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAPU8; + } + function GROWABLE_HEAP_I16() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAP16; + } + function GROWABLE_HEAP_U16() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAPU16; + } + function GROWABLE_HEAP_I32() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAP32; + } + function GROWABLE_HEAP_U32() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAPU32; + } + function GROWABLE_HEAP_F32() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAPF32; + } + function GROWABLE_HEAP_F64() { + if (wasmMemory.buffer != buffer) { + updateGlobalBufferAndViews(wasmMemory.buffer); + } + return HEAPF64; + } var Module = typeof WebIFCWasm3 !== "undefined" ? WebIFCWasm3 : {}; var readyPromiseResolve, readyPromiseReject; Module["ready"] = new Promise(function(resolve, reject) { @@ -112081,14 +118403,10 @@ var require_web_ifc = __commonJS({ var quit_ = function(status, toThrow) { throw toThrow; }; - var ENVIRONMENT_IS_WEB = false; - var ENVIRONMENT_IS_WORKER = false; - var ENVIRONMENT_IS_NODE = false; - var ENVIRONMENT_IS_SHELL = false; - ENVIRONMENT_IS_WEB = typeof window === "object"; - ENVIRONMENT_IS_WORKER = typeof importScripts === "function"; - ENVIRONMENT_IS_NODE = typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string"; - ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; + var ENVIRONMENT_IS_WEB = typeof window === "object"; + var ENVIRONMENT_IS_WORKER = typeof importScripts === "function"; + var ENVIRONMENT_IS_NODE = typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string"; + var ENVIRONMENT_IS_PTHREAD = Module["ENVIRONMENT_IS_PTHREAD"] || false; var scriptDirectory = ""; function locateFile(path) { if (Module["locateFile"]) { @@ -112096,7 +118414,7 @@ var require_web_ifc = __commonJS({ } return scriptDirectory + path; } - var read_, readBinary; + var read_, readAsync, readBinary; var nodeFS; var nodePath; if (ENVIRONMENT_IS_NODE) { @@ -112121,6 +118439,19 @@ var require_web_ifc = __commonJS({ assert(ret.buffer); return ret; }; + readAsync = function readAsync2(filename, onload, onerror) { + if (!nodeFS) + nodeFS = __require("fs"); + if (!nodePath) + nodePath = __require("path"); + filename = nodePath["normalize"](filename); + nodeFS["readFile"](filename, function(err2, data) { + if (err2) + onerror(err2); + else + onload(data.buffer); + }); + }; if (process["argv"].length > 1) { thisProgram = process["argv"][1].replace(/\\/g, "/"); } @@ -112131,41 +118462,24 @@ var require_web_ifc = __commonJS({ } }); process["on"]("unhandledRejection", abort); - quit_ = function(status) { + quit_ = function(status, toThrow) { + if (keepRuntimeAlive()) { + process["exitCode"] = status; + throw toThrow; + } process["exit"](status); }; Module["inspect"] = function() { return "[Emscripten Module object]"; }; - } else if (ENVIRONMENT_IS_SHELL) { - if (typeof read != "undefined") { - read_ = function shell_read(f) { - return read(f); - }; - } - readBinary = function readBinary2(f) { - var data; - if (typeof readbuffer === "function") { - return new Uint8Array(readbuffer(f)); - } - data = read(f, "binary"); - assert(typeof data === "object"); - return data; - }; - if (typeof scriptArgs != "undefined") { - scriptArgs; - } - if (typeof quit === "function") { - quit_ = function(status) { - quit(status); - }; - } - if (typeof print !== "undefined") { - if (typeof console === "undefined") - console = {}; - console.log = print; - console.warn = console.error = typeof printErr !== "undefined" ? printErr : print; + var nodeWorkerThreads; + try { + nodeWorkerThreads = __require("worker_threads"); + } catch (e) { + console.error('The "worker_threads" module is not supported in this node.js build - perhaps a newer version is needed?'); + throw e; } + global.Worker = nodeWorkerThreads.Worker; } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { if (ENVIRONMENT_IS_WORKER) { scriptDirectory = self.location.href; @@ -112180,15 +118494,45 @@ var require_web_ifc = __commonJS({ } else { scriptDirectory = ""; } - { - read_ = function shell_read(url) { + if (ENVIRONMENT_IS_NODE) { + read_ = function shell_read(filename, binary) { + if (!nodeFS) + nodeFS = __require("fs"); + if (!nodePath) + nodePath = __require("path"); + filename = nodePath["normalize"](filename); + return nodeFS["readFileSync"](filename, binary ? null : "utf8"); + }; + readBinary = function readBinary2(filename) { + var ret = read_(filename, true); + if (!ret.buffer) { + ret = new Uint8Array(ret); + } + assert(ret.buffer); + return ret; + }; + readAsync = function readAsync2(filename, onload, onerror) { + if (!nodeFS) + nodeFS = __require("fs"); + if (!nodePath) + nodePath = __require("path"); + filename = nodePath["normalize"](filename); + nodeFS["readFile"](filename, function(err2, data) { + if (err2) + onerror(err2); + else + onload(data.buffer); + }); + }; + } else { + read_ = function(url) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.send(null); return xhr.responseText; }; if (ENVIRONMENT_IS_WORKER) { - readBinary = function readBinary2(url) { + readBinary = function(url) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.responseType = "arraybuffer"; @@ -112196,12 +118540,31 @@ var require_web_ifc = __commonJS({ return new Uint8Array(xhr.response); }; } + readAsync = function(url, onload, onerror) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + xhr.onload = function() { + if (xhr.status == 200 || xhr.status == 0 && xhr.response) { + onload(xhr.response); + return; + } + onerror(); + }; + xhr.onerror = onerror; + xhr.send(null); + }; } } else ; - var out = Module["print"] || console.log.bind(console); - var err = Module["printErr"] || console.warn.bind(console); - for (key in moduleOverrides) { - if (moduleOverrides.hasOwnProperty(key)) { + if (ENVIRONMENT_IS_NODE) { + if (typeof performance === "undefined") { + global.performance = __require("perf_hooks").performance; + } + } + var out = Module["print"] || console.log.bind(console); + var err = Module["printErr"] || console.warn.bind(console); + for (key in moduleOverrides) { + if (moduleOverrides.hasOwnProperty(key)) { Module[key] = moduleOverrides[key]; } } @@ -112218,23 +118581,39 @@ var require_web_ifc = __commonJS({ factor = STACK_ALIGN; return Math.ceil(size / factor) * factor; } + function warnOnce(text) { + if (!warnOnce.shown) + warnOnce.shown = {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + err(text); + } + } var wasmBinary; if (Module["wasmBinary"]) wasmBinary = Module["wasmBinary"]; - var noExitRuntime; - if (Module["noExitRuntime"]) - noExitRuntime = Module["noExitRuntime"]; + var noExitRuntime = Module["noExitRuntime"] || true; if (typeof WebAssembly !== "object") { abort("no native wasm support detected"); } var wasmMemory; + var wasmModule; var ABORT = false; function assert(condition, text) { if (!condition) { abort("Assertion failed: " + text); } } - var UTF8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf8") : void 0; + function TextDecoderWrapper(encoding) { + var textDecoder = new TextDecoder(encoding); + this.decode = function(data) { + if (data.buffer instanceof SharedArrayBuffer) { + data = new Uint8Array(data); + } + return textDecoder.decode.call(textDecoder, data); + }; + } + var UTF8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoderWrapper("utf8") : void 0; function UTF8ArrayToString(heap, idx, maxBytesToRead) { idx >>>= 0; var endIdx = idx + maxBytesToRead; @@ -112274,7 +118653,7 @@ var require_web_ifc = __commonJS({ } function UTF8ToString(ptr, maxBytesToRead) { ptr >>>= 0; - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; + return ptr ? UTF8ArrayToString(GROWABLE_HEAP_U8(), ptr, maxBytesToRead) : ""; } function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { outIdx >>>= 0; @@ -112316,7 +118695,7 @@ var require_web_ifc = __commonJS({ return outIdx - startIdx; } function stringToUTF8(str, outPtr, maxBytesToWrite) { - return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + return stringToUTF8Array(str, GROWABLE_HEAP_U8(), outPtr, maxBytesToWrite); } function lengthBytesUTF8(str) { var len = 0; @@ -112335,20 +118714,20 @@ var require_web_ifc = __commonJS({ } return len; } - var UTF16Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le") : void 0; + var UTF16Decoder = typeof TextDecoder !== "undefined" ? new TextDecoderWrapper("utf-16le") : void 0; function UTF16ToString(ptr, maxBytesToRead) { var endPtr = ptr; var idx = endPtr >> 1; var maxIdx = idx + maxBytesToRead / 2; - while (!(idx >= maxIdx) && HEAPU16[idx >>> 0]) + while (!(idx >= maxIdx) && GROWABLE_HEAP_U16()[idx >>> 0]) ++idx; endPtr = idx << 1; if (endPtr - ptr > 32 && UTF16Decoder) { - return UTF16Decoder.decode(HEAPU8.subarray(ptr >>> 0, endPtr >>> 0)); + return UTF16Decoder.decode(GROWABLE_HEAP_U8().subarray(ptr >>> 0, endPtr >>> 0)); } else { var str = ""; for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { - var codeUnit = HEAP16[ptr + i * 2 >>> 1]; + var codeUnit = GROWABLE_HEAP_I16()[ptr + i * 2 >>> 1]; if (codeUnit == 0) break; str += String.fromCharCode(codeUnit); @@ -112367,10 +118746,10 @@ var require_web_ifc = __commonJS({ var numCharsToWrite = maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length; for (var i = 0; i < numCharsToWrite; ++i) { var codeUnit = str.charCodeAt(i); - HEAP16[outPtr >>> 1] = codeUnit; + GROWABLE_HEAP_I16()[outPtr >>> 1] = codeUnit; outPtr += 2; } - HEAP16[outPtr >>> 1] = 0; + GROWABLE_HEAP_I16()[outPtr >>> 1] = 0; return outPtr - startPtr; } function lengthBytesUTF16(str) { @@ -112380,7 +118759,7 @@ var require_web_ifc = __commonJS({ var i = 0; var str = ""; while (!(i >= maxBytesToRead / 4)) { - var utf32 = HEAP32[ptr + i * 4 >>> 2]; + var utf32 = GROWABLE_HEAP_I32()[ptr + i * 4 >>> 2]; if (utf32 == 0) break; ++i; @@ -112408,12 +118787,12 @@ var require_web_ifc = __commonJS({ var trailSurrogate = str.charCodeAt(++i); codeUnit = 65536 + ((codeUnit & 1023) << 10) | trailSurrogate & 1023; } - HEAP32[outPtr >>> 2] = codeUnit; + GROWABLE_HEAP_I32()[outPtr >>> 2] = codeUnit; outPtr += 4; if (outPtr + 4 > endPtr) break; } - HEAP32[outPtr >>> 2] = 0; + GROWABLE_HEAP_I32()[outPtr >>> 2] = 0; return outPtr - startPtr; } function lengthBytesUTF32(str) { @@ -112427,14 +118806,14 @@ var require_web_ifc = __commonJS({ return len; } function writeArrayToMemory(array, buffer2) { - HEAP8.set(array, buffer2 >>> 0); + GROWABLE_HEAP_I8().set(array, buffer2 >>> 0); } function writeAsciiToMemory(str, buffer2, dontAddNull) { for (var i = 0; i < str.length; ++i) { - HEAP8[buffer2++ >>> 0] = str.charCodeAt(i); + GROWABLE_HEAP_I8()[buffer2++ >>> 0] = str.charCodeAt(i); } if (!dontAddNull) - HEAP8[buffer2 >>> 0] = 0; + GROWABLE_HEAP_I8()[buffer2 >>> 0] = 0; } function alignUp(x, multiple) { if (x % multiple > 0) { @@ -112443,6 +118822,9 @@ var require_web_ifc = __commonJS({ return x; } var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; + if (ENVIRONMENT_IS_PTHREAD) { + buffer = Module["buffer"]; + } function updateGlobalBufferAndViews(buf) { buffer = buf; Module["HEAP8"] = HEAP8 = new Int8Array(buf); @@ -112455,10 +118837,22 @@ var require_web_ifc = __commonJS({ Module["HEAPF64"] = HEAPF64 = new Float64Array(buf); } var INITIAL_MEMORY = Module["INITIAL_MEMORY"] || 16777216; - if (Module["wasmMemory"]) { + if (ENVIRONMENT_IS_PTHREAD) { wasmMemory = Module["wasmMemory"]; + buffer = Module["buffer"]; } else { - wasmMemory = new WebAssembly.Memory({ "initial": INITIAL_MEMORY / 65536, "maximum": 4294967296 / 65536 }); + if (Module["wasmMemory"]) { + wasmMemory = Module["wasmMemory"]; + } else { + wasmMemory = new WebAssembly.Memory({ "initial": INITIAL_MEMORY / 65536, "maximum": 4294967296 / 65536, "shared": true }); + if (!(wasmMemory.buffer instanceof SharedArrayBuffer)) { + err("requested a shared WebAssembly.Memory but the returned buffer is not a SharedArrayBuffer, indicating that while the browser has SharedArrayBuffer it does not have WebAssembly threads support - you may need to set a flag"); + if (ENVIRONMENT_IS_NODE) { + console.log("(on node you may need: --experimental-wasm-threads --experimental-wasm-bulk-memory and also use a recent version)"); + } + throw Error("bad memory"); + } + } } if (wasmMemory) { buffer = wasmMemory.buffer; @@ -112470,7 +118864,13 @@ var require_web_ifc = __commonJS({ var __ATINIT__ = []; var __ATMAIN__ = []; var __ATPOSTRUN__ = []; + var runtimeKeepaliveCounter = 0; + function keepRuntimeAlive() { + return noExitRuntime || runtimeKeepaliveCounter > 0; + } function preRun() { + if (ENVIRONMENT_IS_PTHREAD) + return; if (Module["preRun"]) { if (typeof Module["preRun"] == "function") Module["preRun"] = [Module["preRun"]]; @@ -112481,15 +118881,21 @@ var require_web_ifc = __commonJS({ callRuntimeCallbacks(__ATPRERUN__); } function initRuntime() { + if (ENVIRONMENT_IS_PTHREAD) + return; if (!Module["noFSInit"] && !FS.init.initialized) FS.init(); + FS.ignorePermissions = false; callRuntimeCallbacks(__ATINIT__); } function preMain() { - FS.ignorePermissions = false; + if (ENVIRONMENT_IS_PTHREAD) + return; callRuntimeCallbacks(__ATMAIN__); } function postRun() { + if (ENVIRONMENT_IS_PTHREAD) + return; if (Module["postRun"]) { if (typeof Module["postRun"] == "function") Module["postRun"] = [Module["postRun"]]; @@ -112502,11 +118908,17 @@ var require_web_ifc = __commonJS({ function addOnPreRun(cb) { __ATPRERUN__.unshift(cb); } + function addOnInit(cb) { + __ATINIT__.unshift(cb); + } function addOnPostRun(cb) { __ATPOSTRUN__.unshift(cb); } var runDependencies = 0; var dependenciesFulfilled = null; + function getUniqueRunDependency(id) { + return id; + } function addRunDependency(id) { runDependencies++; if (Module["monitorRunDependencies"]) { @@ -112532,6 +118944,8 @@ var require_web_ifc = __commonJS({ if (Module["onAbort"]) { Module["onAbort"](what); } + if (ENVIRONMENT_IS_PTHREAD) + console.error("Pthread aborting at " + new Error().stack); what += ""; err(what); ABORT = true; @@ -112540,28 +118954,25 @@ var require_web_ifc = __commonJS({ readyPromiseReject(e); throw e; } - function hasPrefix(str, prefix) { - return String.prototype.startsWith ? str.startsWith(prefix) : str.indexOf(prefix) === 0; - } var dataURIPrefix = "data:application/octet-stream;base64,"; function isDataURI(filename) { - return hasPrefix(filename, dataURIPrefix); + return filename.startsWith(dataURIPrefix); } - var fileURIPrefix = "file://"; function isFileURI(filename) { - return hasPrefix(filename, fileURIPrefix); + return filename.startsWith("file://"); } - var wasmBinaryFile = "web-ifc.wasm"; + var wasmBinaryFile; + wasmBinaryFile = "web-ifc-mt.wasm"; if (!isDataURI(wasmBinaryFile)) { wasmBinaryFile = locateFile(wasmBinaryFile); } - function getBinary() { + function getBinary(file) { try { - if (wasmBinary) { + if (file == wasmBinaryFile && wasmBinary) { return new Uint8Array(wasmBinary); } if (readBinary) { - return readBinary(wasmBinaryFile); + return readBinary(file); } else { throw "both async and sync fetching of the wasm failed"; } @@ -112570,33 +118981,59 @@ var require_web_ifc = __commonJS({ } } function getBinaryPromise() { - if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) && typeof fetch === "function" && !isFileURI(wasmBinaryFile)) { - return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { - if (!response["ok"]) { - throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (typeof fetch === "function" && !isFileURI(wasmBinaryFile)) { + return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { + if (!response["ok"]) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; + } + return response["arrayBuffer"](); + }).catch(function() { + return getBinary(wasmBinaryFile); + }); + } else { + if (readAsync) { + return new Promise(function(resolve, reject) { + readAsync(wasmBinaryFile, function(response) { + resolve(new Uint8Array(response)); + }, reject); + }); } - return response["arrayBuffer"](); - }).catch(function() { - return getBinary(); - }); + } } - return Promise.resolve().then(getBinary); + return Promise.resolve().then(function() { + return getBinary(wasmBinaryFile); + }); } function createWasm() { var info = { "a": asmLibraryArg }; function receiveInstance(instance, module2) { var exports3 = instance.exports; Module["asm"] = exports3; - wasmTable = Module["asm"]["ba"]; - removeRunDependency(); + wasmTable = Module["asm"]["ta"]; + addOnInit(Module["asm"]["oa"]); + PThread.tlsInitFunctions.push(Module["asm"]["sa"]); + wasmModule = module2; + if (!ENVIRONMENT_IS_PTHREAD) { + var numWorkersToLoad = PThread.unusedWorkers.length; + PThread.unusedWorkers.forEach(function(w) { + PThread.loadWasmModuleToWorker(w, function() { + if (!--numWorkersToLoad) + removeRunDependency(); + }); + }); + } } - addRunDependency(); - function receiveInstantiatedSource(output) { - receiveInstance(output["instance"]); + if (!ENVIRONMENT_IS_PTHREAD) { + addRunDependency(); + } + function receiveInstantiationResult(result) { + receiveInstance(result["instance"], result["module"]); } function instantiateArrayBuffer(receiver) { return getBinaryPromise().then(function(binary) { - return WebAssembly.instantiate(binary, info); + var result = WebAssembly.instantiate(binary, info); + return result; }).then(receiver, function(reason) { err("failed to asynchronously prepare wasm: " + reason); abort(reason); @@ -112606,14 +119043,14 @@ var require_web_ifc = __commonJS({ if (!wasmBinary && typeof WebAssembly.instantiateStreaming === "function" && !isDataURI(wasmBinaryFile) && !isFileURI(wasmBinaryFile) && typeof fetch === "function") { return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { var result = WebAssembly.instantiateStreaming(response, info); - return result.then(receiveInstantiatedSource, function(reason) { + return result.then(receiveInstantiationResult, function(reason) { err("wasm streaming compile failed: " + reason); err("falling back to ArrayBuffer instantiation"); - return instantiateArrayBuffer(receiveInstantiatedSource); + return instantiateArrayBuffer(receiveInstantiationResult); }); }); } else { - return instantiateArrayBuffer(receiveInstantiatedSource); + return instantiateArrayBuffer(receiveInstantiationResult); } } if (Module["instantiateWasm"]) { @@ -112630,6 +119067,16 @@ var require_web_ifc = __commonJS({ } var tempDouble; var tempI64; + var ASM_CONSTS = { 44848: function() { + throw "Canceled!"; + }, 44866: function($0, $1) { + setTimeout(function() { + __emscripten_do_dispatch_to_thread($0, $1); + }, 0); + } }; + function initPthreadsJS() { + PThread.initRuntime(); + } function callRuntimeCallbacks(callbacks) { while (callbacks.length > 0) { var callback = callbacks.shift(); @@ -112649,56 +119096,342 @@ var require_web_ifc = __commonJS({ } } } - function dynCallLegacy(sig, ptr, args) { - if (args && args.length) { - return Module["dynCall_" + sig].apply(null, [ptr].concat(args)); + function _emscripten_futex_wake(addr, count) { + if (addr <= 0 || addr > GROWABLE_HEAP_I8().length || addr & true || count < 0) + return -28; + if (count == 0) + return 0; + if (count >= 2147483647) + count = Infinity; + var mainThreadWaitAddress = Atomics.load(GROWABLE_HEAP_I32(), __emscripten_main_thread_futex >> 2); + var mainThreadWoken = 0; + if (mainThreadWaitAddress == addr) { + var loadedAddr = Atomics.compareExchange(GROWABLE_HEAP_I32(), __emscripten_main_thread_futex >> 2, mainThreadWaitAddress, 0); + if (loadedAddr == mainThreadWaitAddress) { + --count; + mainThreadWoken = 1; + if (count <= 0) + return 1; + } } - return Module["dynCall_" + sig].call(null, ptr); + var ret = Atomics.notify(GROWABLE_HEAP_I32(), addr >> 2, count); + if (ret >= 0) + return ret + mainThreadWoken; + throw "Atomics.notify returned an unexpected value " + ret; } - function dynCall(sig, ptr, args) { - if (sig.indexOf("j") != -1) { - return dynCallLegacy(sig, ptr, args); + Module["_emscripten_futex_wake"] = _emscripten_futex_wake; + function killThread(pthread_ptr) { + if (ENVIRONMENT_IS_PTHREAD) + throw "Internal Error! killThread() can only ever be called from main application thread!"; + if (!pthread_ptr) + throw "Internal Error! Null pthread_ptr in killThread!"; + GROWABLE_HEAP_I32()[pthread_ptr + 12 >>> 2] = 0; + var pthread = PThread.pthreads[pthread_ptr]; + pthread.worker.terminate(); + PThread.freeThreadData(pthread); + PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(pthread.worker), 1); + pthread.worker.pthread = void 0; + } + function cancelThread(pthread_ptr) { + if (ENVIRONMENT_IS_PTHREAD) + throw "Internal Error! cancelThread() can only ever be called from main application thread!"; + if (!pthread_ptr) + throw "Internal Error! Null pthread_ptr in cancelThread!"; + var pthread = PThread.pthreads[pthread_ptr]; + pthread.worker.postMessage({ "cmd": "cancel" }); + } + function cleanupThread(pthread_ptr) { + if (ENVIRONMENT_IS_PTHREAD) + throw "Internal Error! cleanupThread() can only ever be called from main application thread!"; + if (!pthread_ptr) + throw "Internal Error! Null pthread_ptr in cleanupThread!"; + var pthread = PThread.pthreads[pthread_ptr]; + if (pthread) { + GROWABLE_HEAP_I32()[pthread_ptr + 12 >>> 2] = 0; + var worker = pthread.worker; + PThread.returnWorkerToPool(worker); } - return wasmTable.get(ptr).apply(null, args); } + var PThread = { unusedWorkers: [], runningWorkers: [], tlsInitFunctions: [], initMainThreadBlock: function() { + var pthreadPoolSize = navigator.hardwareConcurrency; + for (var i = 0; i < pthreadPoolSize; ++i) { + PThread.allocateUnusedWorker(); + } + }, initRuntime: function() { + var tb = _malloc(228); + for (var i = 0; i < 228 / 4; ++i) + GROWABLE_HEAP_U32()[tb / 4 + i >>> 0] = 0; + GROWABLE_HEAP_I32()[tb + 12 >>> 2] = tb; + var headPtr = tb + 152; + GROWABLE_HEAP_I32()[headPtr >>> 2] = headPtr; + var tlsMemory = _malloc(512); + for (var i = 0; i < 128; ++i) + GROWABLE_HEAP_U32()[tlsMemory / 4 + i >>> 0] = 0; + Atomics.store(GROWABLE_HEAP_U32(), tb + 100 >> 2, tlsMemory); + Atomics.store(GROWABLE_HEAP_U32(), tb + 40 >> 2, tb); + __emscripten_thread_init(tb, !ENVIRONMENT_IS_WORKER, 1); + _emscripten_register_main_browser_thread_id(tb); + }, initWorker: function() { + }, pthreads: {}, threadExitHandlers: [], runExitHandlers: function() { + while (PThread.threadExitHandlers.length > 0) { + PThread.threadExitHandlers.pop()(); + } + ___pthread_tsd_run_dtors(); + }, runExitHandlersAndDeinitThread: function(tb, exitCode) { + Atomics.store(GROWABLE_HEAP_U32(), tb + 56 >> 2, 1); + Atomics.store(GROWABLE_HEAP_U32(), tb + 60 >> 2, 0); + PThread.runExitHandlers(); + Atomics.store(GROWABLE_HEAP_U32(), tb + 4 >> 2, exitCode); + Atomics.store(GROWABLE_HEAP_U32(), tb + 0 >> 2, 1); + _emscripten_futex_wake(tb + 0, 2147483647); + __emscripten_thread_init(0, 0, 0); + }, setExitStatus: function(status) { + }, threadExit: function(exitCode) { + var tb = _pthread_self(); + if (tb) { + PThread.runExitHandlersAndDeinitThread(tb, exitCode); + if (ENVIRONMENT_IS_PTHREAD) { + postMessage({ "cmd": "exit" }); + } + } + }, threadCancel: function() { + PThread.runExitHandlersAndDeinitThread(_pthread_self(), -1); + postMessage({ "cmd": "cancelDone" }); + }, terminateAllThreads: function() { + for (var t in PThread.pthreads) { + var pthread = PThread.pthreads[t]; + if (pthread && pthread.worker) { + PThread.returnWorkerToPool(pthread.worker); + } + } + PThread.pthreads = {}; + for (var i = 0; i < PThread.unusedWorkers.length; ++i) { + var worker = PThread.unusedWorkers[i]; + worker.terminate(); + } + PThread.unusedWorkers = []; + for (var i = 0; i < PThread.runningWorkers.length; ++i) { + var worker = PThread.runningWorkers[i]; + var pthread = worker.pthread; + PThread.freeThreadData(pthread); + worker.terminate(); + } + PThread.runningWorkers = []; + }, freeThreadData: function(pthread) { + if (!pthread) + return; + if (pthread.threadInfoStruct) { + var tlsMemory = GROWABLE_HEAP_I32()[pthread.threadInfoStruct + 100 >>> 2]; + GROWABLE_HEAP_I32()[pthread.threadInfoStruct + 100 >>> 2] = 0; + _free(tlsMemory); + _free(pthread.threadInfoStruct); + } + pthread.threadInfoStruct = 0; + if (pthread.allocatedOwnStack && pthread.stackBase) + _free(pthread.stackBase); + pthread.stackBase = 0; + if (pthread.worker) + pthread.worker.pthread = null; + }, returnWorkerToPool: function(worker) { + PThread.runWithoutMainThreadQueuedCalls(function() { + delete PThread.pthreads[worker.pthread.threadInfoStruct]; + PThread.unusedWorkers.push(worker); + PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker), 1); + PThread.freeThreadData(worker.pthread); + worker.pthread = void 0; + }); + }, runWithoutMainThreadQueuedCalls: function(func) { + GROWABLE_HEAP_I32()[__emscripten_allow_main_runtime_queued_calls >>> 2] = 0; + try { + func(); + } finally { + GROWABLE_HEAP_I32()[__emscripten_allow_main_runtime_queued_calls >>> 2] = 1; + } + }, receiveObjectTransfer: function(data) { + }, threadInit: function() { + for (var i in PThread.tlsInitFunctions) { + PThread.tlsInitFunctions[i](); + } + }, loadWasmModuleToWorker: function(worker, onFinishedLoading) { + worker.onmessage = function(e) { + var d = e["data"]; + var cmd = d["cmd"]; + if (worker.pthread) + PThread.currentProxiedOperationCallerThread = worker.pthread.threadInfoStruct; + if (d["targetThread"] && d["targetThread"] != _pthread_self()) { + var thread = PThread.pthreads[d.targetThread]; + if (thread) { + thread.worker.postMessage(e.data, d["transferList"]); + } else { + console.error('Internal error! Worker sent a message "' + cmd + '" to target pthread ' + d["targetThread"] + ", but that thread no longer exists!"); + } + PThread.currentProxiedOperationCallerThread = void 0; + return; + } + if (cmd === "processQueuedMainThreadWork") { + _emscripten_main_thread_process_queued_calls(); + } else if (cmd === "spawnThread") { + spawnThread(e.data); + } else if (cmd === "cleanupThread") { + cleanupThread(d["thread"]); + } else if (cmd === "killThread") { + killThread(d["thread"]); + } else if (cmd === "cancelThread") { + cancelThread(d["thread"]); + } else if (cmd === "loaded") { + worker.loaded = true; + if (onFinishedLoading) + onFinishedLoading(worker); + if (worker.runPthread) { + worker.runPthread(); + delete worker.runPthread; + } + } else if (cmd === "print") { + out("Thread " + d["threadId"] + ": " + d["text"]); + } else if (cmd === "printErr") { + err("Thread " + d["threadId"] + ": " + d["text"]); + } else if (cmd === "alert") { + alert("Thread " + d["threadId"] + ": " + d["text"]); + } else if (cmd === "exit") { + var detached = worker.pthread && Atomics.load(GROWABLE_HEAP_U32(), worker.pthread.threadInfoStruct + 64 >> 2); + if (detached) { + PThread.returnWorkerToPool(worker); + } + } else if (cmd === "exitProcess") { + try { + exit(d["returnCode"]); + } catch (e2) { + if (e2 instanceof ExitStatus) + return; + throw e2; + } + } else if (cmd === "cancelDone") { + PThread.returnWorkerToPool(worker); + } else if (cmd === "objectTransfer") { + PThread.receiveObjectTransfer(e.data); + } else if (e.data.target === "setimmediate") { + worker.postMessage(e.data); + } else { + err("worker sent an unknown command " + cmd); + } + PThread.currentProxiedOperationCallerThread = void 0; + }; + worker.onerror = function(e) { + err("pthread sent an error! " + e.filename + ":" + e.lineno + ": " + e.message); + }; + if (ENVIRONMENT_IS_NODE) { + worker.on("message", function(data) { + worker.onmessage({ data }); + }); + worker.on("error", function(data) { + worker.onerror(data); + }); + worker.on("exit", function(data) { + }); + } + worker.postMessage({ "cmd": "load", "urlOrBlob": Module["mainScriptUrlOrBlob"] || _scriptDir, "wasmMemory": wasmMemory, "wasmModule": wasmModule }); + }, allocateUnusedWorker: function() { + var pthreadMainJs = locateFile("web-ifc-mt.worker.js"); + PThread.unusedWorkers.push(new Worker(pthreadMainJs)); + }, getNewWorker: function() { + if (PThread.unusedWorkers.length == 0) { + PThread.allocateUnusedWorker(); + PThread.loadWasmModuleToWorker(PThread.unusedWorkers[0]); + } + return PThread.unusedWorkers.pop(); + }, busySpinWait: function(msecs) { + var t = performance.now() + msecs; + while (performance.now() < t) { + } + } }; + function establishStackSpace(stackTop, stackMax) { + _emscripten_stack_set_limits(stackTop, stackMax); + stackRestore(stackTop); + } + Module["establishStackSpace"] = establishStackSpace; + function invokeEntryPoint(ptr, arg) { + return wasmTable.get(ptr)(arg); + } + Module["invokeEntryPoint"] = invokeEntryPoint; function ___assert_fail(condition, filename, line, func) { abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function"]); } - var ExceptionInfoAttrs = { DESTRUCTOR_OFFSET: 0, REFCOUNT_OFFSET: 4, TYPE_OFFSET: 8, CAUGHT_OFFSET: 12, RETHROWN_OFFSET: 13, SIZE: 16 }; + var _emscripten_get_now; + if (ENVIRONMENT_IS_NODE) { + _emscripten_get_now = function() { + var t = process["hrtime"](); + return t[0] * 1e3 + t[1] / 1e6; + }; + } else if (ENVIRONMENT_IS_PTHREAD) { + _emscripten_get_now = function() { + return performance.now() - Module["__performance_now_clock_drift"]; + }; + } else + _emscripten_get_now = function() { + return performance.now(); + }; + var _emscripten_get_now_is_monotonic = true; + function setErrNo(value) { + GROWABLE_HEAP_I32()[___errno_location() >>> 2] = value; + return value; + } + function _clock_gettime(clk_id, tp) { + var now; + if (clk_id === 0) { + now = Date.now(); + } else if ((clk_id === 1 || clk_id === 4) && _emscripten_get_now_is_monotonic) { + now = _emscripten_get_now(); + } else { + setErrNo(28); + return -1; + } + GROWABLE_HEAP_I32()[tp >>> 2] = now / 1e3 | 0; + GROWABLE_HEAP_I32()[tp + 4 >>> 2] = now % 1e3 * 1e3 * 1e3 | 0; + return 0; + } function ___cxa_allocate_exception(size) { - return _malloc(size + ExceptionInfoAttrs.SIZE) + ExceptionInfoAttrs.SIZE; + return _malloc(size + 16) + 16; + } + function _atexit(func, arg) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(1, 1, func, arg); + } + function ___cxa_thread_atexit(routine, arg) { + PThread.threadExitHandlers.push(function() { + wasmTable.get(routine)(arg); + }); } function ExceptionInfo(excPtr) { this.excPtr = excPtr; - this.ptr = excPtr - ExceptionInfoAttrs.SIZE; + this.ptr = excPtr - 16; this.set_type = function(type) { - HEAP32[this.ptr + ExceptionInfoAttrs.TYPE_OFFSET >>> 2] = type; + GROWABLE_HEAP_I32()[this.ptr + 4 >>> 2] = type; }; this.get_type = function() { - return HEAP32[this.ptr + ExceptionInfoAttrs.TYPE_OFFSET >>> 2]; + return GROWABLE_HEAP_I32()[this.ptr + 4 >>> 2]; }; this.set_destructor = function(destructor) { - HEAP32[this.ptr + ExceptionInfoAttrs.DESTRUCTOR_OFFSET >>> 2] = destructor; + GROWABLE_HEAP_I32()[this.ptr + 8 >>> 2] = destructor; }; this.get_destructor = function() { - return HEAP32[this.ptr + ExceptionInfoAttrs.DESTRUCTOR_OFFSET >>> 2]; + return GROWABLE_HEAP_I32()[this.ptr + 8 >>> 2]; }; this.set_refcount = function(refcount) { - HEAP32[this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >>> 2] = refcount; + GROWABLE_HEAP_I32()[this.ptr >>> 2] = refcount; }; this.set_caught = function(caught) { caught = caught ? 1 : 0; - HEAP8[this.ptr + ExceptionInfoAttrs.CAUGHT_OFFSET >>> 0] = caught; + GROWABLE_HEAP_I8()[this.ptr + 12 >>> 0] = caught; }; this.get_caught = function() { - return HEAP8[this.ptr + ExceptionInfoAttrs.CAUGHT_OFFSET >>> 0] != 0; + return GROWABLE_HEAP_I8()[this.ptr + 12 >>> 0] != 0; }; this.set_rethrown = function(rethrown) { rethrown = rethrown ? 1 : 0; - HEAP8[this.ptr + ExceptionInfoAttrs.RETHROWN_OFFSET >>> 0] = rethrown; + GROWABLE_HEAP_I8()[this.ptr + 13 >>> 0] = rethrown; }; this.get_rethrown = function() { - return HEAP8[this.ptr + ExceptionInfoAttrs.RETHROWN_OFFSET >>> 0] != 0; + return GROWABLE_HEAP_I8()[this.ptr + 13 >>> 0] != 0; }; this.init = function(type, destructor) { this.set_type(type); @@ -112708,12 +119441,10 @@ var require_web_ifc = __commonJS({ this.set_rethrown(false); }; this.add_ref = function() { - var value = HEAP32[this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >>> 2]; - HEAP32[this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >>> 2] = value + 1; + Atomics.add(GROWABLE_HEAP_I32(), this.ptr + 0 >> 2, 1); }; this.release_ref = function() { - var prev = HEAP32[this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >>> 2]; - HEAP32[this.ptr + ExceptionInfoAttrs.REFCOUNT_OFFSET >>> 2] = prev - 1; + var prev = Atomics.sub(GROWABLE_HEAP_I32(), this.ptr + 0 >> 2, 1); return prev === 1; }; } @@ -112914,12 +119645,12 @@ var require_web_ifc = __commonJS({ var result = null; if (ENVIRONMENT_IS_NODE) { var BUFSIZE = 256; - var buf = Buffer.alloc ? Buffer.alloc(BUFSIZE) : new Buffer(BUFSIZE); + var buf = Buffer.alloc(BUFSIZE); var bytesRead = 0; try { bytesRead = nodeFS.readSync(process.stdin.fd, buf, 0, BUFSIZE, null); } catch (e) { - if (e.toString().indexOf("EOF") != -1) + if (e.toString().includes("EOF")) bytesRead = 0; else throw e; @@ -112973,11 +119704,15 @@ var require_web_ifc = __commonJS({ tty.output = []; } } } }; + function zeroMemory(address, size) { + GROWABLE_HEAP_U8().fill(0, address, address + size); + } function mmapAlloc(size) { - var alignedSize = alignMemory(size, 16384); - var ptr = _malloc(alignedSize); - while (size < alignedSize) - HEAP8[ptr + size++ >>> 0] = 0; + size = alignMemory(size, 65536); + var ptr = _memalign(65536, size); + if (!ptr) + return 0; + zeroMemory(ptr, size); return ptr; } var MEMFS = { ops_table: null, mount: function(mount) { @@ -113009,16 +119744,9 @@ var require_web_ifc = __commonJS({ node.timestamp = Date.now(); if (parent) { parent.contents[name2] = node; + parent.timestamp = node.timestamp; } return node; - }, getFileDataAsRegularArray: function(node) { - if (node.contents && node.contents.subarray) { - var arr = []; - for (var i = 0; i < node.usedBytes; ++i) - arr.push(node.contents[i]); - return arr; - } - return node.contents; }, getFileDataAsTypedArray: function(node) { if (!node.contents) return new Uint8Array(0); @@ -113038,7 +119766,6 @@ var require_web_ifc = __commonJS({ node.contents = new Uint8Array(newCapacity); if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); - return; }, resizeFileStorage: function(node, newSize) { newSize >>>= 0; if (node.usedBytes == newSize) @@ -113046,25 +119773,14 @@ var require_web_ifc = __commonJS({ if (newSize == 0) { node.contents = null; node.usedBytes = 0; - return; - } - if (!node.contents || node.contents.subarray) { + } else { var oldContents = node.contents; node.contents = new Uint8Array(newSize); if (oldContents) { node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); } node.usedBytes = newSize; - return; } - if (!node.contents) - node.contents = []; - if (node.contents.length > newSize) - node.contents.length = newSize; - else - while (node.contents.length < newSize) - node.contents.push(0); - node.usedBytes = newSize; }, node_ops: { getattr: function(node) { var attr = {}; attr.dev = FS.isChrdev(node.mode) ? node.id : 1; @@ -113117,17 +119833,21 @@ var require_web_ifc = __commonJS({ } } delete old_node.parent.contents[old_node.name]; + old_node.parent.timestamp = Date.now(); old_node.name = new_name; new_dir.contents[new_name] = old_node; + new_dir.timestamp = old_node.parent.timestamp; old_node.parent = new_dir; }, unlink: function(parent, name2) { delete parent.contents[name2]; + parent.timestamp = Date.now(); }, rmdir: function(parent, name2) { var node = FS.lookupNode(parent, name2); for (var i in node.contents) { throw new FS.ErrnoError(55); } delete parent.contents[name2]; + parent.timestamp = Date.now(); }, readdir: function(node) { var entries = [".", ".."]; for (var key2 in node.contents) { @@ -113159,7 +119879,7 @@ var require_web_ifc = __commonJS({ } return size; }, write: function(stream, buffer2, offset, length, position, canOwn) { - if (buffer2.buffer === HEAP8.buffer) { + if (buffer2.buffer === GROWABLE_HEAP_I8().buffer) { canOwn = false; } if (!length) @@ -113207,7 +119927,9 @@ var require_web_ifc = __commonJS({ MEMFS.expandFileStorage(stream.node, offset + length); stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); }, mmap: function(stream, address, length, position, prot, flags) { - assert(address === 0); + if (address !== 0) { + throw new FS.ErrnoError(28); + } if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError(43); } @@ -113231,7 +119953,7 @@ var require_web_ifc = __commonJS({ throw new FS.ErrnoError(48); } ptr >>>= 0; - HEAP8.set(contents, ptr >>> 0); + GROWABLE_HEAP_I8().set(contents, ptr >>> 0); } return { ptr, allocated }; }, msync: function(stream, buffer2, offset, length, mmapFlags) { @@ -113244,6 +119966,23 @@ var require_web_ifc = __commonJS({ MEMFS.stream_ops.write(stream, buffer2, 0, length, offset, false); return 0; } } }; + function asyncLoad(url, onload, onerror, noRunDep) { + var dep = !noRunDep ? getUniqueRunDependency("al " + url) : ""; + readAsync(url, function(arrayBuffer) { + assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).'); + onload(new Uint8Array(arrayBuffer)); + if (dep) + removeRunDependency(); + }, function(event) { + if (onerror) { + onerror(); + } else { + throw 'Loading data file "' + url + '" failed.'; + } + }); + if (dep) + addRunDependency(); + } var FS = { root: null, mounts: [], devices: {}, streams: [], nextInode: 1, nameTable: null, currentPath: "/", initialized: false, ignorePermissions: true, trackingDelegate: {}, tracking: { openFlags: { READ: 1, WRITE: 2 } }, ErrnoError: null, genericErrors: {}, filesystems: null, syncFSRequests: 0, lookupPath: function(path, opts) { path = PATH_FS.resolve(FS.cwd(), path); opts = opts || {}; @@ -113378,11 +120117,11 @@ var require_web_ifc = __commonJS({ if (FS.ignorePermissions) { return 0; } - if (perms.indexOf("r") !== -1 && !(node.mode & 292)) { + if (perms.includes("r") && !(node.mode & 292)) { return 2; - } else if (perms.indexOf("w") !== -1 && !(node.mode & 146)) { + } else if (perms.includes("w") && !(node.mode & 146)) { return 2; - } else if (perms.indexOf("x") !== -1 && !(node.mode & 73)) { + } else if (perms.includes("x") && !(node.mode & 73)) { return 2; } return 0; @@ -113576,7 +120315,7 @@ var require_web_ifc = __commonJS({ var current = FS.nameTable[hash]; while (current) { var next = current.name_next; - if (mounts.indexOf(current.mount) !== -1) { + if (mounts.includes(current.mount)) { FS.destroyNode(current); } current = next; @@ -114179,10 +120918,10 @@ var require_web_ifc = __commonJS({ FS.mkdir("/dev/shm/tmp"); }, createSpecialDirectories: function() { FS.mkdir("/proc"); - FS.mkdir("/proc/self"); + var proc_self = FS.mkdir("/proc/self"); FS.mkdir("/proc/self/fd"); FS.mount({ mount: function() { - var node = FS.createNode("/proc/self", "fd", 16384 | 511, 73); + var node = FS.createNode(proc_self, "fd", 16384 | 511, 73); node.node_ops = { lookup: function(parent, name2) { var fd = +name2; var stream = FS.getStream(fd); @@ -114558,7 +121297,7 @@ var require_web_ifc = __commonJS({ } addRunDependency(); if (typeof url == "string") { - Browser.asyncLoad(url, function(byteArray) { + asyncLoad(url, function(byteArray) { processData(byteArray); }, onerror); } else { @@ -114660,20 +121399,26 @@ var require_web_ifc = __commonJS({ }; openRequest.onerror = onerror; } }; - var SYSCALLS = { mappings: {}, DEFAULT_POLLMASK: 5, umask: 511, calculateAt: function(dirfd, path) { - if (path[0] !== "/") { - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = FS.getStream(dirfd); - if (!dirstream) - throw new FS.ErrnoError(8); - dir = dirstream.path; + var SYSCALLS = { mappings: {}, DEFAULT_POLLMASK: 5, umask: 511, calculateAt: function(dirfd, path, allowEmpty) { + if (path[0] === "/") { + return path; + } + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = FS.getStream(dirfd); + if (!dirstream) + throw new FS.ErrnoError(8); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44); } - path = PATH.join2(dir, path); + return dir; } - return path; + return PATH.join2(dir, path); }, doStat: function(func, path, buf) { try { var stat = func(path); @@ -114683,28 +121428,28 @@ var require_web_ifc = __commonJS({ } throw e; } - HEAP32[buf >>> 2] = stat.dev; - HEAP32[buf + 4 >>> 2] = 0; - HEAP32[buf + 8 >>> 2] = stat.ino; - HEAP32[buf + 12 >>> 2] = stat.mode; - HEAP32[buf + 16 >>> 2] = stat.nlink; - HEAP32[buf + 20 >>> 2] = stat.uid; - HEAP32[buf + 24 >>> 2] = stat.gid; - HEAP32[buf + 28 >>> 2] = stat.rdev; - HEAP32[buf + 32 >>> 2] = 0; - tempI64 = [stat.size >>> 0, (tempDouble = stat.size, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], HEAP32[buf + 40 >>> 2] = tempI64[0], HEAP32[buf + 44 >>> 2] = tempI64[1]; - HEAP32[buf + 48 >>> 2] = 4096; - HEAP32[buf + 52 >>> 2] = stat.blocks; - HEAP32[buf + 56 >>> 2] = stat.atime.getTime() / 1e3 | 0; - HEAP32[buf + 60 >>> 2] = 0; - HEAP32[buf + 64 >>> 2] = stat.mtime.getTime() / 1e3 | 0; - HEAP32[buf + 68 >>> 2] = 0; - HEAP32[buf + 72 >>> 2] = stat.ctime.getTime() / 1e3 | 0; - HEAP32[buf + 76 >>> 2] = 0; - tempI64 = [stat.ino >>> 0, (tempDouble = stat.ino, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], HEAP32[buf + 80 >>> 2] = tempI64[0], HEAP32[buf + 84 >>> 2] = tempI64[1]; + GROWABLE_HEAP_I32()[buf >>> 2] = stat.dev; + GROWABLE_HEAP_I32()[buf + 4 >>> 2] = 0; + GROWABLE_HEAP_I32()[buf + 8 >>> 2] = stat.ino; + GROWABLE_HEAP_I32()[buf + 12 >>> 2] = stat.mode; + GROWABLE_HEAP_I32()[buf + 16 >>> 2] = stat.nlink; + GROWABLE_HEAP_I32()[buf + 20 >>> 2] = stat.uid; + GROWABLE_HEAP_I32()[buf + 24 >>> 2] = stat.gid; + GROWABLE_HEAP_I32()[buf + 28 >>> 2] = stat.rdev; + GROWABLE_HEAP_I32()[buf + 32 >>> 2] = 0; + tempI64 = [stat.size >>> 0, (tempDouble = stat.size, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf + 40 >>> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 44 >>> 2] = tempI64[1]; + GROWABLE_HEAP_I32()[buf + 48 >>> 2] = 4096; + GROWABLE_HEAP_I32()[buf + 52 >>> 2] = stat.blocks; + GROWABLE_HEAP_I32()[buf + 56 >>> 2] = stat.atime.getTime() / 1e3 | 0; + GROWABLE_HEAP_I32()[buf + 60 >>> 2] = 0; + GROWABLE_HEAP_I32()[buf + 64 >>> 2] = stat.mtime.getTime() / 1e3 | 0; + GROWABLE_HEAP_I32()[buf + 68 >>> 2] = 0; + GROWABLE_HEAP_I32()[buf + 72 >>> 2] = stat.ctime.getTime() / 1e3 | 0; + GROWABLE_HEAP_I32()[buf + 76 >>> 2] = 0; + tempI64 = [stat.ino >>> 0, (tempDouble = stat.ino, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[buf + 80 >>> 2] = tempI64[0], GROWABLE_HEAP_I32()[buf + 84 >>> 2] = tempI64[1]; return 0; }, doMsync: function(addr, stream, len, flags, offset) { - var buffer2 = HEAPU8.slice(addr, addr + len); + var buffer2 = GROWABLE_HEAP_U8().slice(addr, addr + len); FS.msync(stream, buffer2, offset, len, flags); }, doMkdir: function(path, mode) { path = PATH.normalize(path); @@ -114730,9 +121475,9 @@ var require_web_ifc = __commonJS({ return -28; var ret = FS.readlink(path); var len = Math.min(bufsize, lengthBytesUTF8(ret)); - var endChar = HEAP8[buf + len >>> 0]; + var endChar = GROWABLE_HEAP_I8()[buf + len >>> 0]; stringToUTF8(ret, buf, bufsize + 1); - HEAP8[buf + len >>> 0] = endChar; + GROWABLE_HEAP_I8()[buf + len >>> 0] = endChar; return len; }, doAccess: function(path, amode) { if (amode & ~7) { @@ -114763,9 +121508,9 @@ var require_web_ifc = __commonJS({ }, doReadv: function(stream, iov, iovcnt, offset) { var ret = 0; for (var i = 0; i < iovcnt; i++) { - var ptr = HEAP32[iov + i * 8 >>> 2]; - var len = HEAP32[iov + (i * 8 + 4) >>> 2]; - var curr = FS.read(stream, HEAP8, ptr, len, offset); + var ptr = GROWABLE_HEAP_I32()[iov + i * 8 >>> 2]; + var len = GROWABLE_HEAP_I32()[iov + (i * 8 + 4) >>> 2]; + var curr = FS.read(stream, GROWABLE_HEAP_I8(), ptr, len, offset); if (curr < 0) return -1; ret += curr; @@ -114776,9 +121521,9 @@ var require_web_ifc = __commonJS({ }, doWritev: function(stream, iov, iovcnt, offset) { var ret = 0; for (var i = 0; i < iovcnt; i++) { - var ptr = HEAP32[iov + i * 8 >>> 2]; - var len = HEAP32[iov + (i * 8 + 4) >>> 2]; - var curr = FS.write(stream, HEAP8, ptr, len, offset); + var ptr = GROWABLE_HEAP_I32()[iov + i * 8 >>> 2]; + var len = GROWABLE_HEAP_I32()[iov + (i * 8 + 4) >>> 2]; + var curr = FS.write(stream, GROWABLE_HEAP_I8(), ptr, len, offset); if (curr < 0) return -1; ret += curr; @@ -114786,7 +121531,7 @@ var require_web_ifc = __commonJS({ return ret; }, varargs: void 0, get: function() { SYSCALLS.varargs += 4; - var ret = HEAP32[SYSCALLS.varargs - 4 >>> 2]; + var ret = GROWABLE_HEAP_I32()[SYSCALLS.varargs - 4 >>> 2]; return ret; }, getStr: function(ptr) { var ret = UTF8ToString(ptr); @@ -114799,7 +121544,60 @@ var require_web_ifc = __commonJS({ }, get64: function(low, high) { return low; } }; + function ___sys_fcntl64(fd, cmd, varargs) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(2, 1, fd, cmd, varargs); + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: { + var arg = SYSCALLS.get(); + if (arg < 0) { + return -28; + } + var newStream; + newStream = FS.open(stream.path, stream.flags, 0, arg); + return newStream.fd; + } + case 1: + case 2: + return 0; + case 3: + return stream.flags; + case 4: { + var arg = SYSCALLS.get(); + stream.flags |= arg; + return 0; + } + case 12: { + var arg = SYSCALLS.get(); + var offset = 0; + GROWABLE_HEAP_I16()[arg + offset >>> 1] = 2; + return 0; + } + case 13: + case 14: + return 0; + case 16: + case 8: + return -28; + case 9: + setErrNo(28); + return -1; + default: { + return -28; + } + } + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return -e.errno; + } + } function ___sys_ioctl(fd, op, varargs) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(3, 1, fd, op, varargs); SYSCALLS.varargs = varargs; try { var stream = SYSCALLS.getStreamFromFD(fd); @@ -114824,7 +121622,7 @@ var require_web_ifc = __commonJS({ if (!stream.tty) return -59; var argp = SYSCALLS.get(); - HEAP32[argp >>> 2] = 0; + GROWABLE_HEAP_I32()[argp >>> 2] = 0; return 0; } case 21520: { @@ -114856,10 +121654,12 @@ var require_web_ifc = __commonJS({ } } function ___sys_open(path, flags, varargs) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(4, 1, path, flags, varargs); SYSCALLS.varargs = varargs; try { var pathname = SYSCALLS.getStr(path); - var mode = SYSCALLS.get(); + var mode = varargs ? SYSCALLS.get() : 0; var stream = FS.open(pathname, flags, mode); return stream.fd; } catch (e) { @@ -114877,7 +121677,7 @@ var require_web_ifc = __commonJS({ } } function simpleReadValueFromPointer(pointer) { - return this["fromWireType"](HEAPU32[pointer >>> 2]); + return this["fromWireType"](GROWABLE_HEAP_U32()[pointer >>> 2]); } var awaitingDependencies = {}; var registeredTypes = {}; @@ -115066,6 +121866,8 @@ var require_web_ifc = __commonJS({ }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: rawDestructor }]; }); } + function __embind_register_bigint(primitiveType, name2, size, minRange, maxRange) { + } function getShiftFromSize(size) { switch (size) { case 1: @@ -115091,8 +121893,8 @@ var require_web_ifc = __commonJS({ function readLatin1String(ptr) { var ret = ""; var c = ptr; - while (HEAPU8[c >>> 0]) { - ret += embind_charCodes[HEAPU8[c++ >>> 0]]; + while (GROWABLE_HEAP_U8()[c >>> 0]) { + ret += embind_charCodes[GROWABLE_HEAP_U8()[c++ >>> 0]]; } return ret; } @@ -115136,11 +121938,11 @@ var require_web_ifc = __commonJS({ }, "argPackAdvance": 8, "readValueFromPointer": function(pointer) { var heap; if (size === 1) { - heap = HEAP8; + heap = GROWABLE_HEAP_I8(); } else if (size === 2) { - heap = HEAP16; + heap = GROWABLE_HEAP_I16(); } else if (size === 4) { - heap = HEAP32; + heap = GROWABLE_HEAP_I32(); } else { throw new TypeError("Unknown boolean type size: " + name2); } @@ -115602,8 +122404,17 @@ var require_web_ifc = __commonJS({ Module[name2].argCount = numArguments; } } + function dynCallLegacy(sig, ptr, args) { + var f = Module["dynCall_" + sig]; + return args && args.length ? f.apply(null, [ptr].concat(args)) : f.call(null, ptr); + } + function dynCall(sig, ptr, args) { + if (sig.includes("j")) { + return dynCallLegacy(sig, ptr, args); + } + return wasmTable.get(ptr).apply(null, args); + } function getDynCaller(sig, ptr) { - assert(sig.indexOf("j") >= 0, "getDynCaller should only be called with i64 sigs"); var argCache = []; return function() { argCache.length = arguments.length; @@ -115616,7 +122427,7 @@ var require_web_ifc = __commonJS({ function embind__requireFunction(signature, rawFunction) { signature = readLatin1String(signature); function makeDynCaller() { - if (signature.indexOf("j") != -1) { + if (signature.includes("j")) { return getDynCaller(signature, rawFunction); } return wasmTable.get(rawFunction); @@ -115705,7 +122516,7 @@ var require_web_ifc = __commonJS({ function heap32VectorToArray(count, firstElement) { var array = []; for (var i = 0; i < count; i++) { - array.push(HEAP32[(firstElement >> 2) + i >>> 0]); + array.push(GROWABLE_HEAP_I32()[(firstElement >> 2) + i >>> 0]); } return array; } @@ -115823,6 +122634,9 @@ var require_web_ifc = __commonJS({ whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; var humanName = classType.name + "." + methodName; + if (methodName.startsWith("@@")) { + methodName = Symbol[methodName.substring(2)]; + } if (isPureVirtual) { classType.registeredClass.pureVirtualFunctions.push(methodName); } @@ -115916,17 +122730,17 @@ var require_web_ifc = __commonJS({ switch (shift) { case 0: return function(pointer) { - var heap = signed ? HEAP8 : HEAPU8; + var heap = signed ? GROWABLE_HEAP_I8() : GROWABLE_HEAP_U8(); return this["fromWireType"](heap[pointer >>> 0]); }; case 1: return function(pointer) { - var heap = signed ? HEAP16 : HEAPU16; + var heap = signed ? GROWABLE_HEAP_I16() : GROWABLE_HEAP_U16(); return this["fromWireType"](heap[pointer >>> 1]); }; case 2: return function(pointer) { - var heap = signed ? HEAP32 : HEAPU32; + var heap = signed ? GROWABLE_HEAP_I32() : GROWABLE_HEAP_U32(); return this["fromWireType"](heap[pointer >>> 2]); }; default: @@ -115977,11 +122791,11 @@ var require_web_ifc = __commonJS({ switch (shift) { case 2: return function(pointer) { - return this["fromWireType"](HEAPF32[pointer >>> 2]); + return this["fromWireType"](GROWABLE_HEAP_F32()[pointer >>> 2]); }; case 3: return function(pointer) { - return this["fromWireType"](HEAPF64[pointer >>> 3]); + return this["fromWireType"](GROWABLE_HEAP_F64()[pointer >>> 3]); }; default: throw new TypeError("Unknown float type: " + name2); @@ -116016,21 +122830,21 @@ var require_web_ifc = __commonJS({ switch (shift) { case 0: return signed ? function readS8FromPointer(pointer) { - return HEAP8[pointer >>> 0]; + return GROWABLE_HEAP_I8()[pointer >>> 0]; } : function readU8FromPointer(pointer) { - return HEAPU8[pointer >>> 0]; + return GROWABLE_HEAP_U8()[pointer >>> 0]; }; case 1: return signed ? function readS16FromPointer(pointer) { - return HEAP16[pointer >>> 1]; + return GROWABLE_HEAP_I16()[pointer >>> 1]; } : function readU16FromPointer(pointer) { - return HEAPU16[pointer >>> 1]; + return GROWABLE_HEAP_U16()[pointer >>> 1]; }; case 2: return signed ? function readS32FromPointer(pointer) { - return HEAP32[pointer >>> 2]; + return GROWABLE_HEAP_I32()[pointer >>> 2]; } : function readU32FromPointer(pointer) { - return HEAPU32[pointer >>> 2]; + return GROWABLE_HEAP_U32()[pointer >>> 2]; }; default: throw new TypeError("Unknown integer type: " + name2); @@ -116051,7 +122865,7 @@ var require_web_ifc = __commonJS({ return value << bitshift >>> bitshift; }; } - var isUnsignedType = name2.indexOf("unsigned") != -1; + var isUnsignedType = name2.includes("unsigned"); registerType(primitiveType, { name: name2, "fromWireType": fromWireType, "toWireType": function(destructors, value) { if (typeof value !== "number" && typeof value !== "boolean") { throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); @@ -116067,7 +122881,7 @@ var require_web_ifc = __commonJS({ var TA = typeMapping[dataTypeIndex]; function decodeMemoryView(handle) { handle = handle >> 2; - var heap = HEAPU32; + var heap = GROWABLE_HEAP_U32(); var size = heap[handle >>> 0]; var data = heap[handle + 1 >>> 0]; return new TA(buffer, data, size); @@ -116079,13 +122893,13 @@ var require_web_ifc = __commonJS({ name2 = readLatin1String(name2); var stdStringIsUTF8 = name2 === "std::string"; registerType(rawType, { name: name2, "fromWireType": function(value) { - var length = HEAPU32[value >>> 2]; + var length = GROWABLE_HEAP_U32()[value >>> 2]; var str; if (stdStringIsUTF8) { var decodeStartPtr = value + 4; for (var i = 0; i <= length; ++i) { var currentBytePtr = value + 4 + i; - if (i == length || HEAPU8[currentBytePtr >>> 0] == 0) { + if (i == length || GROWABLE_HEAP_U8()[currentBytePtr >>> 0] == 0) { var maxRead = currentBytePtr - decodeStartPtr; var stringSegment = UTF8ToString(decodeStartPtr, maxRead); if (str === void 0) { @@ -116100,7 +122914,7 @@ var require_web_ifc = __commonJS({ } else { var a = new Array(length); for (var i = 0; i < length; ++i) { - a[i] = String.fromCharCode(HEAPU8[value + 4 + i >>> 0]); + a[i] = String.fromCharCode(GROWABLE_HEAP_U8()[value + 4 + i >>> 0]); } str = a.join(""); } @@ -116127,7 +122941,7 @@ var require_web_ifc = __commonJS({ var length = getLength(); var ptr = _malloc(4 + length + 1); ptr >>>= 0; - HEAPU32[ptr >>> 2] = length; + GROWABLE_HEAP_U32()[ptr >>> 2] = length; if (stdStringIsUTF8 && valueIsOfTypeString) { stringToUTF8(value, ptr + 4, length + 1); } else { @@ -116138,11 +122952,11 @@ var require_web_ifc = __commonJS({ _free(ptr); throwBindingError("String has UTF-16 code units that do not fit in 8 bits"); } - HEAPU8[ptr + 4 + i >>> 0] = charCode; + GROWABLE_HEAP_U8()[ptr + 4 + i >>> 0] = charCode; } } else { for (var i = 0; i < length; ++i) { - HEAPU8[ptr + 4 + i >>> 0] = value[i]; + GROWABLE_HEAP_U8()[ptr + 4 + i >>> 0] = value[i]; } } } @@ -116162,7 +122976,7 @@ var require_web_ifc = __commonJS({ encodeString = stringToUTF16; lengthBytesUTF = lengthBytesUTF16; getHeap = function() { - return HEAPU16; + return GROWABLE_HEAP_U16(); }; shift = 1; } else if (charSize === 4) { @@ -116170,12 +122984,12 @@ var require_web_ifc = __commonJS({ encodeString = stringToUTF32; lengthBytesUTF = lengthBytesUTF32; getHeap = function() { - return HEAPU32; + return GROWABLE_HEAP_U32(); }; shift = 2; } registerType(rawType, { name: name2, "fromWireType": function(value) { - var length = HEAPU32[value >>> 2]; + var length = GROWABLE_HEAP_U32()[value >>> 2]; var HEAP = getHeap(); var str; var decodeStartPtr = value + 4; @@ -116202,7 +123016,7 @@ var require_web_ifc = __commonJS({ var length = lengthBytesUTF(value); var ptr = _malloc(4 + length + charSize); ptr >>>= 0; - HEAPU32[ptr >>> 2] = length >> shift; + GROWABLE_HEAP_U32()[ptr >>> 2] = length >> shift; encodeString(value, ptr + 4, length + charSize); if (destructors !== null) { destructors.push(_free, ptr); @@ -116232,6 +123046,21 @@ var require_web_ifc = __commonJS({ return void 0; } }); } + function __emscripten_notify_thread_queue(targetThreadId, mainThreadId) { + if (targetThreadId == mainThreadId) { + postMessage({ "cmd": "processQueuedMainThreadWork" }); + } else if (ENVIRONMENT_IS_PTHREAD) { + postMessage({ "targetThread": targetThreadId, "cmd": "processThreadQueue" }); + } else { + var pthread = PThread.pthreads[targetThreadId]; + var worker = pthread && pthread.worker; + if (!worker) { + return; + } + worker.postMessage({ "cmd": "processThreadQueue" }); + } + return 1; + } function requireHandle(handle) { if (!handle) { throwBindingError("Cannot use deleted val. handle = " + handle); @@ -116243,13 +123072,13 @@ var require_web_ifc = __commonJS({ returnType = requireRegisteredType(returnType, "emval::as"); var destructors = []; var rd = __emval_register(destructors); - HEAP32[destructorsRef >>> 2] = rd; + GROWABLE_HEAP_I32()[destructorsRef >>> 2] = rd; return returnType["toWireType"](destructors, handle); } function __emval_lookupTypes(argCount, argTypes) { var a = new Array(argCount); for (var i = 0; i < argCount; ++i) { - a[i] = requireRegisteredType(HEAP32[(argTypes >> 2) + i >>> 0], "parameter " + i); + a[i] = requireRegisteredType(GROWABLE_HEAP_I32()[(argTypes >> 2) + i >>> 0], "parameter " + i); } return a; } @@ -116337,42 +123166,98 @@ var require_web_ifc = __commonJS({ function _abort() { abort(); } - var _emscripten_get_now; - if (ENVIRONMENT_IS_NODE) { - _emscripten_get_now = function() { - var t = process["hrtime"](); - return t[0] * 1e3 + t[1] / 1e6; - }; - } else if (typeof dateNow !== "undefined") { - _emscripten_get_now = dateNow; - } else - _emscripten_get_now = function() { - return performance.now(); - }; - var _emscripten_get_now_is_monotonic = true; - function setErrNo(value) { - HEAP32[___errno_location() >>> 2] = value; - return value; + var readAsmConstArgsArray = []; + function readAsmConstArgs(sigPtr, buf) { + readAsmConstArgsArray.length = 0; + var ch; + buf >>= 2; + while (ch = GROWABLE_HEAP_U8()[sigPtr++ >>> 0]) { + var double = ch < 105; + if (double && buf & 1) + buf++; + readAsmConstArgsArray.push(double ? GROWABLE_HEAP_F64()[buf++ >>> 1] : GROWABLE_HEAP_I32()[buf >>> 0]); + ++buf; + } + return readAsmConstArgsArray; } - function _clock_gettime(clk_id, tp) { - var now; - if (clk_id === 0) { - now = Date.now(); - } else if ((clk_id === 1 || clk_id === 4) && _emscripten_get_now_is_monotonic) { - now = _emscripten_get_now(); + function _emscripten_asm_const_int(code, sigPtr, argbuf) { + var args = readAsmConstArgs(sigPtr, argbuf); + return ASM_CONSTS[code].apply(null, args); + } + function _emscripten_check_blocking_allowed() { + if (ENVIRONMENT_IS_NODE) + return; + if (ENVIRONMENT_IS_WORKER) + return; + warnOnce("Blocking on the main thread is very dangerous, see https://emscripten.org/docs/porting/pthreads.html#blocking-on-the-main-browser-thread"); + } + function _emscripten_conditional_set_current_thread_status(expectedStatus, newStatus) { + } + function _emscripten_futex_wait(addr, val, timeout) { + if (addr <= 0 || addr > GROWABLE_HEAP_I8().length || addr & true) + return -28; + if (!ENVIRONMENT_IS_WEB) { + var ret = Atomics.wait(GROWABLE_HEAP_I32(), addr >> 2, val, timeout); + if (ret === "timed-out") + return -73; + if (ret === "not-equal") + return -6; + if (ret === "ok") + return 0; + throw "Atomics.wait returned an unexpected value " + ret; } else { - setErrNo(28); - return -1; + if (Atomics.load(GROWABLE_HEAP_I32(), addr >> 2) != val) { + return -6; + } + var tNow = performance.now(); + var tEnd = tNow + timeout; + var lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), __emscripten_main_thread_futex >> 2, addr); + while (1) { + tNow = performance.now(); + if (tNow > tEnd) { + lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), __emscripten_main_thread_futex >> 2, 0); + return -73; + } + lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), __emscripten_main_thread_futex >> 2, 0); + if (lastAddr == 0) { + break; + } + _emscripten_main_thread_process_queued_calls(); + if (Atomics.load(GROWABLE_HEAP_I32(), addr >> 2) != val) { + return -6; + } + lastAddr = Atomics.exchange(GROWABLE_HEAP_I32(), __emscripten_main_thread_futex >> 2, addr); + } + return 0; } - HEAP32[tp >>> 2] = now / 1e3 | 0; - HEAP32[tp + 4 >>> 2] = now % 1e3 * 1e3 * 1e3 | 0; - return 0; } function _emscripten_memcpy_big(dest, src, num) { - HEAPU8.copyWithin(dest >>> 0, src >>> 0, src + num >>> 0); + GROWABLE_HEAP_U8().copyWithin(dest >>> 0, src >>> 0, src + num >>> 0); + } + function _emscripten_proxy_to_main_thread_js(index, sync) { + var numCallArgs = arguments.length - 2; + var stack = stackSave(); + var serializedNumCallArgs = numCallArgs; + var args = stackAlloc(serializedNumCallArgs * 8); + var b = args >> 3; + for (var i = 0; i < numCallArgs; i++) { + var arg = arguments[2 + i]; + GROWABLE_HEAP_F64()[b + i >>> 0] = arg; + } + var ret = _emscripten_run_in_main_runtime_thread_js(index, serializedNumCallArgs, args, sync); + stackRestore(stack); + return ret; } - function _emscripten_get_heap_size() { - return HEAPU8.length; + var _emscripten_receive_on_main_thread_js_callArgs = []; + function _emscripten_receive_on_main_thread_js(index, numCallArgs, args) { + _emscripten_receive_on_main_thread_js_callArgs.length = numCallArgs; + var b = args >> 3; + for (var i = 0; i < numCallArgs; i++) { + _emscripten_receive_on_main_thread_js_callArgs[i] = GROWABLE_HEAP_F64()[b + i >>> 0]; + } + var isEmAsmConst = index < 0; + var func = !isEmAsmConst ? proxiedFunctionTable[index] : ASM_CONSTS[-index - 1]; + return func.apply(null, _emscripten_receive_on_main_thread_js_callArgs); } function emscripten_realloc_buffer(size) { try { @@ -116383,17 +123268,19 @@ var require_web_ifc = __commonJS({ } } function _emscripten_resize_heap(requestedSize) { + var oldSize = GROWABLE_HEAP_U8().length; requestedSize = requestedSize >>> 0; - var oldSize = _emscripten_get_heap_size(); - var maxHeapSize = 4294967296; + if (requestedSize <= oldSize) { + return false; + } + var maxHeapSize = 4294901760; if (requestedSize > maxHeapSize) { return false; } - var minHeapSize = 16777216; for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296); - var newSize = Math.min(maxHeapSize, alignUp(Math.max(minHeapSize, requestedSize, overGrownHeapSize), 65536)); + var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); var replacement = emscripten_realloc_buffer(newSize); if (replacement) { return true; @@ -116401,6 +123288,334 @@ var require_web_ifc = __commonJS({ } return false; } + var JSEvents = { inEventHandler: 0, removeAllEventListeners: function() { + for (var i = JSEvents.eventHandlers.length - 1; i >= 0; --i) { + JSEvents._removeHandler(i); + } + JSEvents.eventHandlers = []; + JSEvents.deferredCalls = []; + }, registerRemoveEventListeners: function() { + if (!JSEvents.removeEventListenersRegistered) { + JSEvents.removeEventListenersRegistered = true; + } + }, deferredCalls: [], deferCall: function(targetFunction, precedence, argsList) { + function arraysHaveEqualContent(arrA, arrB) { + if (arrA.length != arrB.length) + return false; + for (var i2 in arrA) { + if (arrA[i2] != arrB[i2]) + return false; + } + return true; + } + for (var i in JSEvents.deferredCalls) { + var call = JSEvents.deferredCalls[i]; + if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { + return; + } + } + JSEvents.deferredCalls.push({ targetFunction, precedence, argsList }); + JSEvents.deferredCalls.sort(function(x, y) { + return x.precedence < y.precedence; + }); + }, removeDeferredCalls: function(targetFunction) { + for (var i = 0; i < JSEvents.deferredCalls.length; ++i) { + if (JSEvents.deferredCalls[i].targetFunction == targetFunction) { + JSEvents.deferredCalls.splice(i, 1); + --i; + } + } + }, canPerformEventHandlerRequests: function() { + return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; + }, runDeferredCalls: function() { + if (!JSEvents.canPerformEventHandlerRequests()) { + return; + } + for (var i = 0; i < JSEvents.deferredCalls.length; ++i) { + var call = JSEvents.deferredCalls[i]; + JSEvents.deferredCalls.splice(i, 1); + --i; + call.targetFunction.apply(null, call.argsList); + } + }, eventHandlers: [], removeAllHandlersOnTarget: function(target, eventTypeString) { + for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == target && (!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) { + JSEvents._removeHandler(i--); + } + } + }, _removeHandler: function(i) { + var h = JSEvents.eventHandlers[i]; + h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture); + JSEvents.eventHandlers.splice(i, 1); + }, registerOrRemoveHandler: function(eventHandler) { + var jsEventHandler = function jsEventHandler2(event) { + ++JSEvents.inEventHandler; + JSEvents.currentEventHandler = eventHandler; + JSEvents.runDeferredCalls(); + eventHandler.handlerFunc(event); + JSEvents.runDeferredCalls(); + --JSEvents.inEventHandler; + }; + if (eventHandler.callbackfunc) { + eventHandler.eventListenerFunc = jsEventHandler; + eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture); + JSEvents.eventHandlers.push(eventHandler); + JSEvents.registerRemoveEventListeners(); + } else { + for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == eventHandler.target && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { + JSEvents._removeHandler(i--); + } + } + } + }, queueEventHandlerOnThread_iiii: function(targetThread, eventHandlerFunc, eventTypeId, eventData, userData) { + var stackTop = stackSave(); + var varargs = stackAlloc(12); + GROWABLE_HEAP_I32()[varargs >>> 2] = eventTypeId; + GROWABLE_HEAP_I32()[varargs + 4 >>> 2] = eventData; + GROWABLE_HEAP_I32()[varargs + 8 >>> 2] = userData; + __emscripten_call_on_thread(0, targetThread, 637534208, eventHandlerFunc, eventData, varargs); + stackRestore(stackTop); + }, getTargetThreadForEventCallback: function(targetThread) { + switch (targetThread) { + case 1: + return 0; + case 2: + return PThread.currentProxiedOperationCallerThread; + default: + return targetThread; + } + }, getNodeNameForTarget: function(target) { + if (!target) + return ""; + if (target == window) + return "#window"; + if (target == screen) + return "#screen"; + return target && target.nodeName ? target.nodeName : ""; + }, fullscreenEnabled: function() { + return document.fullscreenEnabled || document.webkitFullscreenEnabled; + } }; + function stringToNewUTF8(jsString) { + var length = lengthBytesUTF8(jsString) + 1; + var cString = _malloc(length); + stringToUTF8(jsString, cString, length); + return cString; + } + function _emscripten_set_offscreencanvas_size_on_target_thread_js(targetThread, targetCanvas, width, height) { + var stackTop = stackSave(); + var varargs = stackAlloc(12); + var targetCanvasPtr = 0; + if (targetCanvas) { + targetCanvasPtr = stringToNewUTF8(targetCanvas); + } + GROWABLE_HEAP_I32()[varargs >>> 2] = targetCanvasPtr; + GROWABLE_HEAP_I32()[varargs + 4 >>> 2] = width; + GROWABLE_HEAP_I32()[varargs + 8 >>> 2] = height; + __emscripten_call_on_thread(0, targetThread, 657457152, 0, targetCanvasPtr, varargs); + stackRestore(stackTop); + } + function _emscripten_set_offscreencanvas_size_on_target_thread(targetThread, targetCanvas, width, height) { + targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : ""; + _emscripten_set_offscreencanvas_size_on_target_thread_js(targetThread, targetCanvas, width, height); + } + function maybeCStringToJsString(cString) { + return cString > 2 ? UTF8ToString(cString) : cString; + } + var specialHTMLTargets = [0, typeof document !== "undefined" ? document : 0, typeof window !== "undefined" ? window : 0]; + function findEventTarget(target) { + target = maybeCStringToJsString(target); + var domElement = specialHTMLTargets[target] || (typeof document !== "undefined" ? document.querySelector(target) : void 0); + return domElement; + } + function findCanvasEventTarget(target) { + return findEventTarget(target); + } + function _emscripten_set_canvas_element_size_calling_thread(target, width, height) { + var canvas = findCanvasEventTarget(target); + if (!canvas) + return -4; + if (canvas.canvasSharedPtr) { + GROWABLE_HEAP_I32()[canvas.canvasSharedPtr >>> 2] = width; + GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 4 >>> 2] = height; + } + if (canvas.offscreenCanvas || !canvas.controlTransferredOffscreen) { + if (canvas.offscreenCanvas) + canvas = canvas.offscreenCanvas; + var autoResizeViewport = false; + if (canvas.GLctxObject && canvas.GLctxObject.GLctx) { + var prevViewport = canvas.GLctxObject.GLctx.getParameter(2978); + autoResizeViewport = prevViewport[0] === 0 && prevViewport[1] === 0 && prevViewport[2] === canvas.width && prevViewport[3] === canvas.height; + } + canvas.width = width; + canvas.height = height; + if (autoResizeViewport) { + canvas.GLctxObject.GLctx.viewport(0, 0, width, height); + } + } else if (canvas.canvasSharedPtr) { + var targetThread = GROWABLE_HEAP_I32()[canvas.canvasSharedPtr + 8 >>> 2]; + _emscripten_set_offscreencanvas_size_on_target_thread(targetThread, target, width, height); + return 1; + } else { + return -4; + } + return 0; + } + function _emscripten_set_canvas_element_size_main_thread(target, width, height) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(5, 1, target, width, height); + return _emscripten_set_canvas_element_size_calling_thread(target, width, height); + } + function _emscripten_set_canvas_element_size(target, width, height) { + var canvas = findCanvasEventTarget(target); + if (canvas) { + return _emscripten_set_canvas_element_size_calling_thread(target, width, height); + } else { + return _emscripten_set_canvas_element_size_main_thread(target, width, height); + } + } + function _emscripten_set_current_thread_status(newStatus) { + } + function __webgl_enable_ANGLE_instanced_arrays(ctx) { + var ext = ctx.getExtension("ANGLE_instanced_arrays"); + if (ext) { + ctx["vertexAttribDivisor"] = function(index, divisor) { + ext["vertexAttribDivisorANGLE"](index, divisor); + }; + ctx["drawArraysInstanced"] = function(mode, first, count, primcount) { + ext["drawArraysInstancedANGLE"](mode, first, count, primcount); + }; + ctx["drawElementsInstanced"] = function(mode, count, type, indices, primcount) { + ext["drawElementsInstancedANGLE"](mode, count, type, indices, primcount); + }; + return 1; + } + } + function __webgl_enable_OES_vertex_array_object(ctx) { + var ext = ctx.getExtension("OES_vertex_array_object"); + if (ext) { + ctx["createVertexArray"] = function() { + return ext["createVertexArrayOES"](); + }; + ctx["deleteVertexArray"] = function(vao) { + ext["deleteVertexArrayOES"](vao); + }; + ctx["bindVertexArray"] = function(vao) { + ext["bindVertexArrayOES"](vao); + }; + ctx["isVertexArray"] = function(vao) { + return ext["isVertexArrayOES"](vao); + }; + return 1; + } + } + function __webgl_enable_WEBGL_draw_buffers(ctx) { + var ext = ctx.getExtension("WEBGL_draw_buffers"); + if (ext) { + ctx["drawBuffers"] = function(n, bufs) { + ext["drawBuffersWEBGL"](n, bufs); + }; + return 1; + } + } + function __webgl_enable_WEBGL_multi_draw(ctx) { + return !!(ctx.multiDrawWebgl = ctx.getExtension("WEBGL_multi_draw")); + } + var GL = { counter: 1, buffers: [], programs: [], framebuffers: [], renderbuffers: [], textures: [], shaders: [], vaos: [], contexts: {}, offscreenCanvases: {}, queries: [], stringCache: {}, unpackAlignment: 4, recordError: function recordError(errorCode) { + if (!GL.lastError) { + GL.lastError = errorCode; + } + }, getNewId: function(table) { + var ret = GL.counter++; + for (var i = table.length; i < ret; i++) { + table[i] = null; + } + return ret; + }, getSource: function(shader, count, string, length) { + var source = ""; + for (var i = 0; i < count; ++i) { + var len = length ? GROWABLE_HEAP_I32()[length + i * 4 >>> 2] : -1; + source += UTF8ToString(GROWABLE_HEAP_I32()[string + i * 4 >>> 2], len < 0 ? void 0 : len); + } + return source; + }, createContext: function(canvas, webGLContextAttributes) { + if (!canvas.getContextSafariWebGL2Fixed) { + canvas.getContextSafariWebGL2Fixed = canvas.getContext; + canvas.getContext = function(ver, attrs) { + var gl = canvas.getContextSafariWebGL2Fixed(ver, attrs); + return ver == "webgl" == gl instanceof WebGLRenderingContext ? gl : null; + }; + } + var ctx = canvas.getContext("webgl", webGLContextAttributes); + if (!ctx) + return 0; + var handle = GL.registerContext(ctx, webGLContextAttributes); + return handle; + }, registerContext: function(ctx, webGLContextAttributes) { + var handle = _malloc(8); + GROWABLE_HEAP_I32()[handle + 4 >>> 2] = _pthread_self(); + var context = { handle, attributes: webGLContextAttributes, version: webGLContextAttributes.majorVersion, GLctx: ctx }; + if (ctx.canvas) + ctx.canvas.GLctxObject = context; + GL.contexts[handle] = context; + if (typeof webGLContextAttributes.enableExtensionsByDefault === "undefined" || webGLContextAttributes.enableExtensionsByDefault) { + GL.initExtensions(context); + } + return handle; + }, makeContextCurrent: function(contextHandle) { + GL.currentContext = GL.contexts[contextHandle]; + Module.ctx = GLctx = GL.currentContext && GL.currentContext.GLctx; + return !(contextHandle && !GLctx); + }, getContext: function(contextHandle) { + return GL.contexts[contextHandle]; + }, deleteContext: function(contextHandle) { + if (GL.currentContext === GL.contexts[contextHandle]) + GL.currentContext = null; + if (typeof JSEvents === "object") + JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); + if (GL.contexts[contextHandle] && GL.contexts[contextHandle].GLctx.canvas) + GL.contexts[contextHandle].GLctx.canvas.GLctxObject = void 0; + _free(GL.contexts[contextHandle].handle); + GL.contexts[contextHandle] = null; + }, initExtensions: function(context) { + if (!context) + context = GL.currentContext; + if (context.initExtensionsDone) + return; + context.initExtensionsDone = true; + var GLctx2 = context.GLctx; + __webgl_enable_ANGLE_instanced_arrays(GLctx2); + __webgl_enable_OES_vertex_array_object(GLctx2); + __webgl_enable_WEBGL_draw_buffers(GLctx2); + { + GLctx2.disjointTimerQueryExt = GLctx2.getExtension("EXT_disjoint_timer_query"); + } + __webgl_enable_WEBGL_multi_draw(GLctx2); + var exts = GLctx2.getSupportedExtensions() || []; + exts.forEach(function(ext) { + if (!ext.includes("lose_context") && !ext.includes("debug")) { + GLctx2.getExtension(ext); + } + }); + } }; + var __emscripten_webgl_power_preferences = ["default", "low-power", "high-performance"]; + function _emscripten_webgl_do_create_context(target, attributes) { + var a = attributes >> 2; + var powerPreference = GROWABLE_HEAP_I32()[a + (24 >> 2) >>> 0]; + var contextAttributes = { "alpha": !!GROWABLE_HEAP_I32()[a + (0 >> 2) >>> 0], "depth": !!GROWABLE_HEAP_I32()[a + (4 >> 2) >>> 0], "stencil": !!GROWABLE_HEAP_I32()[a + (8 >> 2) >>> 0], "antialias": !!GROWABLE_HEAP_I32()[a + (12 >> 2) >>> 0], "premultipliedAlpha": !!GROWABLE_HEAP_I32()[a + (16 >> 2) >>> 0], "preserveDrawingBuffer": !!GROWABLE_HEAP_I32()[a + (20 >> 2) >>> 0], "powerPreference": __emscripten_webgl_power_preferences[powerPreference], "failIfMajorPerformanceCaveat": !!GROWABLE_HEAP_I32()[a + (28 >> 2) >>> 0], majorVersion: GROWABLE_HEAP_I32()[a + (32 >> 2) >>> 0], minorVersion: GROWABLE_HEAP_I32()[a + (36 >> 2) >>> 0], enableExtensionsByDefault: GROWABLE_HEAP_I32()[a + (40 >> 2) >>> 0], explicitSwapControl: GROWABLE_HEAP_I32()[a + (44 >> 2) >>> 0], proxyContextToMainThread: GROWABLE_HEAP_I32()[a + (48 >> 2) >>> 0], renderViaOffscreenBackBuffer: GROWABLE_HEAP_I32()[a + (52 >> 2) >>> 0] }; + var canvas = findCanvasEventTarget(target); + if (!canvas) { + return 0; + } + if (contextAttributes.explicitSwapControl) { + return 0; + } + var contextHandle = GL.createContext(canvas, contextAttributes); + return contextHandle; + } + function _emscripten_webgl_create_context(a0, a1) { + return _emscripten_webgl_do_create_context(a0, a1); + } var ENV = {}; function getExecutableName() { return thisProgram || "./this.program"; @@ -116410,7 +123625,10 @@ var require_web_ifc = __commonJS({ var lang = (typeof navigator === "object" && navigator.languages && navigator.languages[0] || "C").replace("-", "_") + ".UTF-8"; var env = { "USER": "web_user", "LOGNAME": "web_user", "PATH": "/", "PWD": "/", "HOME": "/home/web_user", "LANG": lang, "_": getExecutableName() }; for (var x in ENV) { - env[x] = ENV[x]; + if (ENV[x] === void 0) + delete env[x]; + else + env[x] = ENV[x]; } var strings = []; for (var x in env) { @@ -116421,11 +123639,13 @@ var require_web_ifc = __commonJS({ return getEnvStrings.strings; } function _environ_get(__environ, environ_buf) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(6, 1, __environ, environ_buf); try { var bufSize = 0; getEnvStrings().forEach(function(string, i) { var ptr = environ_buf + bufSize; - HEAP32[__environ + i * 4 >>> 2] = ptr; + GROWABLE_HEAP_I32()[__environ + i * 4 >>> 2] = ptr; writeAsciiToMemory(string, ptr); bufSize += string.length + 1; }); @@ -116437,14 +123657,16 @@ var require_web_ifc = __commonJS({ } } function _environ_sizes_get(penviron_count, penviron_buf_size) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(7, 1, penviron_count, penviron_buf_size); try { var strings = getEnvStrings(); - HEAP32[penviron_count >>> 2] = strings.length; + GROWABLE_HEAP_I32()[penviron_count >>> 2] = strings.length; var bufSize = 0; strings.forEach(function(string) { bufSize += string.length + 1; }); - HEAP32[penviron_buf_size >>> 2] = bufSize; + GROWABLE_HEAP_I32()[penviron_buf_size >>> 2] = bufSize; return 0; } catch (e) { if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) @@ -116453,6 +123675,8 @@ var require_web_ifc = __commonJS({ } } function _fd_close(fd) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(8, 1, fd); try { var stream = SYSCALLS.getStreamFromFD(fd); FS.close(stream); @@ -116464,10 +123688,12 @@ var require_web_ifc = __commonJS({ } } function _fd_read(fd, iov, iovcnt, pnum) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(9, 1, fd, iov, iovcnt, pnum); try { var stream = SYSCALLS.getStreamFromFD(fd); var num = SYSCALLS.doReadv(stream, iov, iovcnt); - HEAP32[pnum >>> 2] = num; + GROWABLE_HEAP_I32()[pnum >>> 2] = num; return 0; } catch (e) { if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) @@ -116476,6 +123702,8 @@ var require_web_ifc = __commonJS({ } } function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(10, 1, fd, offset_low, offset_high, whence, newOffset); try { var stream = SYSCALLS.getStreamFromFD(fd); var HIGH_OFFSET = 4294967296; @@ -116485,7 +123713,7 @@ var require_web_ifc = __commonJS({ return -61; } FS.llseek(stream, offset, whence); - tempI64 = [stream.position >>> 0, (tempDouble = stream.position, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], HEAP32[newOffset >>> 2] = tempI64[0], HEAP32[newOffset + 4 >>> 2] = tempI64[1]; + tempI64 = [stream.position >>> 0, (tempDouble = stream.position, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], GROWABLE_HEAP_I32()[newOffset >>> 2] = tempI64[0], GROWABLE_HEAP_I32()[newOffset + 4 >>> 2] = tempI64[1]; if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; return 0; @@ -116496,10 +123724,12 @@ var require_web_ifc = __commonJS({ } } function _fd_write(fd, iov, iovcnt, pnum) { + if (ENVIRONMENT_IS_PTHREAD) + return _emscripten_proxy_to_main_thread_js(11, 1, fd, iov, iovcnt, pnum); try { var stream = SYSCALLS.getStreamFromFD(fd); var num = SYSCALLS.doWritev(stream, iov, iovcnt); - HEAP32[pnum >>> 2] = num; + GROWABLE_HEAP_I32()[pnum >>> 2] = num; return 0; } catch (e) { if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) @@ -116507,13 +123737,96 @@ var require_web_ifc = __commonJS({ return e.errno; } } - function _pthread_mutexattr_destroy() { - } - function _pthread_mutexattr_init() { + function spawnThread(threadParams) { + if (ENVIRONMENT_IS_PTHREAD) + throw "Internal Error! spawnThread() can only ever be called from main application thread!"; + var worker = PThread.getNewWorker(); + if (!worker) { + return 6; + } + if (worker.pthread !== void 0) + throw "Internal error!"; + if (!threadParams.pthread_ptr) + throw "Internal error, no pthread ptr!"; + PThread.runningWorkers.push(worker); + var tlsMemory = _malloc(128 * 4); + for (var i = 0; i < 128; ++i) { + GROWABLE_HEAP_I32()[tlsMemory + i * 4 >>> 2] = 0; + } + var stackHigh = threadParams.stackBase + threadParams.stackSize; + var pthread = PThread.pthreads[threadParams.pthread_ptr] = { worker, stackBase: threadParams.stackBase, stackSize: threadParams.stackSize, allocatedOwnStack: threadParams.allocatedOwnStack, threadInfoStruct: threadParams.pthread_ptr }; + var tis = pthread.threadInfoStruct >> 2; + Atomics.store(GROWABLE_HEAP_U32(), tis + (64 >> 2), threadParams.detached); + Atomics.store(GROWABLE_HEAP_U32(), tis + (100 >> 2), tlsMemory); + Atomics.store(GROWABLE_HEAP_U32(), tis + (40 >> 2), pthread.threadInfoStruct); + Atomics.store(GROWABLE_HEAP_U32(), tis + (80 >> 2), threadParams.stackSize); + Atomics.store(GROWABLE_HEAP_U32(), tis + (76 >> 2), stackHigh); + Atomics.store(GROWABLE_HEAP_U32(), tis + (104 >> 2), threadParams.stackSize); + Atomics.store(GROWABLE_HEAP_U32(), tis + (104 + 8 >> 2), stackHigh); + Atomics.store(GROWABLE_HEAP_U32(), tis + (104 + 12 >> 2), threadParams.detached); + var global_libc = _emscripten_get_global_libc(); + var global_locale = global_libc + 40; + Atomics.store(GROWABLE_HEAP_U32(), tis + (172 >> 2), global_locale); + worker.pthread = pthread; + var msg = { "cmd": "run", "start_routine": threadParams.startRoutine, "arg": threadParams.arg, "threadInfoStruct": threadParams.pthread_ptr, "stackBase": threadParams.stackBase, "stackSize": threadParams.stackSize }; + worker.runPthread = function() { + msg.time = performance.now(); + worker.postMessage(msg, threadParams.transferList); + }; + if (worker.loaded) { + worker.runPthread(); + delete worker.runPthread; + } + return 0; } - function _pthread_mutexattr_settype() { + function _pthread_create(pthread_ptr, attr, start_routine, arg) { + if (typeof SharedArrayBuffer === "undefined") { + err("Current environment does not support SharedArrayBuffer, pthreads are not available!"); + return 6; + } + if (!pthread_ptr) { + err("pthread_create called with a null thread pointer!"); + return 28; + } + var transferList = []; + var error = 0; + if (ENVIRONMENT_IS_PTHREAD && (transferList.length === 0 || error)) { + return _emscripten_sync_run_in_main_thread_4(687865856, pthread_ptr, attr, start_routine, arg); + } + var stackSize = 0; + var stackBase = 0; + var detached = 0; + if (attr && attr != -1) { + stackSize = GROWABLE_HEAP_I32()[attr >>> 2]; + stackSize += 81920; + stackBase = GROWABLE_HEAP_I32()[attr + 8 >>> 2]; + detached = GROWABLE_HEAP_I32()[attr + 12 >>> 2] !== 0; + } else { + stackSize = 2097152; + } + var allocatedOwnStack = stackBase == 0; + if (allocatedOwnStack) { + stackBase = _memalign(16, stackSize); + } else { + stackBase -= stackSize; + assert(stackBase > 0); + } + var threadInfoStruct = _malloc(228); + for (var i = 0; i < 228 >> 2; ++i) + GROWABLE_HEAP_U32()[(threadInfoStruct >> 2) + i >>> 0] = 0; + GROWABLE_HEAP_I32()[pthread_ptr >>> 2] = threadInfoStruct; + GROWABLE_HEAP_I32()[threadInfoStruct + 12 >>> 2] = threadInfoStruct; + var headPtr = threadInfoStruct + 152; + GROWABLE_HEAP_I32()[headPtr >>> 2] = headPtr; + var threadParams = { stackBase, stackSize, allocatedOwnStack, detached, startRoutine: start_routine, pthread_ptr: threadInfoStruct, arg, transferList }; + if (ENVIRONMENT_IS_PTHREAD) { + threadParams.cmd = "spawnThread"; + postMessage(threadParams, transferList); + return 0; + } + return spawnThread(threadParams); } - function _setTempRet0($i) { + function _setTempRet0(val) { } function __isLeapYear(year) { return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); @@ -116549,8 +123862,8 @@ var require_web_ifc = __commonJS({ return newDate; } function _strftime(s, maxsize, format, tm) { - var tm_zone = HEAP32[tm + 40 >>> 2]; - var date = { tm_sec: HEAP32[tm >>> 2], tm_min: HEAP32[tm + 4 >>> 2], tm_hour: HEAP32[tm + 8 >>> 2], tm_mday: HEAP32[tm + 12 >>> 2], tm_mon: HEAP32[tm + 16 >>> 2], tm_year: HEAP32[tm + 20 >>> 2], tm_wday: HEAP32[tm + 24 >>> 2], tm_yday: HEAP32[tm + 28 >>> 2], tm_isdst: HEAP32[tm + 32 >>> 2], tm_gmtoff: HEAP32[tm + 36 >>> 2], tm_zone: tm_zone ? UTF8ToString(tm_zone) : "" }; + var tm_zone = GROWABLE_HEAP_I32()[tm + 40 >>> 2]; + var date = { tm_sec: GROWABLE_HEAP_I32()[tm >>> 2], tm_min: GROWABLE_HEAP_I32()[tm + 4 >>> 2], tm_hour: GROWABLE_HEAP_I32()[tm + 8 >>> 2], tm_mday: GROWABLE_HEAP_I32()[tm + 12 >>> 2], tm_mon: GROWABLE_HEAP_I32()[tm + 16 >>> 2], tm_year: GROWABLE_HEAP_I32()[tm + 20 >>> 2], tm_wday: GROWABLE_HEAP_I32()[tm + 24 >>> 2], tm_yday: GROWABLE_HEAP_I32()[tm + 28 >>> 2], tm_isdst: GROWABLE_HEAP_I32()[tm + 32 >>> 2], tm_gmtoff: GROWABLE_HEAP_I32()[tm + 36 >>> 2], tm_zone: tm_zone ? UTF8ToString(tm_zone) : "" }; var pattern = UTF8ToString(format); var EXPANSION_RULES_1 = { "%c": "%a %b %d %H:%M:%S %Y", "%D": "%m/%d/%y", "%F": "%Y-%m-%d", "%h": "%b", "%r": "%I:%M:%S %p", "%R": "%H:%M", "%T": "%H:%M:%S", "%x": "%m/%d/%y", "%X": "%H:%M:%S", "%Ec": "%c", "%EC": "%C", "%Ex": "%m/%d/%y", "%EX": "%H:%M:%S", "%Ey": "%y", "%EY": "%Y", "%Od": "%d", "%Oe": "%e", "%OH": "%H", "%OI": "%I", "%Om": "%m", "%OM": "%M", "%OS": "%S", "%Ou": "%u", "%OU": "%U", "%OV": "%V", "%Ow": "%w", "%OW": "%W", "%Oy": "%y" }; for (var rule in EXPANSION_RULES_1) { @@ -116721,7 +124034,7 @@ var require_web_ifc = __commonJS({ return "%"; } }; for (var rule in EXPANSION_RULES_2) { - if (pattern.indexOf(rule) >= 0) { + if (pattern.includes(rule)) { pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_2[rule](date)); } } @@ -116735,6 +124048,8 @@ var require_web_ifc = __commonJS({ function _strftime_l(s, maxsize, format, tm) { return _strftime(s, maxsize, format, tm); } + if (!ENVIRONMENT_IS_PTHREAD) + PThread.initMainThreadBlock(); var FSNode = function(parent, name2, mode, rdev) { if (!parent) { parent = this; @@ -116780,6 +124095,8 @@ var require_web_ifc = __commonJS({ init_embind(); UnboundTypeError = Module["UnboundTypeError"] = extendError(Error, "UnboundTypeError"); init_emval(); + var GLctx; + var proxiedFunctionTable = [null, _atexit, ___sys_fcntl64, ___sys_ioctl, ___sys_open, _emscripten_set_canvas_element_size_main_thread, _environ_get, _environ_sizes_get, _fd_close, _fd_read, _fd_seek, _fd_write]; function intArrayFromString(stringy, dontAddNull, length) { var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; var u8array = new Array(len); @@ -116788,47 +124105,97 @@ var require_web_ifc = __commonJS({ u8array.length = numBytesWritten; return u8array; } - __ATINIT__.push({ func: function() { - ___wasm_call_ctors(); - } }); - var asmLibraryArg = { "z": ___assert_fail, "y": ___cxa_allocate_exception, "x": ___cxa_throw, "V": ___sys_ioctl, "W": ___sys_open, "$": __embind_finalize_value_array, "q": __embind_finalize_value_object, "Y": __embind_register_bool, "t": __embind_register_class, "s": __embind_register_class_constructor, "c": __embind_register_class_function, "X": __embind_register_emval, "_": __embind_register_enum, "v": __embind_register_enum_value, "F": __embind_register_float, "f": __embind_register_function, "o": __embind_register_integer, "k": __embind_register_memory_view, "G": __embind_register_std_string, "w": __embind_register_std_wstring, "aa": __embind_register_value_array, "h": __embind_register_value_array_element, "r": __embind_register_value_object, "e": __embind_register_value_object_field, "Z": __embind_register_void, "m": __emval_as, "H": __emval_call, "b": __emval_decref, "J": __emval_get_global, "n": __emval_get_property, "j": __emval_incref, "N": __emval_instanceof, "I": __emval_is_number, "A": __emval_new_array, "g": __emval_new_cstring, "u": __emval_new_object, "l": __emval_run_destructors, "i": __emval_set_property, "d": __emval_take_value, "C": _abort, "T": _clock_gettime, "M": _emscripten_memcpy_big, "p": _emscripten_resize_heap, "R": _environ_get, "S": _environ_sizes_get, "E": _fd_close, "U": _fd_read, "K": _fd_seek, "D": _fd_write, "a": wasmMemory, "B": _pthread_mutexattr_destroy, "P": _pthread_mutexattr_init, "O": _pthread_mutexattr_settype, "L": _setTempRet0, "Q": _strftime_l }; + var asmLibraryArg = { "l": ___assert_fail, "B": ___cxa_allocate_exception, "ka": ___cxa_thread_atexit, "A": ___cxa_throw, "D": ___sys_fcntl64, "V": ___sys_ioctl, "W": ___sys_open, "ma": __embind_finalize_value_array, "s": __embind_finalize_value_object, "O": __embind_register_bigint, "ia": __embind_register_bool, "v": __embind_register_class, "u": __embind_register_class_constructor, "c": __embind_register_class_function, "ha": __embind_register_emval, "la": __embind_register_enum, "y": __embind_register_enum_value, "J": __embind_register_float, "f": __embind_register_function, "p": __embind_register_integer, "k": __embind_register_memory_view, "K": __embind_register_std_string, "z": __embind_register_std_wstring, "na": __embind_register_value_array, "h": __embind_register_value_array_element, "t": __embind_register_value_object, "e": __embind_register_value_object_field, "ja": __embind_register_void, "ea": __emscripten_notify_thread_queue, "n": __emval_as, "L": __emval_call, "b": __emval_decref, "U": __emval_get_global, "o": __emval_get_property, "j": __emval_incref, "ca": __emval_instanceof, "M": __emval_is_number, "C": __emval_new_array, "g": __emval_new_cstring, "w": __emval_new_object, "m": __emval_run_destructors, "i": __emval_set_property, "d": __emval_take_value, "I": _abort, "T": _clock_gettime, "G": _emscripten_asm_const_int, "_": _emscripten_check_blocking_allowed, "F": _emscripten_conditional_set_current_thread_status, "r": _emscripten_futex_wait, "q": _emscripten_futex_wake, "x": _emscripten_get_now, "R": _emscripten_memcpy_big, "$": _emscripten_receive_on_main_thread_js, "S": _emscripten_resize_heap, "aa": _emscripten_set_canvas_element_size, "E": _emscripten_set_current_thread_status, "ba": _emscripten_webgl_create_context, "Y": _environ_get, "Z": _environ_sizes_get, "H": _fd_close, "ga": _fd_read, "N": _fd_seek, "fa": _fd_write, "Q": initPthreadsJS, "a": wasmMemory || Module["wasmMemory"], "da": _pthread_create, "P": _setTempRet0, "X": _strftime_l }; createWasm(); - var ___wasm_call_ctors = Module["___wasm_call_ctors"] = function() { - return (___wasm_call_ctors = Module["___wasm_call_ctors"] = Module["asm"]["ca"]).apply(null, arguments); + Module["___wasm_call_ctors"] = function() { + return (Module["___wasm_call_ctors"] = Module["asm"]["oa"]).apply(null, arguments); }; Module["_main"] = function() { - return (Module["_main"] = Module["asm"]["da"]).apply(null, arguments); + return (Module["_main"] = Module["asm"]["pa"]).apply(null, arguments); }; var _malloc = Module["_malloc"] = function() { - return (_malloc = Module["_malloc"] = Module["asm"]["ea"]).apply(null, arguments); + return (_malloc = Module["_malloc"] = Module["asm"]["qa"]).apply(null, arguments); }; var _free = Module["_free"] = function() { - return (_free = Module["_free"] = Module["asm"]["fa"]).apply(null, arguments); + return (_free = Module["_free"] = Module["asm"]["ra"]).apply(null, arguments); + }; + Module["_emscripten_tls_init"] = function() { + return (Module["_emscripten_tls_init"] = Module["asm"]["sa"]).apply(null, arguments); }; var ___getTypeName = Module["___getTypeName"] = function() { - return (___getTypeName = Module["___getTypeName"] = Module["asm"]["ga"]).apply(null, arguments); + return (___getTypeName = Module["___getTypeName"] = Module["asm"]["ua"]).apply(null, arguments); }; Module["___embind_register_native_and_builtin_types"] = function() { - return (Module["___embind_register_native_and_builtin_types"] = Module["asm"]["ha"]).apply(null, arguments); + return (Module["___embind_register_native_and_builtin_types"] = Module["asm"]["va"]).apply(null, arguments); + }; + Module["_emscripten_current_thread_process_queued_calls"] = function() { + return (Module["_emscripten_current_thread_process_queued_calls"] = Module["asm"]["wa"]).apply(null, arguments); + }; + var _emscripten_register_main_browser_thread_id = Module["_emscripten_register_main_browser_thread_id"] = function() { + return (_emscripten_register_main_browser_thread_id = Module["_emscripten_register_main_browser_thread_id"] = Module["asm"]["xa"]).apply(null, arguments); + }; + var __emscripten_do_dispatch_to_thread = Module["__emscripten_do_dispatch_to_thread"] = function() { + return (__emscripten_do_dispatch_to_thread = Module["__emscripten_do_dispatch_to_thread"] = Module["asm"]["ya"]).apply(null, arguments); + }; + var _emscripten_sync_run_in_main_thread_4 = Module["_emscripten_sync_run_in_main_thread_4"] = function() { + return (_emscripten_sync_run_in_main_thread_4 = Module["_emscripten_sync_run_in_main_thread_4"] = Module["asm"]["za"]).apply(null, arguments); + }; + var _emscripten_main_thread_process_queued_calls = Module["_emscripten_main_thread_process_queued_calls"] = function() { + return (_emscripten_main_thread_process_queued_calls = Module["_emscripten_main_thread_process_queued_calls"] = Module["asm"]["Aa"]).apply(null, arguments); + }; + var _emscripten_run_in_main_runtime_thread_js = Module["_emscripten_run_in_main_runtime_thread_js"] = function() { + return (_emscripten_run_in_main_runtime_thread_js = Module["_emscripten_run_in_main_runtime_thread_js"] = Module["asm"]["Ba"]).apply(null, arguments); + }; + var __emscripten_call_on_thread = Module["__emscripten_call_on_thread"] = function() { + return (__emscripten_call_on_thread = Module["__emscripten_call_on_thread"] = Module["asm"]["Ca"]).apply(null, arguments); + }; + var __emscripten_thread_init = Module["__emscripten_thread_init"] = function() { + return (__emscripten_thread_init = Module["__emscripten_thread_init"] = Module["asm"]["Da"]).apply(null, arguments); + }; + var _emscripten_get_global_libc = Module["_emscripten_get_global_libc"] = function() { + return (_emscripten_get_global_libc = Module["_emscripten_get_global_libc"] = Module["asm"]["Ea"]).apply(null, arguments); }; var ___errno_location = Module["___errno_location"] = function() { - return (___errno_location = Module["___errno_location"] = Module["asm"]["ia"]).apply(null, arguments); + return (___errno_location = Module["___errno_location"] = Module["asm"]["Fa"]).apply(null, arguments); + }; + var _pthread_self = Module["_pthread_self"] = function() { + return (_pthread_self = Module["_pthread_self"] = Module["asm"]["Ga"]).apply(null, arguments); + }; + var ___pthread_tsd_run_dtors = Module["___pthread_tsd_run_dtors"] = function() { + return (___pthread_tsd_run_dtors = Module["___pthread_tsd_run_dtors"] = Module["asm"]["Ha"]).apply(null, arguments); + }; + var stackSave = Module["stackSave"] = function() { + return (stackSave = Module["stackSave"] = Module["asm"]["Ia"]).apply(null, arguments); + }; + var stackRestore = Module["stackRestore"] = function() { + return (stackRestore = Module["stackRestore"] = Module["asm"]["Ja"]).apply(null, arguments); + }; + var stackAlloc = Module["stackAlloc"] = function() { + return (stackAlloc = Module["stackAlloc"] = Module["asm"]["Ka"]).apply(null, arguments); + }; + var _emscripten_stack_set_limits = Module["_emscripten_stack_set_limits"] = function() { + return (_emscripten_stack_set_limits = Module["_emscripten_stack_set_limits"] = Module["asm"]["La"]).apply(null, arguments); + }; + var _memalign = Module["_memalign"] = function() { + return (_memalign = Module["_memalign"] = Module["asm"]["Ma"]).apply(null, arguments); }; Module["dynCall_jiji"] = function() { - return (Module["dynCall_jiji"] = Module["asm"]["ja"]).apply(null, arguments); + return (Module["dynCall_jiji"] = Module["asm"]["Na"]).apply(null, arguments); }; Module["dynCall_viijii"] = function() { - return (Module["dynCall_viijii"] = Module["asm"]["ka"]).apply(null, arguments); - }; - Module["dynCall_iiiiiijj"] = function() { - return (Module["dynCall_iiiiiijj"] = Module["asm"]["la"]).apply(null, arguments); + return (Module["dynCall_viijii"] = Module["asm"]["Oa"]).apply(null, arguments); }; Module["dynCall_iiiiij"] = function() { - return (Module["dynCall_iiiiij"] = Module["asm"]["ma"]).apply(null, arguments); + return (Module["dynCall_iiiiij"] = Module["asm"]["Pa"]).apply(null, arguments); }; Module["dynCall_iiiiijj"] = function() { - return (Module["dynCall_iiiiijj"] = Module["asm"]["na"]).apply(null, arguments); + return (Module["dynCall_iiiiijj"] = Module["asm"]["Qa"]).apply(null, arguments); }; + Module["dynCall_iiiiiijj"] = function() { + return (Module["dynCall_iiiiiijj"] = Module["asm"]["Ra"]).apply(null, arguments); + }; + var __emscripten_allow_main_runtime_queued_calls = Module["__emscripten_allow_main_runtime_queued_calls"] = 44840; + var __emscripten_main_thread_futex = Module["__emscripten_main_thread_futex"] = 48292; Module["addRunDependency"] = addRunDependency; Module["removeRunDependency"] = removeRunDependency; Module["FS_createPath"] = FS.createPath; @@ -116837,7 +124204,12 @@ var require_web_ifc = __commonJS({ Module["FS_createLazyFile"] = FS.createLazyFile; Module["FS_createDevice"] = FS.createDevice; Module["FS_unlink"] = FS.unlink; + Module["keepRuntimeAlive"] = keepRuntimeAlive; Module["FS"] = FS; + Module["PThread"] = PThread; + Module["PThread"] = PThread; + Module["wasmMemory"] = wasmMemory; + Module["ExitStatus"] = ExitStatus; var calledRun; function ExitStatus(status) { this.name = "ExitStatus"; @@ -116858,19 +124230,15 @@ var require_web_ifc = __commonJS({ var ret = entryFunction(argc, argv); exit(ret, true); } catch (e) { - if (e instanceof ExitStatus) { + if (e instanceof ExitStatus || e == "unwind") { return; - } else if (e == "unwind") { - noExitRuntime = true; - return; - } else { - var toLog = e; - if (e && typeof e === "object" && e.stack) { - toLog = [e, e.stack]; - } - err("exception thrown: " + toLog); - quit_(1, e); } + var toLog = e; + if (e && typeof e === "object" && e.stack) { + toLog = [e, e.stack]; + } + err("exception thrown: " + toLog); + quit_(1, e); } finally { } } @@ -116878,9 +124246,16 @@ var require_web_ifc = __commonJS({ if (runDependencies > 0) { return; } + if (ENVIRONMENT_IS_PTHREAD) { + readyPromiseResolve(Module); + initRuntime(); + postMessage({ "cmd": "loaded" }); + return; + } preRun(); - if (runDependencies > 0) + if (runDependencies > 0) { return; + } function doRun() { if (calledRun) return; @@ -116911,10 +124286,14 @@ var require_web_ifc = __commonJS({ } Module["run"] = run; function exit(status, implicit) { - if (implicit && noExitRuntime && status === 0) { - return; + if (!implicit) { + if (ENVIRONMENT_IS_PTHREAD) { + postMessage({ "cmd": "exitProcess", "returnCode": status }); + throw new ExitStatus(status); + } } - if (noExitRuntime) ; else { + if (keepRuntimeAlive()) ; else { + PThread.terminateAllThreads(); if (Module["onExit"]) Module["onExit"](status); ABORT = true; @@ -116931,7 +124310,10 @@ var require_web_ifc = __commonJS({ var shouldRunNow = true; if (Module["noInitialRun"]) shouldRunNow = false; - noExitRuntime = true; + if (ENVIRONMENT_IS_PTHREAD) { + noExitRuntime = false; + PThread.initWorker(); + } run(); return WebIFCWasm3.ready; }; @@ -116947,43700 +124329,37820 @@ var require_web_ifc = __commonJS({ } }); -// dist/ifc2x4.ts -var IFCACTIONREQUEST = 3821786052; -var IFCACTOR = 2296667514; -var IFCACTORROLE = 3630933823; -var IFCACTUATOR = 4288193352; -var IFCACTUATORTYPE = 2874132201; -var IFCADDRESS = 618182010; -var IFCADVANCEDBREP = 1635779807; -var IFCADVANCEDBREPWITHVOIDS = 2603310189; -var IFCADVANCEDFACE = 3406155212; -var IFCAIRTERMINAL = 1634111441; -var IFCAIRTERMINALBOX = 177149247; -var IFCAIRTERMINALBOXTYPE = 1411407467; -var IFCAIRTERMINALTYPE = 3352864051; -var IFCAIRTOAIRHEATRECOVERY = 2056796094; -var IFCAIRTOAIRHEATRECOVERYTYPE = 1871374353; -var IFCALARM = 3087945054; -var IFCALARMTYPE = 3001207471; -var IFCALIGNMENT = 325726236; -var IFCALIGNMENT2DHORIZONTAL = 749761778; -var IFCALIGNMENT2DHORIZONTALSEGMENT = 3199563722; -var IFCALIGNMENT2DSEGMENT = 2483840362; -var IFCALIGNMENT2DVERSEGCIRCULARARC = 3379348081; -var IFCALIGNMENT2DVERSEGLINE = 3239324667; -var IFCALIGNMENT2DVERSEGPARABOLICARC = 4263986512; -var IFCALIGNMENT2DVERTICAL = 53199957; -var IFCALIGNMENT2DVERTICALSEGMENT = 2029264950; -var IFCALIGNMENTCURVE = 3512275521; -var IFCANNOTATION = 1674181508; -var IFCANNOTATIONFILLAREA = 669184980; -var IFCAPPLICATION = 639542469; -var IFCAPPLIEDVALUE = 411424972; -var IFCAPPROVAL = 130549933; -var IFCAPPROVALRELATIONSHIP = 3869604511; -var IFCARBITRARYCLOSEDPROFILEDEF = 3798115385; -var IFCARBITRARYOPENPROFILEDEF = 1310608509; -var IFCARBITRARYPROFILEDEFWITHVOIDS = 2705031697; -var IFCASSET = 3460190687; -var IFCASYMMETRICISHAPEPROFILEDEF = 3207858831; -var IFCAUDIOVISUALAPPLIANCE = 277319702; -var IFCAUDIOVISUALAPPLIANCETYPE = 1532957894; -var IFCAXIS1PLACEMENT = 4261334040; -var IFCAXIS2PLACEMENT2D = 3125803723; -var IFCAXIS2PLACEMENT3D = 2740243338; -var IFCBSPLINECURVE = 1967976161; -var IFCBSPLINECURVEWITHKNOTS = 2461110595; -var IFCBSPLINESURFACE = 2887950389; -var IFCBSPLINESURFACEWITHKNOTS = 167062518; -var IFCBEAM = 753842376; -var IFCBEAMSTANDARDCASE = 2906023776; -var IFCBEAMTYPE = 819618141; -var IFCBEARING = 4196446775; -var IFCBEARINGTYPE = 3649138523; -var IFCBLOBTEXTURE = 616511568; -var IFCBLOCK = 1334484129; -var IFCBOILER = 32344328; -var IFCBOILERTYPE = 231477066; -var IFCBOOLEANCLIPPINGRESULT = 3649129432; -var IFCBOOLEANRESULT = 2736907675; -var IFCBOUNDARYCONDITION = 4037036970; -var IFCBOUNDARYCURVE = 1136057603; -var IFCBOUNDARYEDGECONDITION = 1560379544; -var IFCBOUNDARYFACECONDITION = 3367102660; -var IFCBOUNDARYNODECONDITION = 1387855156; -var IFCBOUNDARYNODECONDITIONWARPING = 2069777674; -var IFCBOUNDEDCURVE = 1260505505; -var IFCBOUNDEDSURFACE = 4182860854; -var IFCBOUNDINGBOX = 2581212453; -var IFCBOXEDHALFSPACE = 2713105998; -var IFCBRIDGE = 644574406; -var IFCBRIDGEPART = 963979645; -var IFCBUILDING = 4031249490; -var IFCBUILDINGELEMENT = 3299480353; -var IFCBUILDINGELEMENTPART = 2979338954; -var IFCBUILDINGELEMENTPARTTYPE = 39481116; -var IFCBUILDINGELEMENTPROXY = 1095909175; -var IFCBUILDINGELEMENTPROXYTYPE = 1909888760; -var IFCBUILDINGELEMENTTYPE = 1950629157; -var IFCBUILDINGSTOREY = 3124254112; -var IFCBUILDINGSYSTEM = 1177604601; -var IFCBURNER = 2938176219; -var IFCBURNERTYPE = 2188180465; -var IFCCSHAPEPROFILEDEF = 2898889636; -var IFCCABLECARRIERFITTING = 635142910; -var IFCCABLECARRIERFITTINGTYPE = 395041908; -var IFCCABLECARRIERSEGMENT = 3758799889; -var IFCCABLECARRIERSEGMENTTYPE = 3293546465; -var IFCCABLEFITTING = 1051757585; -var IFCCABLEFITTINGTYPE = 2674252688; -var IFCCABLESEGMENT = 4217484030; -var IFCCABLESEGMENTTYPE = 1285652485; -var IFCCAISSONFOUNDATION = 3999819293; -var IFCCAISSONFOUNDATIONTYPE = 3203706013; -var IFCCARTESIANPOINT = 1123145078; -var IFCCARTESIANPOINTLIST = 574549367; -var IFCCARTESIANPOINTLIST2D = 1675464909; -var IFCCARTESIANPOINTLIST3D = 2059837836; -var IFCCARTESIANTRANSFORMATIONOPERATOR = 59481748; -var IFCCARTESIANTRANSFORMATIONOPERATOR2D = 3749851601; -var IFCCARTESIANTRANSFORMATIONOPERATOR2DNONUNIFORM = 3486308946; -var IFCCARTESIANTRANSFORMATIONOPERATOR3D = 3331915920; -var IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM = 1416205885; -var IFCCENTERLINEPROFILEDEF = 3150382593; -var IFCCHILLER = 3902619387; -var IFCCHILLERTYPE = 2951183804; -var IFCCHIMNEY = 3296154744; -var IFCCHIMNEYTYPE = 2197970202; -var IFCCIRCLE = 2611217952; -var IFCCIRCLEHOLLOWPROFILEDEF = 2937912522; -var IFCCIRCLEPROFILEDEF = 1383045692; -var IFCCIRCULARARCSEGMENT2D = 1062206242; -var IFCCIVILELEMENT = 1677625105; -var IFCCIVILELEMENTTYPE = 3893394355; -var IFCCLASSIFICATION = 747523909; -var IFCCLASSIFICATIONREFERENCE = 647927063; -var IFCCLOSEDSHELL = 2205249479; -var IFCCOIL = 639361253; -var IFCCOILTYPE = 2301859152; -var IFCCOLOURRGB = 776857604; -var IFCCOLOURRGBLIST = 3285139300; -var IFCCOLOURSPECIFICATION = 3264961684; -var IFCCOLUMN = 843113511; -var IFCCOLUMNSTANDARDCASE = 905975707; -var IFCCOLUMNTYPE = 300633059; -var IFCCOMMUNICATIONSAPPLIANCE = 3221913625; -var IFCCOMMUNICATIONSAPPLIANCETYPE = 400855858; -var IFCCOMPLEXPROPERTY = 2542286263; -var IFCCOMPLEXPROPERTYTEMPLATE = 3875453745; -var IFCCOMPOSITECURVE = 3732776249; -var IFCCOMPOSITECURVEONSURFACE = 15328376; -var IFCCOMPOSITECURVESEGMENT = 2485617015; -var IFCCOMPOSITEPROFILEDEF = 1485152156; -var IFCCOMPRESSOR = 3571504051; -var IFCCOMPRESSORTYPE = 3850581409; -var IFCCONDENSER = 2272882330; -var IFCCONDENSERTYPE = 2816379211; -var IFCCONIC = 2510884976; -var IFCCONNECTEDFACESET = 370225590; -var IFCCONNECTIONCURVEGEOMETRY = 1981873012; -var IFCCONNECTIONGEOMETRY = 2859738748; -var IFCCONNECTIONPOINTECCENTRICITY = 45288368; -var IFCCONNECTIONPOINTGEOMETRY = 2614616156; -var IFCCONNECTIONSURFACEGEOMETRY = 2732653382; -var IFCCONNECTIONVOLUMEGEOMETRY = 775493141; -var IFCCONSTRAINT = 1959218052; -var IFCCONSTRUCTIONEQUIPMENTRESOURCE = 3898045240; -var IFCCONSTRUCTIONEQUIPMENTRESOURCETYPE = 2185764099; -var IFCCONSTRUCTIONMATERIALRESOURCE = 1060000209; -var IFCCONSTRUCTIONMATERIALRESOURCETYPE = 4105962743; -var IFCCONSTRUCTIONPRODUCTRESOURCE = 488727124; -var IFCCONSTRUCTIONPRODUCTRESOURCETYPE = 1525564444; -var IFCCONSTRUCTIONRESOURCE = 2559216714; -var IFCCONSTRUCTIONRESOURCETYPE = 2574617495; -var IFCCONTEXT = 3419103109; -var IFCCONTEXTDEPENDENTUNIT = 3050246964; -var IFCCONTROL = 3293443760; -var IFCCONTROLLER = 25142252; -var IFCCONTROLLERTYPE = 578613899; -var IFCCONVERSIONBASEDUNIT = 2889183280; -var IFCCONVERSIONBASEDUNITWITHOFFSET = 2713554722; -var IFCCOOLEDBEAM = 4136498852; -var IFCCOOLEDBEAMTYPE = 335055490; -var IFCCOOLINGTOWER = 3640358203; -var IFCCOOLINGTOWERTYPE = 2954562838; -var IFCCOORDINATEOPERATION = 1785450214; -var IFCCOORDINATEREFERENCESYSTEM = 1466758467; -var IFCCOSTITEM = 3895139033; -var IFCCOSTSCHEDULE = 1419761937; -var IFCCOSTVALUE = 602808272; -var IFCCOVERING = 1973544240; -var IFCCOVERINGTYPE = 1916426348; -var IFCCREWRESOURCE = 3295246426; -var IFCCREWRESOURCETYPE = 1815067380; -var IFCCSGPRIMITIVE3D = 2506170314; -var IFCCSGSOLID = 2147822146; -var IFCCURRENCYRELATIONSHIP = 539742890; -var IFCCURTAINWALL = 3495092785; -var IFCCURTAINWALLTYPE = 1457835157; -var IFCCURVE = 2601014836; -var IFCCURVEBOUNDEDPLANE = 2827736869; -var IFCCURVEBOUNDEDSURFACE = 2629017746; -var IFCCURVESEGMENT2D = 1186437898; -var IFCCURVESTYLE = 3800577675; -var IFCCURVESTYLEFONT = 1105321065; -var IFCCURVESTYLEFONTANDSCALING = 2367409068; -var IFCCURVESTYLEFONTPATTERN = 3510044353; -var IFCCYLINDRICALSURFACE = 1213902940; -var IFCDAMPER = 4074379575; -var IFCDAMPERTYPE = 3961806047; -var IFCDEEPFOUNDATION = 3426335179; -var IFCDEEPFOUNDATIONTYPE = 1306400036; -var IFCDERIVEDPROFILEDEF = 3632507154; -var IFCDERIVEDUNIT = 1765591967; -var IFCDERIVEDUNITELEMENT = 1045800335; -var IFCDIMENSIONALEXPONENTS = 2949456006; -var IFCDIRECTION = 32440307; -var IFCDISCRETEACCESSORY = 1335981549; -var IFCDISCRETEACCESSORYTYPE = 2635815018; -var IFCDISTANCEEXPRESSION = 1945343521; -var IFCDISTRIBUTIONCHAMBERELEMENT = 1052013943; -var IFCDISTRIBUTIONCHAMBERELEMENTTYPE = 1599208980; -var IFCDISTRIBUTIONCIRCUIT = 562808652; -var IFCDISTRIBUTIONCONTROLELEMENT = 1062813311; -var IFCDISTRIBUTIONCONTROLELEMENTTYPE = 2063403501; -var IFCDISTRIBUTIONELEMENT = 1945004755; -var IFCDISTRIBUTIONELEMENTTYPE = 3256556792; -var IFCDISTRIBUTIONFLOWELEMENT = 3040386961; -var IFCDISTRIBUTIONFLOWELEMENTTYPE = 3849074793; -var IFCDISTRIBUTIONPORT = 3041715199; -var IFCDISTRIBUTIONSYSTEM = 3205830791; -var IFCDOCUMENTINFORMATION = 1154170062; -var IFCDOCUMENTINFORMATIONRELATIONSHIP = 770865208; -var IFCDOCUMENTREFERENCE = 3732053477; -var IFCDOOR = 395920057; -var IFCDOORLININGPROPERTIES = 2963535650; -var IFCDOORPANELPROPERTIES = 1714330368; -var IFCDOORSTANDARDCASE = 3242481149; -var IFCDOORSTYLE = 526551008; -var IFCDOORTYPE = 2323601079; -var IFCDRAUGHTINGPREDEFINEDCOLOUR = 445594917; -var IFCDRAUGHTINGPREDEFINEDCURVEFONT = 4006246654; -var IFCDUCTFITTING = 342316401; -var IFCDUCTFITTINGTYPE = 869906466; -var IFCDUCTSEGMENT = 3518393246; -var IFCDUCTSEGMENTTYPE = 3760055223; -var IFCDUCTSILENCER = 1360408905; -var IFCDUCTSILENCERTYPE = 2030761528; -var IFCEDGE = 3900360178; -var IFCEDGECURVE = 476780140; -var IFCEDGELOOP = 1472233963; -var IFCELECTRICAPPLIANCE = 1904799276; -var IFCELECTRICAPPLIANCETYPE = 663422040; -var IFCELECTRICDISTRIBUTIONBOARD = 862014818; -var IFCELECTRICDISTRIBUTIONBOARDTYPE = 2417008758; -var IFCELECTRICFLOWSTORAGEDEVICE = 3310460725; -var IFCELECTRICFLOWSTORAGEDEVICETYPE = 3277789161; -var IFCELECTRICGENERATOR = 264262732; -var IFCELECTRICGENERATORTYPE = 1534661035; -var IFCELECTRICMOTOR = 402227799; -var IFCELECTRICMOTORTYPE = 1217240411; -var IFCELECTRICTIMECONTROL = 1003880860; -var IFCELECTRICTIMECONTROLTYPE = 712377611; -var IFCELEMENT = 1758889154; -var IFCELEMENTASSEMBLY = 4123344466; -var IFCELEMENTASSEMBLYTYPE = 2397081782; -var IFCELEMENTCOMPONENT = 1623761950; -var IFCELEMENTCOMPONENTTYPE = 2590856083; -var IFCELEMENTQUANTITY = 1883228015; -var IFCELEMENTTYPE = 339256511; -var IFCELEMENTARYSURFACE = 2777663545; -var IFCELLIPSE = 1704287377; -var IFCELLIPSEPROFILEDEF = 2835456948; -var IFCENERGYCONVERSIONDEVICE = 1658829314; -var IFCENERGYCONVERSIONDEVICETYPE = 2107101300; -var IFCENGINE = 2814081492; -var IFCENGINETYPE = 132023988; -var IFCEVAPORATIVECOOLER = 3747195512; -var IFCEVAPORATIVECOOLERTYPE = 3174744832; -var IFCEVAPORATOR = 484807127; -var IFCEVAPORATORTYPE = 3390157468; -var IFCEVENT = 4148101412; -var IFCEVENTTIME = 211053100; -var IFCEVENTTYPE = 4024345920; -var IFCEXTENDEDPROPERTIES = 297599258; -var IFCEXTERNALINFORMATION = 4294318154; -var IFCEXTERNALREFERENCE = 3200245327; -var IFCEXTERNALREFERENCERELATIONSHIP = 1437805879; -var IFCEXTERNALSPATIALELEMENT = 1209101575; -var IFCEXTERNALSPATIALSTRUCTUREELEMENT = 2853485674; -var IFCEXTERNALLYDEFINEDHATCHSTYLE = 2242383968; -var IFCEXTERNALLYDEFINEDSURFACESTYLE = 1040185647; -var IFCEXTERNALLYDEFINEDTEXTFONT = 3548104201; -var IFCEXTRUDEDAREASOLID = 477187591; -var IFCEXTRUDEDAREASOLIDTAPERED = 2804161546; -var IFCFACE = 2556980723; -var IFCFACEBASEDSURFACEMODEL = 2047409740; -var IFCFACEBOUND = 1809719519; -var IFCFACEOUTERBOUND = 803316827; -var IFCFACESURFACE = 3008276851; -var IFCFACETEDBREP = 807026263; -var IFCFACETEDBREPWITHVOIDS = 3737207727; -var IFCFACILITY = 24185140; -var IFCFACILITYPART = 1310830890; -var IFCFAILURECONNECTIONCONDITION = 4219587988; -var IFCFAN = 3415622556; -var IFCFANTYPE = 346874300; -var IFCFASTENER = 647756555; -var IFCFASTENERTYPE = 2489546625; -var IFCFEATUREELEMENT = 2827207264; -var IFCFEATUREELEMENTADDITION = 2143335405; -var IFCFEATUREELEMENTSUBTRACTION = 1287392070; -var IFCFILLAREASTYLE = 738692330; -var IFCFILLAREASTYLEHATCHING = 374418227; -var IFCFILLAREASTYLETILES = 315944413; -var IFCFILTER = 819412036; -var IFCFILTERTYPE = 1810631287; -var IFCFIRESUPPRESSIONTERMINAL = 1426591983; -var IFCFIRESUPPRESSIONTERMINALTYPE = 4222183408; -var IFCFIXEDREFERENCESWEPTAREASOLID = 2652556860; -var IFCFLOWCONTROLLER = 2058353004; -var IFCFLOWCONTROLLERTYPE = 3907093117; -var IFCFLOWFITTING = 4278956645; -var IFCFLOWFITTINGTYPE = 3198132628; -var IFCFLOWINSTRUMENT = 182646315; -var IFCFLOWINSTRUMENTTYPE = 4037862832; -var IFCFLOWMETER = 2188021234; -var IFCFLOWMETERTYPE = 3815607619; -var IFCFLOWMOVINGDEVICE = 3132237377; -var IFCFLOWMOVINGDEVICETYPE = 1482959167; -var IFCFLOWSEGMENT = 987401354; -var IFCFLOWSEGMENTTYPE = 1834744321; -var IFCFLOWSTORAGEDEVICE = 707683696; -var IFCFLOWSTORAGEDEVICETYPE = 1339347760; -var IFCFLOWTERMINAL = 2223149337; -var IFCFLOWTERMINALTYPE = 2297155007; -var IFCFLOWTREATMENTDEVICE = 3508470533; -var IFCFLOWTREATMENTDEVICETYPE = 3009222698; -var IFCFOOTING = 900683007; -var IFCFOOTINGTYPE = 1893162501; -var IFCFURNISHINGELEMENT = 263784265; -var IFCFURNISHINGELEMENTTYPE = 4238390223; -var IFCFURNITURE = 1509553395; -var IFCFURNITURETYPE = 1268542332; -var IFCGEOGRAPHICELEMENT = 3493046030; -var IFCGEOGRAPHICELEMENTTYPE = 4095422895; -var IFCGEOMETRICCURVESET = 987898635; -var IFCGEOMETRICREPRESENTATIONCONTEXT = 3448662350; -var IFCGEOMETRICREPRESENTATIONITEM = 2453401579; -var IFCGEOMETRICREPRESENTATIONSUBCONTEXT = 4142052618; -var IFCGEOMETRICSET = 3590301190; -var IFCGRID = 3009204131; -var IFCGRIDAXIS = 852622518; -var IFCGRIDPLACEMENT = 178086475; -var IFCGROUP = 2706460486; -var IFCHALFSPACESOLID = 812098782; -var IFCHEATEXCHANGER = 3319311131; -var IFCHEATEXCHANGERTYPE = 1251058090; -var IFCHUMIDIFIER = 2068733104; -var IFCHUMIDIFIERTYPE = 1806887404; -var IFCISHAPEPROFILEDEF = 1484403080; -var IFCIMAGETEXTURE = 3905492369; -var IFCINDEXEDCOLOURMAP = 3570813810; -var IFCINDEXEDPOLYCURVE = 2571569899; -var IFCINDEXEDPOLYGONALFACE = 178912537; -var IFCINDEXEDPOLYGONALFACEWITHVOIDS = 2294589976; -var IFCINDEXEDTEXTUREMAP = 1437953363; -var IFCINDEXEDTRIANGLETEXTUREMAP = 2133299955; -var IFCINTERCEPTOR = 4175244083; -var IFCINTERCEPTORTYPE = 3946677679; -var IFCINTERSECTIONCURVE = 3113134337; -var IFCINVENTORY = 2391368822; -var IFCIRREGULARTIMESERIES = 3741457305; -var IFCIRREGULARTIMESERIESVALUE = 3020489413; -var IFCJUNCTIONBOX = 2176052936; -var IFCJUNCTIONBOXTYPE = 4288270099; -var IFCLSHAPEPROFILEDEF = 572779678; -var IFCLABORRESOURCE = 3827777499; -var IFCLABORRESOURCETYPE = 428585644; -var IFCLAGTIME = 1585845231; -var IFCLAMP = 76236018; -var IFCLAMPTYPE = 1051575348; -var IFCLIBRARYINFORMATION = 2655187982; -var IFCLIBRARYREFERENCE = 3452421091; -var IFCLIGHTDISTRIBUTIONDATA = 4162380809; -var IFCLIGHTFIXTURE = 629592764; -var IFCLIGHTFIXTURETYPE = 1161773419; -var IFCLIGHTINTENSITYDISTRIBUTION = 1566485204; -var IFCLIGHTSOURCE = 1402838566; -var IFCLIGHTSOURCEAMBIENT = 125510826; -var IFCLIGHTSOURCEDIRECTIONAL = 2604431987; -var IFCLIGHTSOURCEGONIOMETRIC = 4266656042; -var IFCLIGHTSOURCEPOSITIONAL = 1520743889; -var IFCLIGHTSOURCESPOT = 3422422726; -var IFCLINE = 1281925730; -var IFCLINESEGMENT2D = 3092502836; -var IFCLINEARPLACEMENT = 388784114; -var IFCLINEARPOSITIONINGELEMENT = 1154579445; -var IFCLOCALPLACEMENT = 2624227202; -var IFCLOOP = 1008929658; -var IFCMANIFOLDSOLIDBREP = 1425443689; -var IFCMAPCONVERSION = 3057273783; -var IFCMAPPEDITEM = 2347385850; -var IFCMATERIAL = 1838606355; -var IFCMATERIALCLASSIFICATIONRELATIONSHIP = 1847130766; -var IFCMATERIALCONSTITUENT = 3708119e3; -var IFCMATERIALCONSTITUENTSET = 2852063980; -var IFCMATERIALDEFINITION = 760658860; -var IFCMATERIALDEFINITIONREPRESENTATION = 2022407955; -var IFCMATERIALLAYER = 248100487; -var IFCMATERIALLAYERSET = 3303938423; -var IFCMATERIALLAYERSETUSAGE = 1303795690; -var IFCMATERIALLAYERWITHOFFSETS = 1847252529; -var IFCMATERIALLIST = 2199411900; -var IFCMATERIALPROFILE = 2235152071; -var IFCMATERIALPROFILESET = 164193824; -var IFCMATERIALPROFILESETUSAGE = 3079605661; -var IFCMATERIALPROFILESETUSAGETAPERING = 3404854881; -var IFCMATERIALPROFILEWITHOFFSETS = 552965576; -var IFCMATERIALPROPERTIES = 3265635763; -var IFCMATERIALRELATIONSHIP = 853536259; -var IFCMATERIALUSAGEDEFINITION = 1507914824; -var IFCMEASUREWITHUNIT = 2597039031; -var IFCMECHANICALFASTENER = 377706215; -var IFCMECHANICALFASTENERTYPE = 2108223431; -var IFCMEDICALDEVICE = 1437502449; -var IFCMEDICALDEVICETYPE = 1114901282; -var IFCMEMBER = 1073191201; -var IFCMEMBERSTANDARDCASE = 1911478936; -var IFCMEMBERTYPE = 3181161470; -var IFCMETRIC = 3368373690; -var IFCMIRROREDPROFILEDEF = 2998442950; -var IFCMONETARYUNIT = 2706619895; -var IFCMOTORCONNECTION = 2474470126; -var IFCMOTORCONNECTIONTYPE = 977012517; -var IFCNAMEDUNIT = 1918398963; -var IFCOBJECT = 3888040117; -var IFCOBJECTDEFINITION = 219451334; -var IFCOBJECTPLACEMENT = 3701648758; -var IFCOBJECTIVE = 2251480897; -var IFCOCCUPANT = 4143007308; -var IFCOFFSETCURVE = 590820931; -var IFCOFFSETCURVE2D = 3388369263; -var IFCOFFSETCURVE3D = 3505215534; -var IFCOFFSETCURVEBYDISTANCES = 2485787929; -var IFCOPENSHELL = 2665983363; -var IFCOPENINGELEMENT = 3588315303; -var IFCOPENINGSTANDARDCASE = 3079942009; -var IFCORGANIZATION = 4251960020; -var IFCORGANIZATIONRELATIONSHIP = 1411181986; -var IFCORIENTATIONEXPRESSION = 643959842; -var IFCORIENTEDEDGE = 1029017970; -var IFCOUTERBOUNDARYCURVE = 144952367; -var IFCOUTLET = 3694346114; -var IFCOUTLETTYPE = 2837617999; -var IFCOWNERHISTORY = 1207048766; -var IFCPARAMETERIZEDPROFILEDEF = 2529465313; -var IFCPATH = 2519244187; -var IFCPCURVE = 1682466193; -var IFCPERFORMANCEHISTORY = 2382730787; -var IFCPERMEABLECOVERINGPROPERTIES = 3566463478; -var IFCPERMIT = 3327091369; -var IFCPERSON = 2077209135; -var IFCPERSONANDORGANIZATION = 101040310; -var IFCPHYSICALCOMPLEXQUANTITY = 3021840470; -var IFCPHYSICALQUANTITY = 2483315170; -var IFCPHYSICALSIMPLEQUANTITY = 2226359599; -var IFCPILE = 1687234759; -var IFCPILETYPE = 1158309216; -var IFCPIPEFITTING = 310824031; -var IFCPIPEFITTINGTYPE = 804291784; -var IFCPIPESEGMENT = 3612865200; -var IFCPIPESEGMENTTYPE = 4231323485; -var IFCPIXELTEXTURE = 597895409; -var IFCPLACEMENT = 2004835150; -var IFCPLANARBOX = 603570806; -var IFCPLANAREXTENT = 1663979128; -var IFCPLANE = 220341763; -var IFCPLATE = 3171933400; -var IFCPLATESTANDARDCASE = 1156407060; -var IFCPLATETYPE = 4017108033; -var IFCPOINT = 2067069095; -var IFCPOINTONCURVE = 4022376103; -var IFCPOINTONSURFACE = 1423911732; -var IFCPOLYLOOP = 2924175390; -var IFCPOLYGONALBOUNDEDHALFSPACE = 2775532180; -var IFCPOLYGONALFACESET = 2839578677; -var IFCPOLYLINE = 3724593414; -var IFCPORT = 3740093272; -var IFCPOSITIONINGELEMENT = 1946335990; -var IFCPOSTALADDRESS = 3355820592; -var IFCPREDEFINEDCOLOUR = 759155922; -var IFCPREDEFINEDCURVEFONT = 2559016684; -var IFCPREDEFINEDITEM = 3727388367; -var IFCPREDEFINEDPROPERTIES = 3778827333; -var IFCPREDEFINEDPROPERTYSET = 3967405729; -var IFCPREDEFINEDTEXTFONT = 1775413392; -var IFCPRESENTATIONITEM = 677532197; -var IFCPRESENTATIONLAYERASSIGNMENT = 2022622350; -var IFCPRESENTATIONLAYERWITHSTYLE = 1304840413; -var IFCPRESENTATIONSTYLE = 3119450353; -var IFCPRESENTATIONSTYLEASSIGNMENT = 2417041796; -var IFCPROCEDURE = 2744685151; -var IFCPROCEDURETYPE = 569719735; -var IFCPROCESS = 2945172077; -var IFCPRODUCT = 4208778838; -var IFCPRODUCTDEFINITIONSHAPE = 673634403; -var IFCPRODUCTREPRESENTATION = 2095639259; -var IFCPROFILEDEF = 3958567839; -var IFCPROFILEPROPERTIES = 2802850158; -var IFCPROJECT = 103090709; -var IFCPROJECTLIBRARY = 653396225; -var IFCPROJECTORDER = 2904328755; -var IFCPROJECTEDCRS = 3843373140; -var IFCPROJECTIONELEMENT = 3651124850; -var IFCPROPERTY = 2598011224; -var IFCPROPERTYABSTRACTION = 986844984; -var IFCPROPERTYBOUNDEDVALUE = 871118103; -var IFCPROPERTYDEFINITION = 1680319473; -var IFCPROPERTYDEPENDENCYRELATIONSHIP = 148025276; -var IFCPROPERTYENUMERATEDVALUE = 4166981789; -var IFCPROPERTYENUMERATION = 3710013099; -var IFCPROPERTYLISTVALUE = 2752243245; -var IFCPROPERTYREFERENCEVALUE = 941946838; -var IFCPROPERTYSET = 1451395588; -var IFCPROPERTYSETDEFINITION = 3357820518; -var IFCPROPERTYSETTEMPLATE = 492091185; -var IFCPROPERTYSINGLEVALUE = 3650150729; -var IFCPROPERTYTABLEVALUE = 110355661; -var IFCPROPERTYTEMPLATE = 3521284610; -var IFCPROPERTYTEMPLATEDEFINITION = 1482703590; -var IFCPROTECTIVEDEVICE = 738039164; -var IFCPROTECTIVEDEVICETRIPPINGUNIT = 2295281155; -var IFCPROTECTIVEDEVICETRIPPINGUNITTYPE = 655969474; -var IFCPROTECTIVEDEVICETYPE = 1842657554; -var IFCPROXY = 3219374653; -var IFCPUMP = 90941305; -var IFCPUMPTYPE = 2250791053; -var IFCQUANTITYAREA = 2044713172; -var IFCQUANTITYCOUNT = 2093928680; -var IFCQUANTITYLENGTH = 931644368; -var IFCQUANTITYSET = 2090586900; -var IFCQUANTITYTIME = 3252649465; -var IFCQUANTITYVOLUME = 2405470396; -var IFCQUANTITYWEIGHT = 825690147; -var IFCRAILING = 2262370178; -var IFCRAILINGTYPE = 2893384427; -var IFCRAMP = 3024970846; -var IFCRAMPFLIGHT = 3283111854; -var IFCRAMPFLIGHTTYPE = 2324767716; -var IFCRAMPTYPE = 1469900589; -var IFCRATIONALBSPLINECURVEWITHKNOTS = 1232101972; -var IFCRATIONALBSPLINESURFACEWITHKNOTS = 683857671; -var IFCRECTANGLEHOLLOWPROFILEDEF = 2770003689; -var IFCRECTANGLEPROFILEDEF = 3615266464; -var IFCRECTANGULARPYRAMID = 2798486643; -var IFCRECTANGULARTRIMMEDSURFACE = 3454111270; -var IFCRECURRENCEPATTERN = 3915482550; -var IFCREFERENCE = 2433181523; -var IFCREFERENT = 4021432810; -var IFCREGULARTIMESERIES = 3413951693; -var IFCREINFORCEMENTBARPROPERTIES = 1580146022; -var IFCREINFORCEMENTDEFINITIONPROPERTIES = 3765753017; -var IFCREINFORCINGBAR = 979691226; -var IFCREINFORCINGBARTYPE = 2572171363; -var IFCREINFORCINGELEMENT = 3027567501; -var IFCREINFORCINGELEMENTTYPE = 964333572; -var IFCREINFORCINGMESH = 2320036040; -var IFCREINFORCINGMESHTYPE = 2310774935; -var IFCRELAGGREGATES = 160246688; -var IFCRELASSIGNS = 3939117080; -var IFCRELASSIGNSTOACTOR = 1683148259; -var IFCRELASSIGNSTOCONTROL = 2495723537; -var IFCRELASSIGNSTOGROUP = 1307041759; -var IFCRELASSIGNSTOGROUPBYFACTOR = 1027710054; -var IFCRELASSIGNSTOPROCESS = 4278684876; -var IFCRELASSIGNSTOPRODUCT = 2857406711; -var IFCRELASSIGNSTORESOURCE = 205026976; -var IFCRELASSOCIATES = 1865459582; -var IFCRELASSOCIATESAPPROVAL = 4095574036; -var IFCRELASSOCIATESCLASSIFICATION = 919958153; -var IFCRELASSOCIATESCONSTRAINT = 2728634034; -var IFCRELASSOCIATESDOCUMENT = 982818633; -var IFCRELASSOCIATESLIBRARY = 3840914261; -var IFCRELASSOCIATESMATERIAL = 2655215786; -var IFCRELCONNECTS = 826625072; -var IFCRELCONNECTSELEMENTS = 1204542856; -var IFCRELCONNECTSPATHELEMENTS = 3945020480; -var IFCRELCONNECTSPORTTOELEMENT = 4201705270; -var IFCRELCONNECTSPORTS = 3190031847; -var IFCRELCONNECTSSTRUCTURALACTIVITY = 2127690289; -var IFCRELCONNECTSSTRUCTURALMEMBER = 1638771189; -var IFCRELCONNECTSWITHECCENTRICITY = 504942748; -var IFCRELCONNECTSWITHREALIZINGELEMENTS = 3678494232; -var IFCRELCONTAINEDINSPATIALSTRUCTURE = 3242617779; -var IFCRELCOVERSBLDGELEMENTS = 886880790; -var IFCRELCOVERSSPACES = 2802773753; -var IFCRELDECLARES = 2565941209; -var IFCRELDECOMPOSES = 2551354335; -var IFCRELDEFINES = 693640335; -var IFCRELDEFINESBYOBJECT = 1462361463; -var IFCRELDEFINESBYPROPERTIES = 4186316022; -var IFCRELDEFINESBYTEMPLATE = 307848117; -var IFCRELDEFINESBYTYPE = 781010003; -var IFCRELFILLSELEMENT = 3940055652; -var IFCRELFLOWCONTROLELEMENTS = 279856033; -var IFCRELINTERFERESELEMENTS = 427948657; -var IFCRELNESTS = 3268803585; -var IFCRELPOSITIONS = 1441486842; -var IFCRELPROJECTSELEMENT = 750771296; -var IFCRELREFERENCEDINSPATIALSTRUCTURE = 1245217292; -var IFCRELSEQUENCE = 4122056220; -var IFCRELSERVICESBUILDINGS = 366585022; -var IFCRELSPACEBOUNDARY = 3451746338; -var IFCRELSPACEBOUNDARY1STLEVEL = 3523091289; -var IFCRELSPACEBOUNDARY2NDLEVEL = 1521410863; -var IFCRELVOIDSELEMENT = 1401173127; -var IFCRELATIONSHIP = 478536968; -var IFCREPARAMETRISEDCOMPOSITECURVESEGMENT = 816062949; -var IFCREPRESENTATION = 1076942058; -var IFCREPRESENTATIONCONTEXT = 3377609919; -var IFCREPRESENTATIONITEM = 3008791417; -var IFCREPRESENTATIONMAP = 1660063152; -var IFCRESOURCE = 2914609552; -var IFCRESOURCEAPPROVALRELATIONSHIP = 2943643501; -var IFCRESOURCECONSTRAINTRELATIONSHIP = 1608871552; -var IFCRESOURCELEVELRELATIONSHIP = 2439245199; -var IFCRESOURCETIME = 1042787934; -var IFCREVOLVEDAREASOLID = 1856042241; -var IFCREVOLVEDAREASOLIDTAPERED = 3243963512; -var IFCRIGHTCIRCULARCONE = 4158566097; -var IFCRIGHTCIRCULARCYLINDER = 3626867408; -var IFCROOF = 2016517767; -var IFCROOFTYPE = 2781568857; -var IFCROOT = 2341007311; -var IFCROUNDEDRECTANGLEPROFILEDEF = 2778083089; -var IFCSIUNIT = 448429030; -var IFCSANITARYTERMINAL = 3053780830; -var IFCSANITARYTERMINALTYPE = 1768891740; -var IFCSCHEDULINGTIME = 1054537805; -var IFCSEAMCURVE = 2157484638; -var IFCSECTIONPROPERTIES = 2042790032; -var IFCSECTIONREINFORCEMENTPROPERTIES = 4165799628; -var IFCSECTIONEDSOLID = 1862484736; -var IFCSECTIONEDSOLIDHORIZONTAL = 1290935644; -var IFCSECTIONEDSPINE = 1509187699; -var IFCSENSOR = 4086658281; -var IFCSENSORTYPE = 1783015770; -var IFCSHADINGDEVICE = 1329646415; -var IFCSHADINGDEVICETYPE = 4074543187; -var IFCSHAPEASPECT = 867548509; -var IFCSHAPEMODEL = 3982875396; -var IFCSHAPEREPRESENTATION = 4240577450; -var IFCSHELLBASEDSURFACEMODEL = 4124623270; -var IFCSIMPLEPROPERTY = 3692461612; -var IFCSIMPLEPROPERTYTEMPLATE = 3663146110; -var IFCSITE = 4097777520; -var IFCSLAB = 1529196076; -var IFCSLABELEMENTEDCASE = 3127900445; -var IFCSLABSTANDARDCASE = 3027962421; -var IFCSLABTYPE = 2533589738; -var IFCSLIPPAGECONNECTIONCONDITION = 2609359061; -var IFCSOLARDEVICE = 3420628829; -var IFCSOLARDEVICETYPE = 1072016465; -var IFCSOLIDMODEL = 723233188; -var IFCSPACE = 3856911033; -var IFCSPACEHEATER = 1999602285; -var IFCSPACEHEATERTYPE = 1305183839; -var IFCSPACETYPE = 3812236995; -var IFCSPATIALELEMENT = 1412071761; -var IFCSPATIALELEMENTTYPE = 710998568; -var IFCSPATIALSTRUCTUREELEMENT = 2706606064; -var IFCSPATIALSTRUCTUREELEMENTTYPE = 3893378262; -var IFCSPATIALZONE = 463610769; -var IFCSPATIALZONETYPE = 2481509218; -var IFCSPHERE = 451544542; -var IFCSPHERICALSURFACE = 4015995234; -var IFCSTACKTERMINAL = 1404847402; -var IFCSTACKTERMINALTYPE = 3112655638; -var IFCSTAIR = 331165859; -var IFCSTAIRFLIGHT = 4252922144; -var IFCSTAIRFLIGHTTYPE = 1039846685; -var IFCSTAIRTYPE = 338393293; -var IFCSTRUCTURALACTION = 682877961; -var IFCSTRUCTURALACTIVITY = 3544373492; -var IFCSTRUCTURALANALYSISMODEL = 2515109513; -var IFCSTRUCTURALCONNECTION = 1179482911; -var IFCSTRUCTURALCONNECTIONCONDITION = 2273995522; -var IFCSTRUCTURALCURVEACTION = 1004757350; -var IFCSTRUCTURALCURVECONNECTION = 4243806635; -var IFCSTRUCTURALCURVEMEMBER = 214636428; -var IFCSTRUCTURALCURVEMEMBERVARYING = 2445595289; -var IFCSTRUCTURALCURVEREACTION = 2757150158; -var IFCSTRUCTURALITEM = 3136571912; -var IFCSTRUCTURALLINEARACTION = 1807405624; -var IFCSTRUCTURALLOAD = 2162789131; -var IFCSTRUCTURALLOADCASE = 385403989; -var IFCSTRUCTURALLOADCONFIGURATION = 3478079324; -var IFCSTRUCTURALLOADGROUP = 1252848954; -var IFCSTRUCTURALLOADLINEARFORCE = 1595516126; -var IFCSTRUCTURALLOADORRESULT = 609421318; -var IFCSTRUCTURALLOADPLANARFORCE = 2668620305; -var IFCSTRUCTURALLOADSINGLEDISPLACEMENT = 2473145415; -var IFCSTRUCTURALLOADSINGLEDISPLACEMENTDISTORTION = 1973038258; -var IFCSTRUCTURALLOADSINGLEFORCE = 1597423693; -var IFCSTRUCTURALLOADSINGLEFORCEWARPING = 1190533807; -var IFCSTRUCTURALLOADSTATIC = 2525727697; -var IFCSTRUCTURALLOADTEMPERATURE = 3408363356; -var IFCSTRUCTURALMEMBER = 530289379; -var IFCSTRUCTURALPLANARACTION = 1621171031; -var IFCSTRUCTURALPOINTACTION = 2082059205; -var IFCSTRUCTURALPOINTCONNECTION = 734778138; -var IFCSTRUCTURALPOINTREACTION = 1235345126; -var IFCSTRUCTURALREACTION = 3689010777; -var IFCSTRUCTURALRESULTGROUP = 2986769608; -var IFCSTRUCTURALSURFACEACTION = 3657597509; -var IFCSTRUCTURALSURFACECONNECTION = 1975003073; -var IFCSTRUCTURALSURFACEMEMBER = 3979015343; -var IFCSTRUCTURALSURFACEMEMBERVARYING = 2218152070; -var IFCSTRUCTURALSURFACEREACTION = 603775116; -var IFCSTYLEMODEL = 2830218821; -var IFCSTYLEDITEM = 3958052878; -var IFCSTYLEDREPRESENTATION = 3049322572; -var IFCSUBCONTRACTRESOURCE = 148013059; -var IFCSUBCONTRACTRESOURCETYPE = 4095615324; -var IFCSUBEDGE = 2233826070; -var IFCSURFACE = 2513912981; -var IFCSURFACECURVE = 699246055; -var IFCSURFACECURVESWEPTAREASOLID = 2028607225; -var IFCSURFACEFEATURE = 3101698114; -var IFCSURFACEOFLINEAREXTRUSION = 2809605785; -var IFCSURFACEOFREVOLUTION = 4124788165; -var IFCSURFACEREINFORCEMENTAREA = 2934153892; -var IFCSURFACESTYLE = 1300840506; -var IFCSURFACESTYLELIGHTING = 3303107099; -var IFCSURFACESTYLEREFRACTION = 1607154358; -var IFCSURFACESTYLERENDERING = 1878645084; -var IFCSURFACESTYLESHADING = 846575682; -var IFCSURFACESTYLEWITHTEXTURES = 1351298697; -var IFCSURFACETEXTURE = 626085974; -var IFCSWEPTAREASOLID = 2247615214; -var IFCSWEPTDISKSOLID = 1260650574; -var IFCSWEPTDISKSOLIDPOLYGONAL = 1096409881; -var IFCSWEPTSURFACE = 230924584; -var IFCSWITCHINGDEVICE = 1162798199; -var IFCSWITCHINGDEVICETYPE = 2315554128; -var IFCSYSTEM = 2254336722; -var IFCSYSTEMFURNITUREELEMENT = 413509423; -var IFCSYSTEMFURNITUREELEMENTTYPE = 1580310250; -var IFCTSHAPEPROFILEDEF = 3071757647; -var IFCTABLE = 985171141; -var IFCTABLECOLUMN = 2043862942; -var IFCTABLEROW = 531007025; -var IFCTANK = 812556717; -var IFCTANKTYPE = 5716631; -var IFCTASK = 3473067441; -var IFCTASKTIME = 1549132990; -var IFCTASKTIMERECURRING = 2771591690; -var IFCTASKTYPE = 3206491090; -var IFCTELECOMADDRESS = 912023232; -var IFCTENDON = 3824725483; -var IFCTENDONANCHOR = 2347447852; -var IFCTENDONANCHORTYPE = 3081323446; -var IFCTENDONCONDUIT = 3663046924; -var IFCTENDONCONDUITTYPE = 2281632017; -var IFCTENDONTYPE = 2415094496; -var IFCTESSELLATEDFACESET = 2387106220; -var IFCTESSELLATEDITEM = 901063453; -var IFCTEXTLITERAL = 4282788508; -var IFCTEXTLITERALWITHEXTENT = 3124975700; -var IFCTEXTSTYLE = 1447204868; -var IFCTEXTSTYLEFONTMODEL = 1983826977; -var IFCTEXTSTYLEFORDEFINEDFONT = 2636378356; -var IFCTEXTSTYLETEXTMODEL = 1640371178; -var IFCTEXTURECOORDINATE = 280115917; -var IFCTEXTURECOORDINATEGENERATOR = 1742049831; -var IFCTEXTUREMAP = 2552916305; -var IFCTEXTUREVERTEX = 1210645708; -var IFCTEXTUREVERTEXLIST = 3611470254; -var IFCTIMEPERIOD = 1199560280; -var IFCTIMESERIES = 3101149627; -var IFCTIMESERIESVALUE = 581633288; -var IFCTOPOLOGICALREPRESENTATIONITEM = 1377556343; -var IFCTOPOLOGYREPRESENTATION = 1735638870; -var IFCTOROIDALSURFACE = 1935646853; -var IFCTRANSFORMER = 3825984169; -var IFCTRANSFORMERTYPE = 1692211062; -var IFCTRANSITIONCURVESEGMENT2D = 2595432518; -var IFCTRANSPORTELEMENT = 1620046519; -var IFCTRANSPORTELEMENTTYPE = 2097647324; -var IFCTRAPEZIUMPROFILEDEF = 2715220739; -var IFCTRIANGULATEDFACESET = 2916149573; -var IFCTRIANGULATEDIRREGULARNETWORK = 1229763772; -var IFCTRIMMEDCURVE = 3593883385; -var IFCTUBEBUNDLE = 3026737570; -var IFCTUBEBUNDLETYPE = 1600972822; -var IFCTYPEOBJECT = 1628702193; -var IFCTYPEPROCESS = 3736923433; -var IFCTYPEPRODUCT = 2347495698; -var IFCTYPERESOURCE = 3698973494; -var IFCUSHAPEPROFILEDEF = 427810014; -var IFCUNITASSIGNMENT = 180925521; -var IFCUNITARYCONTROLELEMENT = 630975310; -var IFCUNITARYCONTROLELEMENTTYPE = 3179687236; -var IFCUNITARYEQUIPMENT = 4292641817; -var IFCUNITARYEQUIPMENTTYPE = 1911125066; -var IFCVALVE = 4207607924; -var IFCVALVETYPE = 728799441; -var IFCVECTOR = 1417489154; -var IFCVERTEX = 2799835756; -var IFCVERTEXLOOP = 2759199220; -var IFCVERTEXPOINT = 1907098498; -var IFCVIBRATIONDAMPER = 1530820697; -var IFCVIBRATIONDAMPERTYPE = 3956297820; -var IFCVIBRATIONISOLATOR = 2391383451; -var IFCVIBRATIONISOLATORTYPE = 3313531582; -var IFCVIRTUALELEMENT = 2769231204; -var IFCVIRTUALGRIDINTERSECTION = 891718957; -var IFCVOIDINGFEATURE = 926996030; -var IFCWALL = 2391406946; -var IFCWALLELEMENTEDCASE = 4156078855; -var IFCWALLSTANDARDCASE = 3512223829; -var IFCWALLTYPE = 1898987631; -var IFCWASTETERMINAL = 4237592921; -var IFCWASTETERMINALTYPE = 1133259667; -var IFCWINDOW = 3304561284; -var IFCWINDOWLININGPROPERTIES = 336235671; -var IFCWINDOWPANELPROPERTIES = 512836454; -var IFCWINDOWSTANDARDCASE = 486154966; -var IFCWINDOWSTYLE = 1299126871; -var IFCWINDOWTYPE = 4009809668; -var IFCWORKCALENDAR = 4088093105; -var IFCWORKCONTROL = 1028945134; -var IFCWORKPLAN = 4218914973; -var IFCWORKSCHEDULE = 3342526732; -var IFCWORKTIME = 1236880293; -var IFCZSHAPEPROFILEDEF = 2543172580; -var IFCZONE = 1033361043; -var IfcElements = [ - IFCACTUATOR, - IFCAIRTERMINAL, - IFCAIRTERMINALBOX, - IFCAIRTOAIRHEATRECOVERY, - IFCALARM, - IFCALIGNMENT, - IFCANNOTATION, - IFCAUDIOVISUALAPPLIANCE, - IFCBEAM, - IFCBEAMSTANDARDCASE, - IFCBEARING, - IFCBOILER, - IFCBRIDGE, - IFCBRIDGEPART, - IFCBUILDING, - IFCBUILDINGELEMENT, - IFCBUILDINGELEMENTPART, - IFCBUILDINGELEMENTPROXY, - IFCBUILDINGSTOREY, - IFCBURNER, - IFCCABLECARRIERFITTING, - IFCCABLECARRIERSEGMENT, - IFCCABLEFITTING, - IFCCABLESEGMENT, - IFCCAISSONFOUNDATION, - IFCCHILLER, - IFCCHIMNEY, - IFCCIVILELEMENT, - IFCCOIL, - IFCCOLUMN, - IFCCOLUMNSTANDARDCASE, - IFCCOMMUNICATIONSAPPLIANCE, - IFCCOMPRESSOR, - IFCCONDENSER, - IFCCONTROLLER, - IFCCOOLEDBEAM, - IFCCOOLINGTOWER, - IFCCOVERING, - IFCCURTAINWALL, - IFCDAMPER, - IFCDEEPFOUNDATION, - IFCDISCRETEACCESSORY, - IFCDISTRIBUTIONCHAMBERELEMENT, - IFCDISTRIBUTIONCONTROLELEMENT, - IFCDISTRIBUTIONELEMENT, - IFCDISTRIBUTIONFLOWELEMENT, - IFCDISTRIBUTIONPORT, - IFCDOOR, - IFCDOORSTANDARDCASE, - IFCDUCTFITTING, - IFCDUCTSEGMENT, - IFCDUCTSILENCER, - IFCELECTRICAPPLIANCE, - IFCELECTRICDISTRIBUTIONBOARD, - IFCELECTRICFLOWSTORAGEDEVICE, - IFCELECTRICGENERATOR, - IFCELECTRICMOTOR, - IFCELECTRICTIMECONTROL, - IFCELEMENT, - IFCELEMENTASSEMBLY, - IFCELEMENTCOMPONENT, - IFCENERGYCONVERSIONDEVICE, - IFCENGINE, - IFCEVAPORATIVECOOLER, - IFCEVAPORATOR, - IFCEXTERNALSPATIALELEMENT, - IFCEXTERNALSPATIALSTRUCTUREELEMENT, - IFCFACILITY, - IFCFACILITYPART, - IFCFAN, - IFCFASTENER, - IFCFEATUREELEMENT, - IFCFEATUREELEMENTADDITION, - IFCFEATUREELEMENTSUBTRACTION, - IFCFILTER, - IFCFIRESUPPRESSIONTERMINAL, - IFCFLOWCONTROLLER, - IFCFLOWFITTING, - IFCFLOWINSTRUMENT, - IFCFLOWMETER, - IFCFLOWMOVINGDEVICE, - IFCFLOWSEGMENT, - IFCFLOWSTORAGEDEVICE, - IFCFLOWTERMINAL, - IFCFLOWTREATMENTDEVICE, - IFCFOOTING, - IFCFURNISHINGELEMENT, - IFCFURNITURE, - IFCGEOGRAPHICELEMENT, - IFCGRID, - IFCHEATEXCHANGER, - IFCHUMIDIFIER, - IFCINTERCEPTOR, - IFCJUNCTIONBOX, - IFCLAMP, - IFCLIGHTFIXTURE, - IFCLINEARPOSITIONINGELEMENT, - IFCMECHANICALFASTENER, - IFCMEDICALDEVICE, - IFCMEMBER, - IFCMEMBERSTANDARDCASE, - IFCMOTORCONNECTION, - IFCOPENINGELEMENT, - IFCOPENINGSTANDARDCASE, - IFCOUTLET, - IFCPILE, - IFCPIPEFITTING, - IFCPIPESEGMENT, - IFCPLATE, - IFCPLATESTANDARDCASE, - IFCPORT, - IFCPOSITIONINGELEMENT, - IFCPROJECTIONELEMENT, - IFCPROTECTIVEDEVICE, - IFCPROTECTIVEDEVICETRIPPINGUNIT, - IFCPROXY, - IFCPUMP, - IFCRAILING, - IFCRAMP, - IFCRAMPFLIGHT, - IFCREFERENT, - IFCREINFORCINGBAR, - IFCREINFORCINGELEMENT, - IFCREINFORCINGMESH, - IFCROOF, - IFCSANITARYTERMINAL, - IFCSENSOR, - IFCSHADINGDEVICE, - IFCSITE, - IFCSLAB, - IFCSLABELEMENTEDCASE, - IFCSLABSTANDARDCASE, - IFCSOLARDEVICE, - IFCSPACE, - IFCSPACEHEATER, - IFCSPATIALELEMENT, - IFCSPATIALSTRUCTUREELEMENT, - IFCSPATIALZONE, - IFCSTACKTERMINAL, - IFCSTAIR, - IFCSTAIRFLIGHT, - IFCSTRUCTURALACTION, - IFCSTRUCTURALACTIVITY, - IFCSTRUCTURALCONNECTION, - IFCSTRUCTURALCURVEACTION, - IFCSTRUCTURALCURVECONNECTION, - IFCSTRUCTURALCURVEMEMBER, - IFCSTRUCTURALCURVEMEMBERVARYING, - IFCSTRUCTURALCURVEREACTION, - IFCSTRUCTURALITEM, - IFCSTRUCTURALLINEARACTION, - IFCSTRUCTURALMEMBER, - IFCSTRUCTURALPLANARACTION, - IFCSTRUCTURALPOINTACTION, - IFCSTRUCTURALPOINTCONNECTION, - IFCSTRUCTURALPOINTREACTION, - IFCSTRUCTURALREACTION, - IFCSTRUCTURALSURFACEACTION, - IFCSTRUCTURALSURFACECONNECTION, - IFCSTRUCTURALSURFACEMEMBER, - IFCSTRUCTURALSURFACEMEMBERVARYING, - IFCSTRUCTURALSURFACEREACTION, - IFCSURFACEFEATURE, - IFCSWITCHINGDEVICE, - IFCSYSTEMFURNITUREELEMENT, - IFCTANK, - IFCTENDON, - IFCTENDONANCHOR, - IFCTENDONCONDUIT, - IFCTRANSFORMER, - IFCTRANSPORTELEMENT, - IFCTUBEBUNDLE, - IFCUNITARYCONTROLELEMENT, - IFCUNITARYEQUIPMENT, - IFCVALVE, - IFCVIBRATIONDAMPER, - IFCVIBRATIONISOLATOR, - IFCVIRTUALELEMENT, - IFCVOIDINGFEATURE, - IFCWALL, - IFCWALLELEMENTEDCASE, - IFCWALLSTANDARDCASE, - IFCWASTETERMINAL, - IFCWINDOW, - IFCWINDOWSTANDARDCASE -]; - -// dist/ifc2x4_helper.ts -var FromRawLineData = {}; -FromRawLineData[IFCACTIONREQUEST] = (d) => { - return IfcActionRequest.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCACTOR] = (d) => { - return IfcActor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCACTORROLE] = (d) => { - return IfcActorRole.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCACTUATOR] = (d) => { - return IfcActuator.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCACTUATORTYPE] = (d) => { - return IfcActuatorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCADDRESS] = (d) => { - return IfcAddress.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCADVANCEDBREP] = (d) => { - return IfcAdvancedBrep.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCADVANCEDBREPWITHVOIDS] = (d) => { - return IfcAdvancedBrepWithVoids.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCADVANCEDFACE] = (d) => { - return IfcAdvancedFace.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAIRTERMINAL] = (d) => { - return IfcAirTerminal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAIRTERMINALBOX] = (d) => { - return IfcAirTerminalBox.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAIRTERMINALBOXTYPE] = (d) => { - return IfcAirTerminalBoxType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAIRTERMINALTYPE] = (d) => { - return IfcAirTerminalType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAIRTOAIRHEATRECOVERY] = (d) => { - return IfcAirToAirHeatRecovery.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAIRTOAIRHEATRECOVERYTYPE] = (d) => { - return IfcAirToAirHeatRecoveryType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALARM] = (d) => { - return IfcAlarm.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALARMTYPE] = (d) => { - return IfcAlarmType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT] = (d) => { - return IfcAlignment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DHORIZONTAL] = (d) => { - return IfcAlignment2DHorizontal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DHORIZONTALSEGMENT] = (d) => { - return IfcAlignment2DHorizontalSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DSEGMENT] = (d) => { - return IfcAlignment2DSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DVERSEGCIRCULARARC] = (d) => { - return IfcAlignment2DVerSegCircularArc.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DVERSEGLINE] = (d) => { - return IfcAlignment2DVerSegLine.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DVERSEGPARABOLICARC] = (d) => { - return IfcAlignment2DVerSegParabolicArc.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DVERTICAL] = (d) => { - return IfcAlignment2DVertical.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENT2DVERTICALSEGMENT] = (d) => { - return IfcAlignment2DVerticalSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCALIGNMENTCURVE] = (d) => { - return IfcAlignmentCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCANNOTATION] = (d) => { - return IfcAnnotation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCANNOTATIONFILLAREA] = (d) => { - return IfcAnnotationFillArea.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAPPLICATION] = (d) => { - return IfcApplication.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAPPLIEDVALUE] = (d) => { - return IfcAppliedValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAPPROVAL] = (d) => { - return IfcApproval.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAPPROVALRELATIONSHIP] = (d) => { - return IfcApprovalRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCARBITRARYCLOSEDPROFILEDEF] = (d) => { - return IfcArbitraryClosedProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCARBITRARYOPENPROFILEDEF] = (d) => { - return IfcArbitraryOpenProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCARBITRARYPROFILEDEFWITHVOIDS] = (d) => { - return IfcArbitraryProfileDefWithVoids.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCASSET] = (d) => { - return IfcAsset.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCASYMMETRICISHAPEPROFILEDEF] = (d) => { - return IfcAsymmetricIShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAUDIOVISUALAPPLIANCE] = (d) => { - return IfcAudioVisualAppliance.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAUDIOVISUALAPPLIANCETYPE] = (d) => { - return IfcAudioVisualApplianceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAXIS1PLACEMENT] = (d) => { - return IfcAxis1Placement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAXIS2PLACEMENT2D] = (d) => { - return IfcAxis2Placement2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCAXIS2PLACEMENT3D] = (d) => { - return IfcAxis2Placement3D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBSPLINECURVE] = (d) => { - return IfcBSplineCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBSPLINECURVEWITHKNOTS] = (d) => { - return IfcBSplineCurveWithKnots.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBSPLINESURFACE] = (d) => { - return IfcBSplineSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBSPLINESURFACEWITHKNOTS] = (d) => { - return IfcBSplineSurfaceWithKnots.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBEAM] = (d) => { - return IfcBeam.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBEAMSTANDARDCASE] = (d) => { - return IfcBeamStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBEAMTYPE] = (d) => { - return IfcBeamType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBEARING] = (d) => { - return IfcBearing.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBEARINGTYPE] = (d) => { - return IfcBearingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBLOBTEXTURE] = (d) => { - return IfcBlobTexture.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBLOCK] = (d) => { - return IfcBlock.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOILER] = (d) => { - return IfcBoiler.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOILERTYPE] = (d) => { - return IfcBoilerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOOLEANCLIPPINGRESULT] = (d) => { - return IfcBooleanClippingResult.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOOLEANRESULT] = (d) => { - return IfcBooleanResult.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDARYCONDITION] = (d) => { - return IfcBoundaryCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDARYCURVE] = (d) => { - return IfcBoundaryCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDARYEDGECONDITION] = (d) => { - return IfcBoundaryEdgeCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDARYFACECONDITION] = (d) => { - return IfcBoundaryFaceCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDARYNODECONDITION] = (d) => { - return IfcBoundaryNodeCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDARYNODECONDITIONWARPING] = (d) => { - return IfcBoundaryNodeConditionWarping.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDEDCURVE] = (d) => { - return IfcBoundedCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDEDSURFACE] = (d) => { - return IfcBoundedSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOUNDINGBOX] = (d) => { - return IfcBoundingBox.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBOXEDHALFSPACE] = (d) => { - return IfcBoxedHalfSpace.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBRIDGE] = (d) => { - return IfcBridge.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBRIDGEPART] = (d) => { - return IfcBridgePart.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDING] = (d) => { - return IfcBuilding.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGELEMENT] = (d) => { - return IfcBuildingElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGELEMENTPART] = (d) => { - return IfcBuildingElementPart.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGELEMENTPARTTYPE] = (d) => { - return IfcBuildingElementPartType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGELEMENTPROXY] = (d) => { - return IfcBuildingElementProxy.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGELEMENTPROXYTYPE] = (d) => { - return IfcBuildingElementProxyType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGELEMENTTYPE] = (d) => { - return IfcBuildingElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGSTOREY] = (d) => { - return IfcBuildingStorey.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBUILDINGSYSTEM] = (d) => { - return IfcBuildingSystem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBURNER] = (d) => { - return IfcBurner.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCBURNERTYPE] = (d) => { - return IfcBurnerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCSHAPEPROFILEDEF] = (d) => { - return IfcCShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLECARRIERFITTING] = (d) => { - return IfcCableCarrierFitting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLECARRIERFITTINGTYPE] = (d) => { - return IfcCableCarrierFittingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLECARRIERSEGMENT] = (d) => { - return IfcCableCarrierSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLECARRIERSEGMENTTYPE] = (d) => { - return IfcCableCarrierSegmentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLEFITTING] = (d) => { - return IfcCableFitting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLEFITTINGTYPE] = (d) => { - return IfcCableFittingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLESEGMENT] = (d) => { - return IfcCableSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCABLESEGMENTTYPE] = (d) => { - return IfcCableSegmentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCAISSONFOUNDATION] = (d) => { - return IfcCaissonFoundation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCAISSONFOUNDATIONTYPE] = (d) => { - return IfcCaissonFoundationType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANPOINT] = (d) => { - return IfcCartesianPoint.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANPOINTLIST] = (d) => { - return IfcCartesianPointList.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANPOINTLIST2D] = (d) => { - return IfcCartesianPointList2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANPOINTLIST3D] = (d) => { - return IfcCartesianPointList3D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR] = (d) => { - return IfcCartesianTransformationOperator.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR2D] = (d) => { - return IfcCartesianTransformationOperator2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR2DNONUNIFORM] = (d) => { - return IfcCartesianTransformationOperator2DnonUniform.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR3D] = (d) => { - return IfcCartesianTransformationOperator3D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM] = (d) => { - return IfcCartesianTransformationOperator3DnonUniform.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCENTERLINEPROFILEDEF] = (d) => { - return IfcCenterLineProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCHILLER] = (d) => { - return IfcChiller.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCHILLERTYPE] = (d) => { - return IfcChillerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCHIMNEY] = (d) => { - return IfcChimney.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCHIMNEYTYPE] = (d) => { - return IfcChimneyType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCIRCLE] = (d) => { - return IfcCircle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCIRCLEHOLLOWPROFILEDEF] = (d) => { - return IfcCircleHollowProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCIRCLEPROFILEDEF] = (d) => { - return IfcCircleProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCIRCULARARCSEGMENT2D] = (d) => { - return IfcCircularArcSegment2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCIVILELEMENT] = (d) => { - return IfcCivilElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCIVILELEMENTTYPE] = (d) => { - return IfcCivilElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCLASSIFICATION] = (d) => { - return IfcClassification.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCLASSIFICATIONREFERENCE] = (d) => { - return IfcClassificationReference.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCLOSEDSHELL] = (d) => { - return IfcClosedShell.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOIL] = (d) => { - return IfcCoil.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOILTYPE] = (d) => { - return IfcCoilType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOLOURRGB] = (d) => { - return IfcColourRgb.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOLOURRGBLIST] = (d) => { - return IfcColourRgbList.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOLOURSPECIFICATION] = (d) => { - return IfcColourSpecification.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOLUMN] = (d) => { - return IfcColumn.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOLUMNSTANDARDCASE] = (d) => { - return IfcColumnStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOLUMNTYPE] = (d) => { - return IfcColumnType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMMUNICATIONSAPPLIANCE] = (d) => { - return IfcCommunicationsAppliance.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMMUNICATIONSAPPLIANCETYPE] = (d) => { - return IfcCommunicationsApplianceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPLEXPROPERTY] = (d) => { - return IfcComplexProperty.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPLEXPROPERTYTEMPLATE] = (d) => { - return IfcComplexPropertyTemplate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPOSITECURVE] = (d) => { - return IfcCompositeCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPOSITECURVEONSURFACE] = (d) => { - return IfcCompositeCurveOnSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPOSITECURVESEGMENT] = (d) => { - return IfcCompositeCurveSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPOSITEPROFILEDEF] = (d) => { - return IfcCompositeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPRESSOR] = (d) => { - return IfcCompressor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOMPRESSORTYPE] = (d) => { - return IfcCompressorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONDENSER] = (d) => { - return IfcCondenser.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONDENSERTYPE] = (d) => { - return IfcCondenserType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONIC] = (d) => { - return IfcConic.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTEDFACESET] = (d) => { - return IfcConnectedFaceSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTIONCURVEGEOMETRY] = (d) => { - return IfcConnectionCurveGeometry.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTIONGEOMETRY] = (d) => { - return IfcConnectionGeometry.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTIONPOINTECCENTRICITY] = (d) => { - return IfcConnectionPointEccentricity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTIONPOINTGEOMETRY] = (d) => { - return IfcConnectionPointGeometry.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTIONSURFACEGEOMETRY] = (d) => { - return IfcConnectionSurfaceGeometry.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONNECTIONVOLUMEGEOMETRY] = (d) => { - return IfcConnectionVolumeGeometry.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRAINT] = (d) => { - return IfcConstraint.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONEQUIPMENTRESOURCE] = (d) => { - return IfcConstructionEquipmentResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONEQUIPMENTRESOURCETYPE] = (d) => { - return IfcConstructionEquipmentResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONMATERIALRESOURCE] = (d) => { - return IfcConstructionMaterialResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONMATERIALRESOURCETYPE] = (d) => { - return IfcConstructionMaterialResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONPRODUCTRESOURCE] = (d) => { - return IfcConstructionProductResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONPRODUCTRESOURCETYPE] = (d) => { - return IfcConstructionProductResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONRESOURCE] = (d) => { - return IfcConstructionResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONSTRUCTIONRESOURCETYPE] = (d) => { - return IfcConstructionResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONTEXT] = (d) => { - return IfcContext.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONTEXTDEPENDENTUNIT] = (d) => { - return IfcContextDependentUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONTROL] = (d) => { - return IfcControl.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONTROLLER] = (d) => { - return IfcController.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONTROLLERTYPE] = (d) => { - return IfcControllerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONVERSIONBASEDUNIT] = (d) => { - return IfcConversionBasedUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCONVERSIONBASEDUNITWITHOFFSET] = (d) => { - return IfcConversionBasedUnitWithOffset.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOOLEDBEAM] = (d) => { - return IfcCooledBeam.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOOLEDBEAMTYPE] = (d) => { - return IfcCooledBeamType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOOLINGTOWER] = (d) => { - return IfcCoolingTower.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOOLINGTOWERTYPE] = (d) => { - return IfcCoolingTowerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOORDINATEOPERATION] = (d) => { - return IfcCoordinateOperation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOORDINATEREFERENCESYSTEM] = (d) => { - return IfcCoordinateReferenceSystem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOSTITEM] = (d) => { - return IfcCostItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOSTSCHEDULE] = (d) => { - return IfcCostSchedule.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOSTVALUE] = (d) => { - return IfcCostValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOVERING] = (d) => { - return IfcCovering.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCOVERINGTYPE] = (d) => { - return IfcCoveringType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCREWRESOURCE] = (d) => { - return IfcCrewResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCREWRESOURCETYPE] = (d) => { - return IfcCrewResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCSGPRIMITIVE3D] = (d) => { - return IfcCsgPrimitive3D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCSGSOLID] = (d) => { - return IfcCsgSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURRENCYRELATIONSHIP] = (d) => { - return IfcCurrencyRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURTAINWALL] = (d) => { - return IfcCurtainWall.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURTAINWALLTYPE] = (d) => { - return IfcCurtainWallType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVE] = (d) => { - return IfcCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVEBOUNDEDPLANE] = (d) => { - return IfcCurveBoundedPlane.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVEBOUNDEDSURFACE] = (d) => { - return IfcCurveBoundedSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVESEGMENT2D] = (d) => { - return IfcCurveSegment2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVESTYLE] = (d) => { - return IfcCurveStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVESTYLEFONT] = (d) => { - return IfcCurveStyleFont.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVESTYLEFONTANDSCALING] = (d) => { - return IfcCurveStyleFontAndScaling.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCURVESTYLEFONTPATTERN] = (d) => { - return IfcCurveStyleFontPattern.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCCYLINDRICALSURFACE] = (d) => { - return IfcCylindricalSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDAMPER] = (d) => { - return IfcDamper.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDAMPERTYPE] = (d) => { - return IfcDamperType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDEEPFOUNDATION] = (d) => { - return IfcDeepFoundation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDEEPFOUNDATIONTYPE] = (d) => { - return IfcDeepFoundationType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDERIVEDPROFILEDEF] = (d) => { - return IfcDerivedProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDERIVEDUNIT] = (d) => { - return IfcDerivedUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDERIVEDUNITELEMENT] = (d) => { - return IfcDerivedUnitElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDIMENSIONALEXPONENTS] = (d) => { - return IfcDimensionalExponents.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDIRECTION] = (d) => { - return IfcDirection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISCRETEACCESSORY] = (d) => { - return IfcDiscreteAccessory.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISCRETEACCESSORYTYPE] = (d) => { - return IfcDiscreteAccessoryType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTANCEEXPRESSION] = (d) => { - return IfcDistanceExpression.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONCHAMBERELEMENT] = (d) => { - return IfcDistributionChamberElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONCHAMBERELEMENTTYPE] = (d) => { - return IfcDistributionChamberElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONCIRCUIT] = (d) => { - return IfcDistributionCircuit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONCONTROLELEMENT] = (d) => { - return IfcDistributionControlElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONCONTROLELEMENTTYPE] = (d) => { - return IfcDistributionControlElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONELEMENT] = (d) => { - return IfcDistributionElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONELEMENTTYPE] = (d) => { - return IfcDistributionElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONFLOWELEMENT] = (d) => { - return IfcDistributionFlowElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONFLOWELEMENTTYPE] = (d) => { - return IfcDistributionFlowElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONPORT] = (d) => { - return IfcDistributionPort.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDISTRIBUTIONSYSTEM] = (d) => { - return IfcDistributionSystem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOCUMENTINFORMATION] = (d) => { - return IfcDocumentInformation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOCUMENTINFORMATIONRELATIONSHIP] = (d) => { - return IfcDocumentInformationRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOCUMENTREFERENCE] = (d) => { - return IfcDocumentReference.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOOR] = (d) => { - return IfcDoor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOORLININGPROPERTIES] = (d) => { - return IfcDoorLiningProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOORPANELPROPERTIES] = (d) => { - return IfcDoorPanelProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOORSTANDARDCASE] = (d) => { - return IfcDoorStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOORSTYLE] = (d) => { - return IfcDoorStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDOORTYPE] = (d) => { - return IfcDoorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDRAUGHTINGPREDEFINEDCOLOUR] = (d) => { - return IfcDraughtingPreDefinedColour.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDRAUGHTINGPREDEFINEDCURVEFONT] = (d) => { - return IfcDraughtingPreDefinedCurveFont.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDUCTFITTING] = (d) => { - return IfcDuctFitting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDUCTFITTINGTYPE] = (d) => { - return IfcDuctFittingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDUCTSEGMENT] = (d) => { - return IfcDuctSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDUCTSEGMENTTYPE] = (d) => { - return IfcDuctSegmentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDUCTSILENCER] = (d) => { - return IfcDuctSilencer.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCDUCTSILENCERTYPE] = (d) => { - return IfcDuctSilencerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEDGE] = (d) => { - return IfcEdge.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEDGECURVE] = (d) => { - return IfcEdgeCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEDGELOOP] = (d) => { - return IfcEdgeLoop.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICAPPLIANCE] = (d) => { - return IfcElectricAppliance.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICAPPLIANCETYPE] = (d) => { - return IfcElectricApplianceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICDISTRIBUTIONBOARD] = (d) => { - return IfcElectricDistributionBoard.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICDISTRIBUTIONBOARDTYPE] = (d) => { - return IfcElectricDistributionBoardType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICFLOWSTORAGEDEVICE] = (d) => { - return IfcElectricFlowStorageDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICFLOWSTORAGEDEVICETYPE] = (d) => { - return IfcElectricFlowStorageDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICGENERATOR] = (d) => { - return IfcElectricGenerator.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICGENERATORTYPE] = (d) => { - return IfcElectricGeneratorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICMOTOR] = (d) => { - return IfcElectricMotor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICMOTORTYPE] = (d) => { - return IfcElectricMotorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICTIMECONTROL] = (d) => { - return IfcElectricTimeControl.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELECTRICTIMECONTROLTYPE] = (d) => { - return IfcElectricTimeControlType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENT] = (d) => { - return IfcElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTASSEMBLY] = (d) => { - return IfcElementAssembly.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTASSEMBLYTYPE] = (d) => { - return IfcElementAssemblyType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTCOMPONENT] = (d) => { - return IfcElementComponent.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTCOMPONENTTYPE] = (d) => { - return IfcElementComponentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTQUANTITY] = (d) => { - return IfcElementQuantity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTTYPE] = (d) => { - return IfcElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELEMENTARYSURFACE] = (d) => { - return IfcElementarySurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELLIPSE] = (d) => { - return IfcEllipse.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCELLIPSEPROFILEDEF] = (d) => { - return IfcEllipseProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCENERGYCONVERSIONDEVICE] = (d) => { - return IfcEnergyConversionDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCENERGYCONVERSIONDEVICETYPE] = (d) => { - return IfcEnergyConversionDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCENGINE] = (d) => { - return IfcEngine.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCENGINETYPE] = (d) => { - return IfcEngineType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVAPORATIVECOOLER] = (d) => { - return IfcEvaporativeCooler.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVAPORATIVECOOLERTYPE] = (d) => { - return IfcEvaporativeCoolerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVAPORATOR] = (d) => { - return IfcEvaporator.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVAPORATORTYPE] = (d) => { - return IfcEvaporatorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVENT] = (d) => { - return IfcEvent.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVENTTIME] = (d) => { - return IfcEventTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEVENTTYPE] = (d) => { - return IfcEventType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTENDEDPROPERTIES] = (d) => { - return IfcExtendedProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALINFORMATION] = (d) => { - return IfcExternalInformation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALREFERENCE] = (d) => { - return IfcExternalReference.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALREFERENCERELATIONSHIP] = (d) => { - return IfcExternalReferenceRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALSPATIALELEMENT] = (d) => { - return IfcExternalSpatialElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALSPATIALSTRUCTUREELEMENT] = (d) => { - return IfcExternalSpatialStructureElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALLYDEFINEDHATCHSTYLE] = (d) => { - return IfcExternallyDefinedHatchStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALLYDEFINEDSURFACESTYLE] = (d) => { - return IfcExternallyDefinedSurfaceStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTERNALLYDEFINEDTEXTFONT] = (d) => { - return IfcExternallyDefinedTextFont.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTRUDEDAREASOLID] = (d) => { - return IfcExtrudedAreaSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCEXTRUDEDAREASOLIDTAPERED] = (d) => { - return IfcExtrudedAreaSolidTapered.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACE] = (d) => { - return IfcFace.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACEBASEDSURFACEMODEL] = (d) => { - return IfcFaceBasedSurfaceModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACEBOUND] = (d) => { - return IfcFaceBound.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACEOUTERBOUND] = (d) => { - return IfcFaceOuterBound.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACESURFACE] = (d) => { - return IfcFaceSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACETEDBREP] = (d) => { - return IfcFacetedBrep.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACETEDBREPWITHVOIDS] = (d) => { - return IfcFacetedBrepWithVoids.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACILITY] = (d) => { - return IfcFacility.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFACILITYPART] = (d) => { - return IfcFacilityPart.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFAILURECONNECTIONCONDITION] = (d) => { - return IfcFailureConnectionCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFAN] = (d) => { - return IfcFan.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFANTYPE] = (d) => { - return IfcFanType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFASTENER] = (d) => { - return IfcFastener.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFASTENERTYPE] = (d) => { - return IfcFastenerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFEATUREELEMENT] = (d) => { - return IfcFeatureElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFEATUREELEMENTADDITION] = (d) => { - return IfcFeatureElementAddition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFEATUREELEMENTSUBTRACTION] = (d) => { - return IfcFeatureElementSubtraction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFILLAREASTYLE] = (d) => { - return IfcFillAreaStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFILLAREASTYLEHATCHING] = (d) => { - return IfcFillAreaStyleHatching.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFILLAREASTYLETILES] = (d) => { - return IfcFillAreaStyleTiles.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFILTER] = (d) => { - return IfcFilter.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFILTERTYPE] = (d) => { - return IfcFilterType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFIRESUPPRESSIONTERMINAL] = (d) => { - return IfcFireSuppressionTerminal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFIRESUPPRESSIONTERMINALTYPE] = (d) => { - return IfcFireSuppressionTerminalType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFIXEDREFERENCESWEPTAREASOLID] = (d) => { - return IfcFixedReferenceSweptAreaSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWCONTROLLER] = (d) => { - return IfcFlowController.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWCONTROLLERTYPE] = (d) => { - return IfcFlowControllerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWFITTING] = (d) => { - return IfcFlowFitting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWFITTINGTYPE] = (d) => { - return IfcFlowFittingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWINSTRUMENT] = (d) => { - return IfcFlowInstrument.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWINSTRUMENTTYPE] = (d) => { - return IfcFlowInstrumentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWMETER] = (d) => { - return IfcFlowMeter.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWMETERTYPE] = (d) => { - return IfcFlowMeterType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWMOVINGDEVICE] = (d) => { - return IfcFlowMovingDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWMOVINGDEVICETYPE] = (d) => { - return IfcFlowMovingDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWSEGMENT] = (d) => { - return IfcFlowSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWSEGMENTTYPE] = (d) => { - return IfcFlowSegmentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWSTORAGEDEVICE] = (d) => { - return IfcFlowStorageDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWSTORAGEDEVICETYPE] = (d) => { - return IfcFlowStorageDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWTERMINAL] = (d) => { - return IfcFlowTerminal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWTERMINALTYPE] = (d) => { - return IfcFlowTerminalType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWTREATMENTDEVICE] = (d) => { - return IfcFlowTreatmentDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFLOWTREATMENTDEVICETYPE] = (d) => { - return IfcFlowTreatmentDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFOOTING] = (d) => { - return IfcFooting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFOOTINGTYPE] = (d) => { - return IfcFootingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFURNISHINGELEMENT] = (d) => { - return IfcFurnishingElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFURNISHINGELEMENTTYPE] = (d) => { - return IfcFurnishingElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFURNITURE] = (d) => { - return IfcFurniture.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCFURNITURETYPE] = (d) => { - return IfcFurnitureType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOGRAPHICELEMENT] = (d) => { - return IfcGeographicElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOGRAPHICELEMENTTYPE] = (d) => { - return IfcGeographicElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOMETRICCURVESET] = (d) => { - return IfcGeometricCurveSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOMETRICREPRESENTATIONCONTEXT] = (d) => { - return IfcGeometricRepresentationContext.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOMETRICREPRESENTATIONITEM] = (d) => { - return IfcGeometricRepresentationItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOMETRICREPRESENTATIONSUBCONTEXT] = (d) => { - return IfcGeometricRepresentationSubContext.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGEOMETRICSET] = (d) => { - return IfcGeometricSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGRID] = (d) => { - return IfcGrid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGRIDAXIS] = (d) => { - return IfcGridAxis.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGRIDPLACEMENT] = (d) => { - return IfcGridPlacement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCGROUP] = (d) => { - return IfcGroup.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCHALFSPACESOLID] = (d) => { - return IfcHalfSpaceSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCHEATEXCHANGER] = (d) => { - return IfcHeatExchanger.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCHEATEXCHANGERTYPE] = (d) => { - return IfcHeatExchangerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCHUMIDIFIER] = (d) => { - return IfcHumidifier.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCHUMIDIFIERTYPE] = (d) => { - return IfcHumidifierType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCISHAPEPROFILEDEF] = (d) => { - return IfcIShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCIMAGETEXTURE] = (d) => { - return IfcImageTexture.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINDEXEDCOLOURMAP] = (d) => { - return IfcIndexedColourMap.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINDEXEDPOLYCURVE] = (d) => { - return IfcIndexedPolyCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINDEXEDPOLYGONALFACE] = (d) => { - return IfcIndexedPolygonalFace.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINDEXEDPOLYGONALFACEWITHVOIDS] = (d) => { - return IfcIndexedPolygonalFaceWithVoids.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINDEXEDTEXTUREMAP] = (d) => { - return IfcIndexedTextureMap.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINDEXEDTRIANGLETEXTUREMAP] = (d) => { - return IfcIndexedTriangleTextureMap.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINTERCEPTOR] = (d) => { - return IfcInterceptor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINTERCEPTORTYPE] = (d) => { - return IfcInterceptorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINTERSECTIONCURVE] = (d) => { - return IfcIntersectionCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCINVENTORY] = (d) => { - return IfcInventory.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCIRREGULARTIMESERIES] = (d) => { - return IfcIrregularTimeSeries.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCIRREGULARTIMESERIESVALUE] = (d) => { - return IfcIrregularTimeSeriesValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCJUNCTIONBOX] = (d) => { - return IfcJunctionBox.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCJUNCTIONBOXTYPE] = (d) => { - return IfcJunctionBoxType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLSHAPEPROFILEDEF] = (d) => { - return IfcLShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLABORRESOURCE] = (d) => { - return IfcLaborResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLABORRESOURCETYPE] = (d) => { - return IfcLaborResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLAGTIME] = (d) => { - return IfcLagTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLAMP] = (d) => { - return IfcLamp.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLAMPTYPE] = (d) => { - return IfcLampType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIBRARYINFORMATION] = (d) => { - return IfcLibraryInformation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIBRARYREFERENCE] = (d) => { - return IfcLibraryReference.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTDISTRIBUTIONDATA] = (d) => { - return IfcLightDistributionData.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTFIXTURE] = (d) => { - return IfcLightFixture.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTFIXTURETYPE] = (d) => { - return IfcLightFixtureType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTINTENSITYDISTRIBUTION] = (d) => { - return IfcLightIntensityDistribution.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTSOURCE] = (d) => { - return IfcLightSource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTSOURCEAMBIENT] = (d) => { - return IfcLightSourceAmbient.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTSOURCEDIRECTIONAL] = (d) => { - return IfcLightSourceDirectional.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTSOURCEGONIOMETRIC] = (d) => { - return IfcLightSourceGoniometric.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTSOURCEPOSITIONAL] = (d) => { - return IfcLightSourcePositional.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLIGHTSOURCESPOT] = (d) => { - return IfcLightSourceSpot.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLINE] = (d) => { - return IfcLine.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLINESEGMENT2D] = (d) => { - return IfcLineSegment2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLINEARPLACEMENT] = (d) => { - return IfcLinearPlacement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLINEARPOSITIONINGELEMENT] = (d) => { - return IfcLinearPositioningElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLOCALPLACEMENT] = (d) => { - return IfcLocalPlacement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCLOOP] = (d) => { - return IfcLoop.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMANIFOLDSOLIDBREP] = (d) => { - return IfcManifoldSolidBrep.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMAPCONVERSION] = (d) => { - return IfcMapConversion.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMAPPEDITEM] = (d) => { - return IfcMappedItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIAL] = (d) => { - return IfcMaterial.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALCLASSIFICATIONRELATIONSHIP] = (d) => { - return IfcMaterialClassificationRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALCONSTITUENT] = (d) => { - return IfcMaterialConstituent.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALCONSTITUENTSET] = (d) => { - return IfcMaterialConstituentSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALDEFINITION] = (d) => { - return IfcMaterialDefinition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALDEFINITIONREPRESENTATION] = (d) => { - return IfcMaterialDefinitionRepresentation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALLAYER] = (d) => { - return IfcMaterialLayer.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALLAYERSET] = (d) => { - return IfcMaterialLayerSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALLAYERSETUSAGE] = (d) => { - return IfcMaterialLayerSetUsage.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALLAYERWITHOFFSETS] = (d) => { - return IfcMaterialLayerWithOffsets.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALLIST] = (d) => { - return IfcMaterialList.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALPROFILE] = (d) => { - return IfcMaterialProfile.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALPROFILESET] = (d) => { - return IfcMaterialProfileSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALPROFILESETUSAGE] = (d) => { - return IfcMaterialProfileSetUsage.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALPROFILESETUSAGETAPERING] = (d) => { - return IfcMaterialProfileSetUsageTapering.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALPROFILEWITHOFFSETS] = (d) => { - return IfcMaterialProfileWithOffsets.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALPROPERTIES] = (d) => { - return IfcMaterialProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALRELATIONSHIP] = (d) => { - return IfcMaterialRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMATERIALUSAGEDEFINITION] = (d) => { - return IfcMaterialUsageDefinition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMEASUREWITHUNIT] = (d) => { - return IfcMeasureWithUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMECHANICALFASTENER] = (d) => { - return IfcMechanicalFastener.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMECHANICALFASTENERTYPE] = (d) => { - return IfcMechanicalFastenerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMEDICALDEVICE] = (d) => { - return IfcMedicalDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMEDICALDEVICETYPE] = (d) => { - return IfcMedicalDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMEMBER] = (d) => { - return IfcMember.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMEMBERSTANDARDCASE] = (d) => { - return IfcMemberStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMEMBERTYPE] = (d) => { - return IfcMemberType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMETRIC] = (d) => { - return IfcMetric.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMIRROREDPROFILEDEF] = (d) => { - return IfcMirroredProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMONETARYUNIT] = (d) => { - return IfcMonetaryUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMOTORCONNECTION] = (d) => { - return IfcMotorConnection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCMOTORCONNECTIONTYPE] = (d) => { - return IfcMotorConnectionType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCNAMEDUNIT] = (d) => { - return IfcNamedUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOBJECT] = (d) => { - return IfcObject.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOBJECTDEFINITION] = (d) => { - return IfcObjectDefinition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOBJECTPLACEMENT] = (d) => { - return IfcObjectPlacement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOBJECTIVE] = (d) => { - return IfcObjective.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOCCUPANT] = (d) => { - return IfcOccupant.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOFFSETCURVE] = (d) => { - return IfcOffsetCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOFFSETCURVE2D] = (d) => { - return IfcOffsetCurve2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOFFSETCURVE3D] = (d) => { - return IfcOffsetCurve3D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOFFSETCURVEBYDISTANCES] = (d) => { - return IfcOffsetCurveByDistances.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOPENSHELL] = (d) => { - return IfcOpenShell.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOPENINGELEMENT] = (d) => { - return IfcOpeningElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOPENINGSTANDARDCASE] = (d) => { - return IfcOpeningStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCORGANIZATION] = (d) => { - return IfcOrganization.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCORGANIZATIONRELATIONSHIP] = (d) => { - return IfcOrganizationRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCORIENTATIONEXPRESSION] = (d) => { - return IfcOrientationExpression.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCORIENTEDEDGE] = (d) => { - return IfcOrientedEdge.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOUTERBOUNDARYCURVE] = (d) => { - return IfcOuterBoundaryCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOUTLET] = (d) => { - return IfcOutlet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOUTLETTYPE] = (d) => { - return IfcOutletType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCOWNERHISTORY] = (d) => { - return IfcOwnerHistory.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPARAMETERIZEDPROFILEDEF] = (d) => { - return IfcParameterizedProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPATH] = (d) => { - return IfcPath.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPCURVE] = (d) => { - return IfcPcurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPERFORMANCEHISTORY] = (d) => { - return IfcPerformanceHistory.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPERMEABLECOVERINGPROPERTIES] = (d) => { - return IfcPermeableCoveringProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPERMIT] = (d) => { - return IfcPermit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPERSON] = (d) => { - return IfcPerson.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPERSONANDORGANIZATION] = (d) => { - return IfcPersonAndOrganization.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPHYSICALCOMPLEXQUANTITY] = (d) => { - return IfcPhysicalComplexQuantity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPHYSICALQUANTITY] = (d) => { - return IfcPhysicalQuantity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPHYSICALSIMPLEQUANTITY] = (d) => { - return IfcPhysicalSimpleQuantity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPILE] = (d) => { - return IfcPile.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPILETYPE] = (d) => { - return IfcPileType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPIPEFITTING] = (d) => { - return IfcPipeFitting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPIPEFITTINGTYPE] = (d) => { - return IfcPipeFittingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPIPESEGMENT] = (d) => { - return IfcPipeSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPIPESEGMENTTYPE] = (d) => { - return IfcPipeSegmentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPIXELTEXTURE] = (d) => { - return IfcPixelTexture.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLACEMENT] = (d) => { - return IfcPlacement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLANARBOX] = (d) => { - return IfcPlanarBox.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLANAREXTENT] = (d) => { - return IfcPlanarExtent.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLANE] = (d) => { - return IfcPlane.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLATE] = (d) => { - return IfcPlate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLATESTANDARDCASE] = (d) => { - return IfcPlateStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPLATETYPE] = (d) => { - return IfcPlateType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOINT] = (d) => { - return IfcPoint.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOINTONCURVE] = (d) => { - return IfcPointOnCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOINTONSURFACE] = (d) => { - return IfcPointOnSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOLYLOOP] = (d) => { - return IfcPolyLoop.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOLYGONALBOUNDEDHALFSPACE] = (d) => { - return IfcPolygonalBoundedHalfSpace.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOLYGONALFACESET] = (d) => { - return IfcPolygonalFaceSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOLYLINE] = (d) => { - return IfcPolyline.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPORT] = (d) => { - return IfcPort.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOSITIONINGELEMENT] = (d) => { - return IfcPositioningElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPOSTALADDRESS] = (d) => { - return IfcPostalAddress.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPREDEFINEDCOLOUR] = (d) => { - return IfcPreDefinedColour.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPREDEFINEDCURVEFONT] = (d) => { - return IfcPreDefinedCurveFont.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPREDEFINEDITEM] = (d) => { - return IfcPreDefinedItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPREDEFINEDPROPERTIES] = (d) => { - return IfcPreDefinedProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPREDEFINEDPROPERTYSET] = (d) => { - return IfcPreDefinedPropertySet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPREDEFINEDTEXTFONT] = (d) => { - return IfcPreDefinedTextFont.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRESENTATIONITEM] = (d) => { - return IfcPresentationItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRESENTATIONLAYERASSIGNMENT] = (d) => { - return IfcPresentationLayerAssignment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRESENTATIONLAYERWITHSTYLE] = (d) => { - return IfcPresentationLayerWithStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRESENTATIONSTYLE] = (d) => { - return IfcPresentationStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRESENTATIONSTYLEASSIGNMENT] = (d) => { - return IfcPresentationStyleAssignment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROCEDURE] = (d) => { - return IfcProcedure.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROCEDURETYPE] = (d) => { - return IfcProcedureType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROCESS] = (d) => { - return IfcProcess.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRODUCT] = (d) => { - return IfcProduct.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRODUCTDEFINITIONSHAPE] = (d) => { - return IfcProductDefinitionShape.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPRODUCTREPRESENTATION] = (d) => { - return IfcProductRepresentation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROFILEDEF] = (d) => { - return IfcProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROFILEPROPERTIES] = (d) => { - return IfcProfileProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROJECT] = (d) => { - return IfcProject.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROJECTLIBRARY] = (d) => { - return IfcProjectLibrary.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROJECTORDER] = (d) => { - return IfcProjectOrder.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROJECTEDCRS] = (d) => { - return IfcProjectedCRS.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROJECTIONELEMENT] = (d) => { - return IfcProjectionElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTY] = (d) => { - return IfcProperty.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYABSTRACTION] = (d) => { - return IfcPropertyAbstraction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYBOUNDEDVALUE] = (d) => { - return IfcPropertyBoundedValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYDEFINITION] = (d) => { - return IfcPropertyDefinition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYDEPENDENCYRELATIONSHIP] = (d) => { - return IfcPropertyDependencyRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYENUMERATEDVALUE] = (d) => { - return IfcPropertyEnumeratedValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYENUMERATION] = (d) => { - return IfcPropertyEnumeration.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYLISTVALUE] = (d) => { - return IfcPropertyListValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYREFERENCEVALUE] = (d) => { - return IfcPropertyReferenceValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYSET] = (d) => { - return IfcPropertySet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYSETDEFINITION] = (d) => { - return IfcPropertySetDefinition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYSETTEMPLATE] = (d) => { - return IfcPropertySetTemplate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYSINGLEVALUE] = (d) => { - return IfcPropertySingleValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYTABLEVALUE] = (d) => { - return IfcPropertyTableValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYTEMPLATE] = (d) => { - return IfcPropertyTemplate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROPERTYTEMPLATEDEFINITION] = (d) => { - return IfcPropertyTemplateDefinition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROTECTIVEDEVICE] = (d) => { - return IfcProtectiveDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROTECTIVEDEVICETRIPPINGUNIT] = (d) => { - return IfcProtectiveDeviceTrippingUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROTECTIVEDEVICETRIPPINGUNITTYPE] = (d) => { - return IfcProtectiveDeviceTrippingUnitType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROTECTIVEDEVICETYPE] = (d) => { - return IfcProtectiveDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPROXY] = (d) => { - return IfcProxy.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPUMP] = (d) => { - return IfcPump.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCPUMPTYPE] = (d) => { - return IfcPumpType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYAREA] = (d) => { - return IfcQuantityArea.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYCOUNT] = (d) => { - return IfcQuantityCount.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYLENGTH] = (d) => { - return IfcQuantityLength.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYSET] = (d) => { - return IfcQuantitySet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYTIME] = (d) => { - return IfcQuantityTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYVOLUME] = (d) => { - return IfcQuantityVolume.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCQUANTITYWEIGHT] = (d) => { - return IfcQuantityWeight.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRAILING] = (d) => { - return IfcRailing.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRAILINGTYPE] = (d) => { - return IfcRailingType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRAMP] = (d) => { - return IfcRamp.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRAMPFLIGHT] = (d) => { - return IfcRampFlight.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRAMPFLIGHTTYPE] = (d) => { - return IfcRampFlightType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRAMPTYPE] = (d) => { - return IfcRampType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRATIONALBSPLINECURVEWITHKNOTS] = (d) => { - return IfcRationalBSplineCurveWithKnots.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRATIONALBSPLINESURFACEWITHKNOTS] = (d) => { - return IfcRationalBSplineSurfaceWithKnots.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRECTANGLEHOLLOWPROFILEDEF] = (d) => { - return IfcRectangleHollowProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRECTANGLEPROFILEDEF] = (d) => { - return IfcRectangleProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRECTANGULARPYRAMID] = (d) => { - return IfcRectangularPyramid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRECTANGULARTRIMMEDSURFACE] = (d) => { - return IfcRectangularTrimmedSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRECURRENCEPATTERN] = (d) => { - return IfcRecurrencePattern.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREFERENCE] = (d) => { - return IfcReference.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREFERENT] = (d) => { - return IfcReferent.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREGULARTIMESERIES] = (d) => { - return IfcRegularTimeSeries.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCEMENTBARPROPERTIES] = (d) => { - return IfcReinforcementBarProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCEMENTDEFINITIONPROPERTIES] = (d) => { - return IfcReinforcementDefinitionProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCINGBAR] = (d) => { - return IfcReinforcingBar.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCINGBARTYPE] = (d) => { - return IfcReinforcingBarType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCINGELEMENT] = (d) => { - return IfcReinforcingElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCINGELEMENTTYPE] = (d) => { - return IfcReinforcingElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCINGMESH] = (d) => { - return IfcReinforcingMesh.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREINFORCINGMESHTYPE] = (d) => { - return IfcReinforcingMeshType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELAGGREGATES] = (d) => { - return IfcRelAggregates.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNS] = (d) => { - return IfcRelAssigns.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTOACTOR] = (d) => { - return IfcRelAssignsToActor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTOCONTROL] = (d) => { - return IfcRelAssignsToControl.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTOGROUP] = (d) => { - return IfcRelAssignsToGroup.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTOGROUPBYFACTOR] = (d) => { - return IfcRelAssignsToGroupByFactor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTOPROCESS] = (d) => { - return IfcRelAssignsToProcess.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTOPRODUCT] = (d) => { - return IfcRelAssignsToProduct.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSIGNSTORESOURCE] = (d) => { - return IfcRelAssignsToResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATES] = (d) => { - return IfcRelAssociates.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATESAPPROVAL] = (d) => { - return IfcRelAssociatesApproval.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATESCLASSIFICATION] = (d) => { - return IfcRelAssociatesClassification.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATESCONSTRAINT] = (d) => { - return IfcRelAssociatesConstraint.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATESDOCUMENT] = (d) => { - return IfcRelAssociatesDocument.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATESLIBRARY] = (d) => { - return IfcRelAssociatesLibrary.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELASSOCIATESMATERIAL] = (d) => { - return IfcRelAssociatesMaterial.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTS] = (d) => { - return IfcRelConnects.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSELEMENTS] = (d) => { - return IfcRelConnectsElements.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSPATHELEMENTS] = (d) => { - return IfcRelConnectsPathElements.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSPORTTOELEMENT] = (d) => { - return IfcRelConnectsPortToElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSPORTS] = (d) => { - return IfcRelConnectsPorts.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSSTRUCTURALACTIVITY] = (d) => { - return IfcRelConnectsStructuralActivity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSSTRUCTURALMEMBER] = (d) => { - return IfcRelConnectsStructuralMember.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSWITHECCENTRICITY] = (d) => { - return IfcRelConnectsWithEccentricity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONNECTSWITHREALIZINGELEMENTS] = (d) => { - return IfcRelConnectsWithRealizingElements.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCONTAINEDINSPATIALSTRUCTURE] = (d) => { - return IfcRelContainedInSpatialStructure.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCOVERSBLDGELEMENTS] = (d) => { - return IfcRelCoversBldgElements.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELCOVERSSPACES] = (d) => { - return IfcRelCoversSpaces.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDECLARES] = (d) => { - return IfcRelDeclares.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDECOMPOSES] = (d) => { - return IfcRelDecomposes.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDEFINES] = (d) => { - return IfcRelDefines.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDEFINESBYOBJECT] = (d) => { - return IfcRelDefinesByObject.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDEFINESBYPROPERTIES] = (d) => { - return IfcRelDefinesByProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDEFINESBYTEMPLATE] = (d) => { - return IfcRelDefinesByTemplate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELDEFINESBYTYPE] = (d) => { - return IfcRelDefinesByType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELFILLSELEMENT] = (d) => { - return IfcRelFillsElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELFLOWCONTROLELEMENTS] = (d) => { - return IfcRelFlowControlElements.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELINTERFERESELEMENTS] = (d) => { - return IfcRelInterferesElements.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELNESTS] = (d) => { - return IfcRelNests.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELPOSITIONS] = (d) => { - return IfcRelPositions.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELPROJECTSELEMENT] = (d) => { - return IfcRelProjectsElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELREFERENCEDINSPATIALSTRUCTURE] = (d) => { - return IfcRelReferencedInSpatialStructure.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELSEQUENCE] = (d) => { - return IfcRelSequence.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELSERVICESBUILDINGS] = (d) => { - return IfcRelServicesBuildings.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELSPACEBOUNDARY] = (d) => { - return IfcRelSpaceBoundary.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELSPACEBOUNDARY1STLEVEL] = (d) => { - return IfcRelSpaceBoundary1stLevel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELSPACEBOUNDARY2NDLEVEL] = (d) => { - return IfcRelSpaceBoundary2ndLevel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELVOIDSELEMENT] = (d) => { - return IfcRelVoidsElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRELATIONSHIP] = (d) => { - return IfcRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREPARAMETRISEDCOMPOSITECURVESEGMENT] = (d) => { - return IfcReparametrisedCompositeCurveSegment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREPRESENTATION] = (d) => { - return IfcRepresentation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREPRESENTATIONCONTEXT] = (d) => { - return IfcRepresentationContext.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREPRESENTATIONITEM] = (d) => { - return IfcRepresentationItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREPRESENTATIONMAP] = (d) => { - return IfcRepresentationMap.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRESOURCE] = (d) => { - return IfcResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRESOURCEAPPROVALRELATIONSHIP] = (d) => { - return IfcResourceApprovalRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRESOURCECONSTRAINTRELATIONSHIP] = (d) => { - return IfcResourceConstraintRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRESOURCELEVELRELATIONSHIP] = (d) => { - return IfcResourceLevelRelationship.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRESOURCETIME] = (d) => { - return IfcResourceTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREVOLVEDAREASOLID] = (d) => { - return IfcRevolvedAreaSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCREVOLVEDAREASOLIDTAPERED] = (d) => { - return IfcRevolvedAreaSolidTapered.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRIGHTCIRCULARCONE] = (d) => { - return IfcRightCircularCone.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCRIGHTCIRCULARCYLINDER] = (d) => { - return IfcRightCircularCylinder.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCROOF] = (d) => { - return IfcRoof.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCROOFTYPE] = (d) => { - return IfcRoofType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCROOT] = (d) => { - return IfcRoot.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCROUNDEDRECTANGLEPROFILEDEF] = (d) => { - return IfcRoundedRectangleProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSIUNIT] = (d) => { - return IfcSIUnit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSANITARYTERMINAL] = (d) => { - return IfcSanitaryTerminal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSANITARYTERMINALTYPE] = (d) => { - return IfcSanitaryTerminalType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSCHEDULINGTIME] = (d) => { - return IfcSchedulingTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSEAMCURVE] = (d) => { - return IfcSeamCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSECTIONPROPERTIES] = (d) => { - return IfcSectionProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSECTIONREINFORCEMENTPROPERTIES] = (d) => { - return IfcSectionReinforcementProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSECTIONEDSOLID] = (d) => { - return IfcSectionedSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSECTIONEDSOLIDHORIZONTAL] = (d) => { - return IfcSectionedSolidHorizontal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSECTIONEDSPINE] = (d) => { - return IfcSectionedSpine.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSENSOR] = (d) => { - return IfcSensor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSENSORTYPE] = (d) => { - return IfcSensorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSHADINGDEVICE] = (d) => { - return IfcShadingDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSHADINGDEVICETYPE] = (d) => { - return IfcShadingDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSHAPEASPECT] = (d) => { - return IfcShapeAspect.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSHAPEMODEL] = (d) => { - return IfcShapeModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSHAPEREPRESENTATION] = (d) => { - return IfcShapeRepresentation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSHELLBASEDSURFACEMODEL] = (d) => { - return IfcShellBasedSurfaceModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSIMPLEPROPERTY] = (d) => { - return IfcSimpleProperty.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSIMPLEPROPERTYTEMPLATE] = (d) => { - return IfcSimplePropertyTemplate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSITE] = (d) => { - return IfcSite.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSLAB] = (d) => { - return IfcSlab.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSLABELEMENTEDCASE] = (d) => { - return IfcSlabElementedCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSLABSTANDARDCASE] = (d) => { - return IfcSlabStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSLABTYPE] = (d) => { - return IfcSlabType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSLIPPAGECONNECTIONCONDITION] = (d) => { - return IfcSlippageConnectionCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSOLARDEVICE] = (d) => { - return IfcSolarDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSOLARDEVICETYPE] = (d) => { - return IfcSolarDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSOLIDMODEL] = (d) => { - return IfcSolidModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPACE] = (d) => { - return IfcSpace.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPACEHEATER] = (d) => { - return IfcSpaceHeater.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPACEHEATERTYPE] = (d) => { - return IfcSpaceHeaterType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPACETYPE] = (d) => { - return IfcSpaceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPATIALELEMENT] = (d) => { - return IfcSpatialElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPATIALELEMENTTYPE] = (d) => { - return IfcSpatialElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPATIALSTRUCTUREELEMENT] = (d) => { - return IfcSpatialStructureElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPATIALSTRUCTUREELEMENTTYPE] = (d) => { - return IfcSpatialStructureElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPATIALZONE] = (d) => { - return IfcSpatialZone.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPATIALZONETYPE] = (d) => { - return IfcSpatialZoneType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPHERE] = (d) => { - return IfcSphere.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSPHERICALSURFACE] = (d) => { - return IfcSphericalSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTACKTERMINAL] = (d) => { - return IfcStackTerminal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTACKTERMINALTYPE] = (d) => { - return IfcStackTerminalType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTAIR] = (d) => { - return IfcStair.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTAIRFLIGHT] = (d) => { - return IfcStairFlight.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTAIRFLIGHTTYPE] = (d) => { - return IfcStairFlightType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTAIRTYPE] = (d) => { - return IfcStairType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALACTION] = (d) => { - return IfcStructuralAction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALACTIVITY] = (d) => { - return IfcStructuralActivity.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALANALYSISMODEL] = (d) => { - return IfcStructuralAnalysisModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCONNECTION] = (d) => { - return IfcStructuralConnection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCONNECTIONCONDITION] = (d) => { - return IfcStructuralConnectionCondition.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCURVEACTION] = (d) => { - return IfcStructuralCurveAction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCURVECONNECTION] = (d) => { - return IfcStructuralCurveConnection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCURVEMEMBER] = (d) => { - return IfcStructuralCurveMember.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCURVEMEMBERVARYING] = (d) => { - return IfcStructuralCurveMemberVarying.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALCURVEREACTION] = (d) => { - return IfcStructuralCurveReaction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALITEM] = (d) => { - return IfcStructuralItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLINEARACTION] = (d) => { - return IfcStructuralLinearAction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOAD] = (d) => { - return IfcStructuralLoad.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADCASE] = (d) => { - return IfcStructuralLoadCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADCONFIGURATION] = (d) => { - return IfcStructuralLoadConfiguration.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADGROUP] = (d) => { - return IfcStructuralLoadGroup.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADLINEARFORCE] = (d) => { - return IfcStructuralLoadLinearForce.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADORRESULT] = (d) => { - return IfcStructuralLoadOrResult.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADPLANARFORCE] = (d) => { - return IfcStructuralLoadPlanarForce.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADSINGLEDISPLACEMENT] = (d) => { - return IfcStructuralLoadSingleDisplacement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADSINGLEDISPLACEMENTDISTORTION] = (d) => { - return IfcStructuralLoadSingleDisplacementDistortion.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADSINGLEFORCE] = (d) => { - return IfcStructuralLoadSingleForce.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADSINGLEFORCEWARPING] = (d) => { - return IfcStructuralLoadSingleForceWarping.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADSTATIC] = (d) => { - return IfcStructuralLoadStatic.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALLOADTEMPERATURE] = (d) => { - return IfcStructuralLoadTemperature.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALMEMBER] = (d) => { - return IfcStructuralMember.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALPLANARACTION] = (d) => { - return IfcStructuralPlanarAction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALPOINTACTION] = (d) => { - return IfcStructuralPointAction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALPOINTCONNECTION] = (d) => { - return IfcStructuralPointConnection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALPOINTREACTION] = (d) => { - return IfcStructuralPointReaction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALREACTION] = (d) => { - return IfcStructuralReaction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALRESULTGROUP] = (d) => { - return IfcStructuralResultGroup.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALSURFACEACTION] = (d) => { - return IfcStructuralSurfaceAction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALSURFACECONNECTION] = (d) => { - return IfcStructuralSurfaceConnection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALSURFACEMEMBER] = (d) => { - return IfcStructuralSurfaceMember.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALSURFACEMEMBERVARYING] = (d) => { - return IfcStructuralSurfaceMemberVarying.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTRUCTURALSURFACEREACTION] = (d) => { - return IfcStructuralSurfaceReaction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTYLEMODEL] = (d) => { - return IfcStyleModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTYLEDITEM] = (d) => { - return IfcStyledItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSTYLEDREPRESENTATION] = (d) => { - return IfcStyledRepresentation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSUBCONTRACTRESOURCE] = (d) => { - return IfcSubContractResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSUBCONTRACTRESOURCETYPE] = (d) => { - return IfcSubContractResourceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSUBEDGE] = (d) => { - return IfcSubedge.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACE] = (d) => { - return IfcSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACECURVE] = (d) => { - return IfcSurfaceCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACECURVESWEPTAREASOLID] = (d) => { - return IfcSurfaceCurveSweptAreaSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACEFEATURE] = (d) => { - return IfcSurfaceFeature.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACEOFLINEAREXTRUSION] = (d) => { - return IfcSurfaceOfLinearExtrusion.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACEOFREVOLUTION] = (d) => { - return IfcSurfaceOfRevolution.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACEREINFORCEMENTAREA] = (d) => { - return IfcSurfaceReinforcementArea.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACESTYLE] = (d) => { - return IfcSurfaceStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACESTYLELIGHTING] = (d) => { - return IfcSurfaceStyleLighting.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACESTYLEREFRACTION] = (d) => { - return IfcSurfaceStyleRefraction.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACESTYLERENDERING] = (d) => { - return IfcSurfaceStyleRendering.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACESTYLESHADING] = (d) => { - return IfcSurfaceStyleShading.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACESTYLEWITHTEXTURES] = (d) => { - return IfcSurfaceStyleWithTextures.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSURFACETEXTURE] = (d) => { - return IfcSurfaceTexture.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSWEPTAREASOLID] = (d) => { - return IfcSweptAreaSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSWEPTDISKSOLID] = (d) => { - return IfcSweptDiskSolid.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSWEPTDISKSOLIDPOLYGONAL] = (d) => { - return IfcSweptDiskSolidPolygonal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSWEPTSURFACE] = (d) => { - return IfcSweptSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSWITCHINGDEVICE] = (d) => { - return IfcSwitchingDevice.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSWITCHINGDEVICETYPE] = (d) => { - return IfcSwitchingDeviceType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSYSTEM] = (d) => { - return IfcSystem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSYSTEMFURNITUREELEMENT] = (d) => { - return IfcSystemFurnitureElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCSYSTEMFURNITUREELEMENTTYPE] = (d) => { - return IfcSystemFurnitureElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTSHAPEPROFILEDEF] = (d) => { - return IfcTShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTABLE] = (d) => { - return IfcTable.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTABLECOLUMN] = (d) => { - return IfcTableColumn.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTABLEROW] = (d) => { - return IfcTableRow.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTANK] = (d) => { - return IfcTank.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTANKTYPE] = (d) => { - return IfcTankType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTASK] = (d) => { - return IfcTask.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTASKTIME] = (d) => { - return IfcTaskTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTASKTIMERECURRING] = (d) => { - return IfcTaskTimeRecurring.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTASKTYPE] = (d) => { - return IfcTaskType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTELECOMADDRESS] = (d) => { - return IfcTelecomAddress.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTENDON] = (d) => { - return IfcTendon.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTENDONANCHOR] = (d) => { - return IfcTendonAnchor.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTENDONANCHORTYPE] = (d) => { - return IfcTendonAnchorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTENDONCONDUIT] = (d) => { - return IfcTendonConduit.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTENDONCONDUITTYPE] = (d) => { - return IfcTendonConduitType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTENDONTYPE] = (d) => { - return IfcTendonType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTESSELLATEDFACESET] = (d) => { - return IfcTessellatedFaceSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTESSELLATEDITEM] = (d) => { - return IfcTessellatedItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTLITERAL] = (d) => { - return IfcTextLiteral.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTLITERALWITHEXTENT] = (d) => { - return IfcTextLiteralWithExtent.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTSTYLE] = (d) => { - return IfcTextStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTSTYLEFONTMODEL] = (d) => { - return IfcTextStyleFontModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTSTYLEFORDEFINEDFONT] = (d) => { - return IfcTextStyleForDefinedFont.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTSTYLETEXTMODEL] = (d) => { - return IfcTextStyleTextModel.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTURECOORDINATE] = (d) => { - return IfcTextureCoordinate.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTURECOORDINATEGENERATOR] = (d) => { - return IfcTextureCoordinateGenerator.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTUREMAP] = (d) => { - return IfcTextureMap.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTUREVERTEX] = (d) => { - return IfcTextureVertex.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTEXTUREVERTEXLIST] = (d) => { - return IfcTextureVertexList.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTIMEPERIOD] = (d) => { - return IfcTimePeriod.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTIMESERIES] = (d) => { - return IfcTimeSeries.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTIMESERIESVALUE] = (d) => { - return IfcTimeSeriesValue.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTOPOLOGICALREPRESENTATIONITEM] = (d) => { - return IfcTopologicalRepresentationItem.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTOPOLOGYREPRESENTATION] = (d) => { - return IfcTopologyRepresentation.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTOROIDALSURFACE] = (d) => { - return IfcToroidalSurface.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRANSFORMER] = (d) => { - return IfcTransformer.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRANSFORMERTYPE] = (d) => { - return IfcTransformerType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRANSITIONCURVESEGMENT2D] = (d) => { - return IfcTransitionCurveSegment2D.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRANSPORTELEMENT] = (d) => { - return IfcTransportElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRANSPORTELEMENTTYPE] = (d) => { - return IfcTransportElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRAPEZIUMPROFILEDEF] = (d) => { - return IfcTrapeziumProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRIANGULATEDFACESET] = (d) => { - return IfcTriangulatedFaceSet.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRIANGULATEDIRREGULARNETWORK] = (d) => { - return IfcTriangulatedIrregularNetwork.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTRIMMEDCURVE] = (d) => { - return IfcTrimmedCurve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTUBEBUNDLE] = (d) => { - return IfcTubeBundle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTUBEBUNDLETYPE] = (d) => { - return IfcTubeBundleType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTYPEOBJECT] = (d) => { - return IfcTypeObject.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTYPEPROCESS] = (d) => { - return IfcTypeProcess.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTYPEPRODUCT] = (d) => { - return IfcTypeProduct.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCTYPERESOURCE] = (d) => { - return IfcTypeResource.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCUSHAPEPROFILEDEF] = (d) => { - return IfcUShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCUNITASSIGNMENT] = (d) => { - return IfcUnitAssignment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCUNITARYCONTROLELEMENT] = (d) => { - return IfcUnitaryControlElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCUNITARYCONTROLELEMENTTYPE] = (d) => { - return IfcUnitaryControlElementType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCUNITARYEQUIPMENT] = (d) => { - return IfcUnitaryEquipment.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCUNITARYEQUIPMENTTYPE] = (d) => { - return IfcUnitaryEquipmentType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVALVE] = (d) => { - return IfcValve.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVALVETYPE] = (d) => { - return IfcValveType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVECTOR] = (d) => { - return IfcVector.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVERTEX] = (d) => { - return IfcVertex.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVERTEXLOOP] = (d) => { - return IfcVertexLoop.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVERTEXPOINT] = (d) => { - return IfcVertexPoint.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVIBRATIONDAMPER] = (d) => { - return IfcVibrationDamper.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVIBRATIONDAMPERTYPE] = (d) => { - return IfcVibrationDamperType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVIBRATIONISOLATOR] = (d) => { - return IfcVibrationIsolator.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVIBRATIONISOLATORTYPE] = (d) => { - return IfcVibrationIsolatorType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVIRTUALELEMENT] = (d) => { - return IfcVirtualElement.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVIRTUALGRIDINTERSECTION] = (d) => { - return IfcVirtualGridIntersection.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCVOIDINGFEATURE] = (d) => { - return IfcVoidingFeature.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWALL] = (d) => { - return IfcWall.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWALLELEMENTEDCASE] = (d) => { - return IfcWallElementedCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWALLSTANDARDCASE] = (d) => { - return IfcWallStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWALLTYPE] = (d) => { - return IfcWallType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWASTETERMINAL] = (d) => { - return IfcWasteTerminal.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWASTETERMINALTYPE] = (d) => { - return IfcWasteTerminalType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWINDOW] = (d) => { - return IfcWindow.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWINDOWLININGPROPERTIES] = (d) => { - return IfcWindowLiningProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWINDOWPANELPROPERTIES] = (d) => { - return IfcWindowPanelProperties.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWINDOWSTANDARDCASE] = (d) => { - return IfcWindowStandardCase.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWINDOWSTYLE] = (d) => { - return IfcWindowStyle.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWINDOWTYPE] = (d) => { - return IfcWindowType.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWORKCALENDAR] = (d) => { - return IfcWorkCalendar.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWORKCONTROL] = (d) => { - return IfcWorkControl.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWORKPLAN] = (d) => { - return IfcWorkPlan.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWORKSCHEDULE] = (d) => { - return IfcWorkSchedule.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCWORKTIME] = (d) => { - return IfcWorkTime.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCZSHAPEPROFILEDEF] = (d) => { - return IfcZShapeProfileDef.FromTape(d.ID, d.type, d.arguments); -}; -FromRawLineData[IFCZONE] = (d) => { - return IfcZone.FromTape(d.ID, d.type, d.arguments); -}; -var IfcActionRequest = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.PredefinedType = PredefinedType; - this.Status = Status; - this.LongDescription = LongDescription; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Status = tape[ptr++]; - let LongDescription = tape[ptr++]; - return new IfcActionRequest(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.PredefinedType); - args.push(this.Status); - args.push(this.LongDescription); - return args; - } -}; -var IfcActor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.TheActor = TheActor; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let TheActor = tape[ptr++]; - return new IfcActor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.TheActor); - return args; - } -}; -var IfcActorRole = class { - constructor(expressID, type, Role, UserDefinedRole, Description) { - this.expressID = expressID; - this.type = type; - this.Role = Role; - this.UserDefinedRole = UserDefinedRole; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Role = tape[ptr++]; - let UserDefinedRole = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcActorRole(expressID, type, Role, UserDefinedRole, Description); - } - ToTape() { - let args = []; - args.push(this.Role); - args.push(this.UserDefinedRole); - args.push(this.Description); - return args; - } -}; -var IfcActuator = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcActuator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcActuatorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcActuatorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAddress = class { - constructor(expressID, type, Purpose, Description, UserDefinedPurpose) { - this.expressID = expressID; - this.type = type; - this.Purpose = Purpose; - this.Description = Description; - this.UserDefinedPurpose = UserDefinedPurpose; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Purpose = tape[ptr++]; - let Description = tape[ptr++]; - let UserDefinedPurpose = tape[ptr++]; - return new IfcAddress(expressID, type, Purpose, Description, UserDefinedPurpose); - } - ToTape() { - let args = []; - args.push(this.Purpose); - args.push(this.Description); - args.push(this.UserDefinedPurpose); - return args; - } -}; -var IfcAdvancedBrep = class { - constructor(expressID, type, Outer) { - this.expressID = expressID; - this.type = type; - this.Outer = Outer; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Outer = tape[ptr++]; - return new IfcAdvancedBrep(expressID, type, Outer); - } - ToTape() { - let args = []; - args.push(this.Outer); - return args; - } -}; -var IfcAdvancedBrepWithVoids = class { - constructor(expressID, type, Outer, Voids) { - this.expressID = expressID; - this.type = type; - this.Outer = Outer; - this.Voids = Voids; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Outer = tape[ptr++]; - let Voids = tape[ptr++]; - return new IfcAdvancedBrepWithVoids(expressID, type, Outer, Voids); - } - ToTape() { - let args = []; - args.push(this.Outer); - args.push(this.Voids); - return args; - } -}; -var IfcAdvancedFace = class { - constructor(expressID, type, Bounds, FaceSurface, SameSense) { - this.expressID = expressID; - this.type = type; - this.Bounds = Bounds; - this.FaceSurface = FaceSurface; - this.SameSense = SameSense; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Bounds = tape[ptr++]; - let FaceSurface = tape[ptr++]; - let SameSense = tape[ptr++]; - return new IfcAdvancedFace(expressID, type, Bounds, FaceSurface, SameSense); - } - ToTape() { - let args = []; - args.push(this.Bounds); - args.push(this.FaceSurface); - args.push(this.SameSense); - return args; - } -}; -var IfcAirTerminal = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAirTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAirTerminalBox = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAirTerminalBox(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAirTerminalBoxType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAirTerminalBoxType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAirTerminalType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAirTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAirToAirHeatRecovery = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAirToAirHeatRecovery(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAirToAirHeatRecoveryType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAirToAirHeatRecoveryType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAlarm = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAlarm(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAlarmType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAlarmType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAlignment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Axis = Axis; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Axis = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAlignment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Axis); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAlignment2DHorizontal = class { - constructor(expressID, type, StartDistAlong, Segments) { - this.expressID = expressID; - this.type = type; - this.StartDistAlong = StartDistAlong; - this.Segments = Segments; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let StartDistAlong = tape[ptr++]; - let Segments = tape[ptr++]; - return new IfcAlignment2DHorizontal(expressID, type, StartDistAlong, Segments); - } - ToTape() { - let args = []; - args.push(this.StartDistAlong); - args.push(this.Segments); - return args; - } -}; -var IfcAlignment2DHorizontalSegment = class { - constructor(expressID, type, TangentialContinuity, StartTag, EndTag, CurveGeometry) { - this.expressID = expressID; - this.type = type; - this.TangentialContinuity = TangentialContinuity; - this.StartTag = StartTag; - this.EndTag = EndTag; - this.CurveGeometry = CurveGeometry; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TangentialContinuity = tape[ptr++]; - let StartTag = tape[ptr++]; - let EndTag = tape[ptr++]; - let CurveGeometry = tape[ptr++]; - return new IfcAlignment2DHorizontalSegment(expressID, type, TangentialContinuity, StartTag, EndTag, CurveGeometry); - } - ToTape() { - let args = []; - args.push(this.TangentialContinuity); - args.push(this.StartTag); - args.push(this.EndTag); - args.push(this.CurveGeometry); - return args; - } -}; -var IfcAlignment2DSegment = class { - constructor(expressID, type, TangentialContinuity, StartTag, EndTag) { - this.expressID = expressID; - this.type = type; - this.TangentialContinuity = TangentialContinuity; - this.StartTag = StartTag; - this.EndTag = EndTag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TangentialContinuity = tape[ptr++]; - let StartTag = tape[ptr++]; - let EndTag = tape[ptr++]; - return new IfcAlignment2DSegment(expressID, type, TangentialContinuity, StartTag, EndTag); - } - ToTape() { - let args = []; - args.push(this.TangentialContinuity); - args.push(this.StartTag); - args.push(this.EndTag); - return args; - } -}; -var IfcAlignment2DVerSegCircularArc = class { - constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, Radius, IsConvex) { - this.expressID = expressID; - this.type = type; - this.TangentialContinuity = TangentialContinuity; - this.StartTag = StartTag; - this.EndTag = EndTag; - this.StartDistAlong = StartDistAlong; - this.HorizontalLength = HorizontalLength; - this.StartHeight = StartHeight; - this.StartGradient = StartGradient; - this.Radius = Radius; - this.IsConvex = IsConvex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TangentialContinuity = tape[ptr++]; - let StartTag = tape[ptr++]; - let EndTag = tape[ptr++]; - let StartDistAlong = tape[ptr++]; - let HorizontalLength = tape[ptr++]; - let StartHeight = tape[ptr++]; - let StartGradient = tape[ptr++]; - let Radius = tape[ptr++]; - let IsConvex = tape[ptr++]; - return new IfcAlignment2DVerSegCircularArc(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, Radius, IsConvex); - } - ToTape() { - let args = []; - args.push(this.TangentialContinuity); - args.push(this.StartTag); - args.push(this.EndTag); - args.push(this.StartDistAlong); - args.push(this.HorizontalLength); - args.push(this.StartHeight); - args.push(this.StartGradient); - args.push(this.Radius); - args.push(this.IsConvex); - return args; - } -}; -var IfcAlignment2DVerSegLine = class { - constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient) { - this.expressID = expressID; - this.type = type; - this.TangentialContinuity = TangentialContinuity; - this.StartTag = StartTag; - this.EndTag = EndTag; - this.StartDistAlong = StartDistAlong; - this.HorizontalLength = HorizontalLength; - this.StartHeight = StartHeight; - this.StartGradient = StartGradient; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TangentialContinuity = tape[ptr++]; - let StartTag = tape[ptr++]; - let EndTag = tape[ptr++]; - let StartDistAlong = tape[ptr++]; - let HorizontalLength = tape[ptr++]; - let StartHeight = tape[ptr++]; - let StartGradient = tape[ptr++]; - return new IfcAlignment2DVerSegLine(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient); - } - ToTape() { - let args = []; - args.push(this.TangentialContinuity); - args.push(this.StartTag); - args.push(this.EndTag); - args.push(this.StartDistAlong); - args.push(this.HorizontalLength); - args.push(this.StartHeight); - args.push(this.StartGradient); - return args; - } -}; -var IfcAlignment2DVerSegParabolicArc = class { - constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, ParabolaConstant, IsConvex) { - this.expressID = expressID; - this.type = type; - this.TangentialContinuity = TangentialContinuity; - this.StartTag = StartTag; - this.EndTag = EndTag; - this.StartDistAlong = StartDistAlong; - this.HorizontalLength = HorizontalLength; - this.StartHeight = StartHeight; - this.StartGradient = StartGradient; - this.ParabolaConstant = ParabolaConstant; - this.IsConvex = IsConvex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TangentialContinuity = tape[ptr++]; - let StartTag = tape[ptr++]; - let EndTag = tape[ptr++]; - let StartDistAlong = tape[ptr++]; - let HorizontalLength = tape[ptr++]; - let StartHeight = tape[ptr++]; - let StartGradient = tape[ptr++]; - let ParabolaConstant = tape[ptr++]; - let IsConvex = tape[ptr++]; - return new IfcAlignment2DVerSegParabolicArc(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, ParabolaConstant, IsConvex); - } - ToTape() { - let args = []; - args.push(this.TangentialContinuity); - args.push(this.StartTag); - args.push(this.EndTag); - args.push(this.StartDistAlong); - args.push(this.HorizontalLength); - args.push(this.StartHeight); - args.push(this.StartGradient); - args.push(this.ParabolaConstant); - args.push(this.IsConvex); - return args; - } -}; -var IfcAlignment2DVertical = class { - constructor(expressID, type, Segments) { - this.expressID = expressID; - this.type = type; - this.Segments = Segments; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Segments = tape[ptr++]; - return new IfcAlignment2DVertical(expressID, type, Segments); - } - ToTape() { - let args = []; - args.push(this.Segments); - return args; - } -}; -var IfcAlignment2DVerticalSegment = class { - constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient) { - this.expressID = expressID; - this.type = type; - this.TangentialContinuity = TangentialContinuity; - this.StartTag = StartTag; - this.EndTag = EndTag; - this.StartDistAlong = StartDistAlong; - this.HorizontalLength = HorizontalLength; - this.StartHeight = StartHeight; - this.StartGradient = StartGradient; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TangentialContinuity = tape[ptr++]; - let StartTag = tape[ptr++]; - let EndTag = tape[ptr++]; - let StartDistAlong = tape[ptr++]; - let HorizontalLength = tape[ptr++]; - let StartHeight = tape[ptr++]; - let StartGradient = tape[ptr++]; - return new IfcAlignment2DVerticalSegment(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient); - } - ToTape() { - let args = []; - args.push(this.TangentialContinuity); - args.push(this.StartTag); - args.push(this.EndTag); - args.push(this.StartDistAlong); - args.push(this.HorizontalLength); - args.push(this.StartHeight); - args.push(this.StartGradient); - return args; - } -}; -var IfcAlignmentCurve = class { - constructor(expressID, type, Horizontal, Vertical, Tag) { - this.expressID = expressID; - this.type = type; - this.Horizontal = Horizontal; - this.Vertical = Vertical; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Horizontal = tape[ptr++]; - let Vertical = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcAlignmentCurve(expressID, type, Horizontal, Vertical, Tag); - } - ToTape() { - let args = []; - args.push(this.Horizontal); - args.push(this.Vertical); - args.push(this.Tag); - return args; - } -}; -var IfcAnnotation = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - return new IfcAnnotation(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - return args; - } -}; -var IfcAnnotationFillArea = class { - constructor(expressID, type, OuterBoundary, InnerBoundaries) { - this.expressID = expressID; - this.type = type; - this.OuterBoundary = OuterBoundary; - this.InnerBoundaries = InnerBoundaries; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let OuterBoundary = tape[ptr++]; - let InnerBoundaries = tape[ptr++]; - return new IfcAnnotationFillArea(expressID, type, OuterBoundary, InnerBoundaries); - } - ToTape() { - let args = []; - args.push(this.OuterBoundary); - args.push(this.InnerBoundaries); - return args; - } -}; -var IfcApplication = class { - constructor(expressID, type, ApplicationDeveloper, Version, ApplicationFullName, ApplicationIdentifier) { - this.expressID = expressID; - this.type = type; - this.ApplicationDeveloper = ApplicationDeveloper; - this.Version = Version; - this.ApplicationFullName = ApplicationFullName; - this.ApplicationIdentifier = ApplicationIdentifier; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ApplicationDeveloper = tape[ptr++]; - let Version = tape[ptr++]; - let ApplicationFullName = tape[ptr++]; - let ApplicationIdentifier = tape[ptr++]; - return new IfcApplication(expressID, type, ApplicationDeveloper, Version, ApplicationFullName, ApplicationIdentifier); - } - ToTape() { - let args = []; - args.push(this.ApplicationDeveloper); - args.push(this.Version); - args.push(this.ApplicationFullName); - args.push(this.ApplicationIdentifier); - return args; - } -}; -var IfcAppliedValue = class { - constructor(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.AppliedValue = AppliedValue; - this.UnitBasis = UnitBasis; - this.ApplicableDate = ApplicableDate; - this.FixedUntilDate = FixedUntilDate; - this.Category = Category; - this.Condition = Condition; - this.ArithmeticOperator = ArithmeticOperator; - this.Components = Components; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let AppliedValue = tape[ptr++]; - let UnitBasis = tape[ptr++]; - let ApplicableDate = tape[ptr++]; - let FixedUntilDate = tape[ptr++]; - let Category = tape[ptr++]; - let Condition = tape[ptr++]; - let ArithmeticOperator = tape[ptr++]; - let Components = tape[ptr++]; - return new IfcAppliedValue(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.AppliedValue); - args.push(this.UnitBasis); - args.push(this.ApplicableDate); - args.push(this.FixedUntilDate); - args.push(this.Category); - args.push(this.Condition); - args.push(this.ArithmeticOperator); - args.push(this.Components); - return args; - } -}; -var IfcApproval = class { - constructor(expressID, type, Identifier, Name, Description, TimeOfApproval, Status, Level, Qualifier, RequestingApproval, GivingApproval) { - this.expressID = expressID; - this.type = type; - this.Identifier = Identifier; - this.Name = Name; - this.Description = Description; - this.TimeOfApproval = TimeOfApproval; - this.Status = Status; - this.Level = Level; - this.Qualifier = Qualifier; - this.RequestingApproval = RequestingApproval; - this.GivingApproval = GivingApproval; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Identifier = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let TimeOfApproval = tape[ptr++]; - let Status = tape[ptr++]; - let Level = tape[ptr++]; - let Qualifier = tape[ptr++]; - let RequestingApproval = tape[ptr++]; - let GivingApproval = tape[ptr++]; - return new IfcApproval(expressID, type, Identifier, Name, Description, TimeOfApproval, Status, Level, Qualifier, RequestingApproval, GivingApproval); - } - ToTape() { - let args = []; - args.push(this.Identifier); - args.push(this.Name); - args.push(this.Description); - args.push(this.TimeOfApproval); - args.push(this.Status); - args.push(this.Level); - args.push(this.Qualifier); - args.push(this.RequestingApproval); - args.push(this.GivingApproval); - return args; - } -}; -var IfcApprovalRelationship = class { - constructor(expressID, type, Name, Description, RelatingApproval, RelatedApprovals) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingApproval = RelatingApproval; - this.RelatedApprovals = RelatedApprovals; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingApproval = tape[ptr++]; - let RelatedApprovals = tape[ptr++]; - return new IfcApprovalRelationship(expressID, type, Name, Description, RelatingApproval, RelatedApprovals); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingApproval); - args.push(this.RelatedApprovals); - return args; - } -}; -var IfcArbitraryClosedProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, OuterCurve) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.OuterCurve = OuterCurve; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let OuterCurve = tape[ptr++]; - return new IfcArbitraryClosedProfileDef(expressID, type, ProfileType, ProfileName, OuterCurve); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.OuterCurve); - return args; - } -}; -var IfcArbitraryOpenProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Curve) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Curve = Curve; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Curve = tape[ptr++]; - return new IfcArbitraryOpenProfileDef(expressID, type, ProfileType, ProfileName, Curve); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Curve); - return args; - } -}; -var IfcArbitraryProfileDefWithVoids = class { - constructor(expressID, type, ProfileType, ProfileName, OuterCurve, InnerCurves) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.OuterCurve = OuterCurve; - this.InnerCurves = InnerCurves; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let OuterCurve = tape[ptr++]; - let InnerCurves = tape[ptr++]; - return new IfcArbitraryProfileDefWithVoids(expressID, type, ProfileType, ProfileName, OuterCurve, InnerCurves); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.OuterCurve); - args.push(this.InnerCurves); - return args; - } -}; -var IfcAsset = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, OriginalValue, CurrentValue, TotalReplacementCost, Owner, User, ResponsiblePerson, IncorporationDate, DepreciatedValue) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.OriginalValue = OriginalValue; - this.CurrentValue = CurrentValue; - this.TotalReplacementCost = TotalReplacementCost; - this.Owner = Owner; - this.User = User; - this.ResponsiblePerson = ResponsiblePerson; - this.IncorporationDate = IncorporationDate; - this.DepreciatedValue = DepreciatedValue; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let OriginalValue = tape[ptr++]; - let CurrentValue = tape[ptr++]; - let TotalReplacementCost = tape[ptr++]; - let Owner = tape[ptr++]; - let User = tape[ptr++]; - let ResponsiblePerson = tape[ptr++]; - let IncorporationDate = tape[ptr++]; - let DepreciatedValue = tape[ptr++]; - return new IfcAsset(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, OriginalValue, CurrentValue, TotalReplacementCost, Owner, User, ResponsiblePerson, IncorporationDate, DepreciatedValue); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.OriginalValue); - args.push(this.CurrentValue); - args.push(this.TotalReplacementCost); - args.push(this.Owner); - args.push(this.User); - args.push(this.ResponsiblePerson); - args.push(this.IncorporationDate); - args.push(this.DepreciatedValue); - return args; - } -}; -var IfcAsymmetricIShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, BottomFlangeWidth, OverallDepth, WebThickness, BottomFlangeThickness, BottomFlangeFilletRadius, TopFlangeWidth, TopFlangeThickness, TopFlangeFilletRadius, BottomFlangeEdgeRadius, BottomFlangeSlope, TopFlangeEdgeRadius, TopFlangeSlope) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.BottomFlangeWidth = BottomFlangeWidth; - this.OverallDepth = OverallDepth; - this.WebThickness = WebThickness; - this.BottomFlangeThickness = BottomFlangeThickness; - this.BottomFlangeFilletRadius = BottomFlangeFilletRadius; - this.TopFlangeWidth = TopFlangeWidth; - this.TopFlangeThickness = TopFlangeThickness; - this.TopFlangeFilletRadius = TopFlangeFilletRadius; - this.BottomFlangeEdgeRadius = BottomFlangeEdgeRadius; - this.BottomFlangeSlope = BottomFlangeSlope; - this.TopFlangeEdgeRadius = TopFlangeEdgeRadius; - this.TopFlangeSlope = TopFlangeSlope; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let BottomFlangeWidth = tape[ptr++]; - let OverallDepth = tape[ptr++]; - let WebThickness = tape[ptr++]; - let BottomFlangeThickness = tape[ptr++]; - let BottomFlangeFilletRadius = tape[ptr++]; - let TopFlangeWidth = tape[ptr++]; - let TopFlangeThickness = tape[ptr++]; - let TopFlangeFilletRadius = tape[ptr++]; - let BottomFlangeEdgeRadius = tape[ptr++]; - let BottomFlangeSlope = tape[ptr++]; - let TopFlangeEdgeRadius = tape[ptr++]; - let TopFlangeSlope = tape[ptr++]; - return new IfcAsymmetricIShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, BottomFlangeWidth, OverallDepth, WebThickness, BottomFlangeThickness, BottomFlangeFilletRadius, TopFlangeWidth, TopFlangeThickness, TopFlangeFilletRadius, BottomFlangeEdgeRadius, BottomFlangeSlope, TopFlangeEdgeRadius, TopFlangeSlope); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.BottomFlangeWidth); - args.push(this.OverallDepth); - args.push(this.WebThickness); - args.push(this.BottomFlangeThickness); - args.push(this.BottomFlangeFilletRadius); - args.push(this.TopFlangeWidth); - args.push(this.TopFlangeThickness); - args.push(this.TopFlangeFilletRadius); - args.push(this.BottomFlangeEdgeRadius); - args.push(this.BottomFlangeSlope); - args.push(this.TopFlangeEdgeRadius); - args.push(this.TopFlangeSlope); - return args; - } -}; -var IfcAudioVisualAppliance = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAudioVisualAppliance(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAudioVisualApplianceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcAudioVisualApplianceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcAxis1Placement = class { - constructor(expressID, type, Location, Axis) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Axis = Axis; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Axis = tape[ptr++]; - return new IfcAxis1Placement(expressID, type, Location, Axis); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Axis); - return args; - } -}; -var IfcAxis2Placement2D = class { - constructor(expressID, type, Location, RefDirection) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.RefDirection = RefDirection; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let RefDirection = tape[ptr++]; - return new IfcAxis2Placement2D(expressID, type, Location, RefDirection); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.RefDirection); - return args; - } -}; -var IfcAxis2Placement3D = class { - constructor(expressID, type, Location, Axis, RefDirection) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Axis = Axis; - this.RefDirection = RefDirection; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Axis = tape[ptr++]; - let RefDirection = tape[ptr++]; - return new IfcAxis2Placement3D(expressID, type, Location, Axis, RefDirection); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Axis); - args.push(this.RefDirection); - return args; - } -}; -var IfcBSplineCurve = class { - constructor(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.Degree = Degree; - this.ControlPointsList = ControlPointsList; - this.CurveForm = CurveForm; - this.ClosedCurve = ClosedCurve; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Degree = tape[ptr++]; - let ControlPointsList = tape[ptr++]; - let CurveForm = tape[ptr++]; - let ClosedCurve = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcBSplineCurve(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.Degree); - args.push(this.ControlPointsList); - args.push(this.CurveForm); - args.push(this.ClosedCurve); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcBSplineCurveWithKnots = class { - constructor(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec) { - this.expressID = expressID; - this.type = type; - this.Degree = Degree; - this.ControlPointsList = ControlPointsList; - this.CurveForm = CurveForm; - this.ClosedCurve = ClosedCurve; - this.SelfIntersect = SelfIntersect; - this.KnotMultiplicities = KnotMultiplicities; - this.Knots = Knots; - this.KnotSpec = KnotSpec; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Degree = tape[ptr++]; - let ControlPointsList = tape[ptr++]; - let CurveForm = tape[ptr++]; - let ClosedCurve = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - let KnotMultiplicities = tape[ptr++]; - let Knots = tape[ptr++]; - let KnotSpec = tape[ptr++]; - return new IfcBSplineCurveWithKnots(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec); - } - ToTape() { - let args = []; - args.push(this.Degree); - args.push(this.ControlPointsList); - args.push(this.CurveForm); - args.push(this.ClosedCurve); - args.push(this.SelfIntersect); - args.push(this.KnotMultiplicities); - args.push(this.Knots); - args.push(this.KnotSpec); - return args; - } -}; -var IfcBSplineSurface = class { - constructor(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.UDegree = UDegree; - this.VDegree = VDegree; - this.ControlPointsList = ControlPointsList; - this.SurfaceForm = SurfaceForm; - this.UClosed = UClosed; - this.VClosed = VClosed; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let UDegree = tape[ptr++]; - let VDegree = tape[ptr++]; - let ControlPointsList = tape[ptr++]; - let SurfaceForm = tape[ptr++]; - let UClosed = tape[ptr++]; - let VClosed = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcBSplineSurface(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.UDegree); - args.push(this.VDegree); - args.push(this.ControlPointsList); - args.push(this.SurfaceForm); - args.push(this.UClosed); - args.push(this.VClosed); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcBSplineSurfaceWithKnots = class { - constructor(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec) { - this.expressID = expressID; - this.type = type; - this.UDegree = UDegree; - this.VDegree = VDegree; - this.ControlPointsList = ControlPointsList; - this.SurfaceForm = SurfaceForm; - this.UClosed = UClosed; - this.VClosed = VClosed; - this.SelfIntersect = SelfIntersect; - this.UMultiplicities = UMultiplicities; - this.VMultiplicities = VMultiplicities; - this.UKnots = UKnots; - this.VKnots = VKnots; - this.KnotSpec = KnotSpec; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let UDegree = tape[ptr++]; - let VDegree = tape[ptr++]; - let ControlPointsList = tape[ptr++]; - let SurfaceForm = tape[ptr++]; - let UClosed = tape[ptr++]; - let VClosed = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - let UMultiplicities = tape[ptr++]; - let VMultiplicities = tape[ptr++]; - let UKnots = tape[ptr++]; - let VKnots = tape[ptr++]; - let KnotSpec = tape[ptr++]; - return new IfcBSplineSurfaceWithKnots(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec); - } - ToTape() { - let args = []; - args.push(this.UDegree); - args.push(this.VDegree); - args.push(this.ControlPointsList); - args.push(this.SurfaceForm); - args.push(this.UClosed); - args.push(this.VClosed); - args.push(this.SelfIntersect); - args.push(this.UMultiplicities); - args.push(this.VMultiplicities); - args.push(this.UKnots); - args.push(this.VKnots); - args.push(this.KnotSpec); - return args; - } -}; -var IfcBeam = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBeam(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBeamStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBeamStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBeamType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBeamType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBearing = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBearing(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBearingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBearingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBlobTexture = class { - constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, RasterFormat, RasterCode) { - this.expressID = expressID; - this.type = type; - this.RepeatS = RepeatS; - this.RepeatT = RepeatT; - this.Mode = Mode; - this.TextureTransform = TextureTransform; - this.Parameter = Parameter; - this.RasterFormat = RasterFormat; - this.RasterCode = RasterCode; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RepeatS = tape[ptr++]; - let RepeatT = tape[ptr++]; - let Mode = tape[ptr++]; - let TextureTransform = tape[ptr++]; - let Parameter = tape[ptr++]; - let RasterFormat = tape[ptr++]; - let RasterCode = tape[ptr++]; - return new IfcBlobTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, RasterFormat, RasterCode); - } - ToTape() { - let args = []; - args.push(this.RepeatS); - args.push(this.RepeatT); - args.push(this.Mode); - args.push(this.TextureTransform); - args.push(this.Parameter); - args.push(this.RasterFormat); - args.push(this.RasterCode); - return args; - } -}; -var IfcBlock = class { - constructor(expressID, type, Position, XLength, YLength, ZLength) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.XLength = XLength; - this.YLength = YLength; - this.ZLength = ZLength; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let XLength = tape[ptr++]; - let YLength = tape[ptr++]; - let ZLength = tape[ptr++]; - return new IfcBlock(expressID, type, Position, XLength, YLength, ZLength); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.XLength); - args.push(this.YLength); - args.push(this.ZLength); - return args; - } -}; -var IfcBoiler = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBoiler(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBoilerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBoilerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBooleanClippingResult = class { - constructor(expressID, type, Operator, FirstOperand, SecondOperand) { - this.expressID = expressID; - this.type = type; - this.Operator = Operator; - this.FirstOperand = FirstOperand; - this.SecondOperand = SecondOperand; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Operator = tape[ptr++]; - let FirstOperand = tape[ptr++]; - let SecondOperand = tape[ptr++]; - return new IfcBooleanClippingResult(expressID, type, Operator, FirstOperand, SecondOperand); - } - ToTape() { - let args = []; - args.push(this.Operator); - args.push(this.FirstOperand); - args.push(this.SecondOperand); - return args; - } -}; -var IfcBooleanResult = class { - constructor(expressID, type, Operator, FirstOperand, SecondOperand) { - this.expressID = expressID; - this.type = type; - this.Operator = Operator; - this.FirstOperand = FirstOperand; - this.SecondOperand = SecondOperand; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Operator = tape[ptr++]; - let FirstOperand = tape[ptr++]; - let SecondOperand = tape[ptr++]; - return new IfcBooleanResult(expressID, type, Operator, FirstOperand, SecondOperand); - } - ToTape() { - let args = []; - args.push(this.Operator); - args.push(this.FirstOperand); - args.push(this.SecondOperand); - return args; - } -}; -var IfcBoundaryCondition = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcBoundaryCondition(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcBoundaryCurve = class { - constructor(expressID, type, Segments, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.Segments = Segments; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Segments = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcBoundaryCurve(expressID, type, Segments, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.Segments); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcBoundaryEdgeCondition = class { - constructor(expressID, type, Name, TranslationalStiffnessByLengthX, TranslationalStiffnessByLengthY, TranslationalStiffnessByLengthZ, RotationalStiffnessByLengthX, RotationalStiffnessByLengthY, RotationalStiffnessByLengthZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.TranslationalStiffnessByLengthX = TranslationalStiffnessByLengthX; - this.TranslationalStiffnessByLengthY = TranslationalStiffnessByLengthY; - this.TranslationalStiffnessByLengthZ = TranslationalStiffnessByLengthZ; - this.RotationalStiffnessByLengthX = RotationalStiffnessByLengthX; - this.RotationalStiffnessByLengthY = RotationalStiffnessByLengthY; - this.RotationalStiffnessByLengthZ = RotationalStiffnessByLengthZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let TranslationalStiffnessByLengthX = tape[ptr++]; - let TranslationalStiffnessByLengthY = tape[ptr++]; - let TranslationalStiffnessByLengthZ = tape[ptr++]; - let RotationalStiffnessByLengthX = tape[ptr++]; - let RotationalStiffnessByLengthY = tape[ptr++]; - let RotationalStiffnessByLengthZ = tape[ptr++]; - return new IfcBoundaryEdgeCondition(expressID, type, Name, TranslationalStiffnessByLengthX, TranslationalStiffnessByLengthY, TranslationalStiffnessByLengthZ, RotationalStiffnessByLengthX, RotationalStiffnessByLengthY, RotationalStiffnessByLengthZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.TranslationalStiffnessByLengthX); - args.push(this.TranslationalStiffnessByLengthY); - args.push(this.TranslationalStiffnessByLengthZ); - args.push(this.RotationalStiffnessByLengthX); - args.push(this.RotationalStiffnessByLengthY); - args.push(this.RotationalStiffnessByLengthZ); - return args; - } -}; -var IfcBoundaryFaceCondition = class { - constructor(expressID, type, Name, TranslationalStiffnessByAreaX, TranslationalStiffnessByAreaY, TranslationalStiffnessByAreaZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.TranslationalStiffnessByAreaX = TranslationalStiffnessByAreaX; - this.TranslationalStiffnessByAreaY = TranslationalStiffnessByAreaY; - this.TranslationalStiffnessByAreaZ = TranslationalStiffnessByAreaZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let TranslationalStiffnessByAreaX = tape[ptr++]; - let TranslationalStiffnessByAreaY = tape[ptr++]; - let TranslationalStiffnessByAreaZ = tape[ptr++]; - return new IfcBoundaryFaceCondition(expressID, type, Name, TranslationalStiffnessByAreaX, TranslationalStiffnessByAreaY, TranslationalStiffnessByAreaZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.TranslationalStiffnessByAreaX); - args.push(this.TranslationalStiffnessByAreaY); - args.push(this.TranslationalStiffnessByAreaZ); - return args; - } -}; -var IfcBoundaryNodeCondition = class { - constructor(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.TranslationalStiffnessX = TranslationalStiffnessX; - this.TranslationalStiffnessY = TranslationalStiffnessY; - this.TranslationalStiffnessZ = TranslationalStiffnessZ; - this.RotationalStiffnessX = RotationalStiffnessX; - this.RotationalStiffnessY = RotationalStiffnessY; - this.RotationalStiffnessZ = RotationalStiffnessZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let TranslationalStiffnessX = tape[ptr++]; - let TranslationalStiffnessY = tape[ptr++]; - let TranslationalStiffnessZ = tape[ptr++]; - let RotationalStiffnessX = tape[ptr++]; - let RotationalStiffnessY = tape[ptr++]; - let RotationalStiffnessZ = tape[ptr++]; - return new IfcBoundaryNodeCondition(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.TranslationalStiffnessX); - args.push(this.TranslationalStiffnessY); - args.push(this.TranslationalStiffnessZ); - args.push(this.RotationalStiffnessX); - args.push(this.RotationalStiffnessY); - args.push(this.RotationalStiffnessZ); - return args; - } -}; -var IfcBoundaryNodeConditionWarping = class { - constructor(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ, WarpingStiffness) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.TranslationalStiffnessX = TranslationalStiffnessX; - this.TranslationalStiffnessY = TranslationalStiffnessY; - this.TranslationalStiffnessZ = TranslationalStiffnessZ; - this.RotationalStiffnessX = RotationalStiffnessX; - this.RotationalStiffnessY = RotationalStiffnessY; - this.RotationalStiffnessZ = RotationalStiffnessZ; - this.WarpingStiffness = WarpingStiffness; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let TranslationalStiffnessX = tape[ptr++]; - let TranslationalStiffnessY = tape[ptr++]; - let TranslationalStiffnessZ = tape[ptr++]; - let RotationalStiffnessX = tape[ptr++]; - let RotationalStiffnessY = tape[ptr++]; - let RotationalStiffnessZ = tape[ptr++]; - let WarpingStiffness = tape[ptr++]; - return new IfcBoundaryNodeConditionWarping(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ, WarpingStiffness); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.TranslationalStiffnessX); - args.push(this.TranslationalStiffnessY); - args.push(this.TranslationalStiffnessZ); - args.push(this.RotationalStiffnessX); - args.push(this.RotationalStiffnessY); - args.push(this.RotationalStiffnessZ); - args.push(this.WarpingStiffness); - return args; - } -}; -var IfcBoundedCurve = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcBoundedCurve(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcBoundedSurface = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcBoundedSurface(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcBoundingBox = class { - constructor(expressID, type, Corner, XDim, YDim, ZDim) { - this.expressID = expressID; - this.type = type; - this.Corner = Corner; - this.XDim = XDim; - this.YDim = YDim; - this.ZDim = ZDim; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Corner = tape[ptr++]; - let XDim = tape[ptr++]; - let YDim = tape[ptr++]; - let ZDim = tape[ptr++]; - return new IfcBoundingBox(expressID, type, Corner, XDim, YDim, ZDim); - } - ToTape() { - let args = []; - args.push(this.Corner); - args.push(this.XDim); - args.push(this.YDim); - args.push(this.ZDim); - return args; - } -}; -var IfcBoxedHalfSpace = class { - constructor(expressID, type, BaseSurface, AgreementFlag, Enclosure) { - this.expressID = expressID; - this.type = type; - this.BaseSurface = BaseSurface; - this.AgreementFlag = AgreementFlag; - this.Enclosure = Enclosure; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BaseSurface = tape[ptr++]; - let AgreementFlag = tape[ptr++]; - let Enclosure = tape[ptr++]; - return new IfcBoxedHalfSpace(expressID, type, BaseSurface, AgreementFlag, Enclosure); - } - ToTape() { - let args = []; - args.push(this.BaseSurface); - args.push(this.AgreementFlag); - args.push(this.Enclosure); - return args; - } -}; -var IfcBridge = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBridge(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBridgePart = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBridgePart(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBuilding = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, ElevationOfRefHeight, ElevationOfTerrain, BuildingAddress) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - this.ElevationOfRefHeight = ElevationOfRefHeight; - this.ElevationOfTerrain = ElevationOfTerrain; - this.BuildingAddress = BuildingAddress; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - let ElevationOfRefHeight = tape[ptr++]; - let ElevationOfTerrain = tape[ptr++]; - let BuildingAddress = tape[ptr++]; - return new IfcBuilding(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, ElevationOfRefHeight, ElevationOfTerrain, BuildingAddress); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - args.push(this.ElevationOfRefHeight); - args.push(this.ElevationOfTerrain); - args.push(this.BuildingAddress); - return args; - } -}; -var IfcBuildingElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcBuildingElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcBuildingElementPart = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBuildingElementPart(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBuildingElementPartType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBuildingElementPartType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBuildingElementProxy = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBuildingElementProxy(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBuildingElementProxyType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBuildingElementProxyType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBuildingElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcBuildingElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcBuildingStorey = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, Elevation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - this.Elevation = Elevation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - let Elevation = tape[ptr++]; - return new IfcBuildingStorey(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, Elevation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - args.push(this.Elevation); - return args; - } -}; -var IfcBuildingSystem = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, LongName) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.PredefinedType = PredefinedType; - this.LongName = LongName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let LongName = tape[ptr++]; - return new IfcBuildingSystem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, LongName); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.PredefinedType); - args.push(this.LongName); - return args; - } -}; -var IfcBurner = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBurner(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcBurnerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcBurnerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Depth, Width, WallThickness, Girth, InternalFilletRadius) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Depth = Depth; - this.Width = Width; - this.WallThickness = WallThickness; - this.Girth = Girth; - this.InternalFilletRadius = InternalFilletRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Depth = tape[ptr++]; - let Width = tape[ptr++]; - let WallThickness = tape[ptr++]; - let Girth = tape[ptr++]; - let InternalFilletRadius = tape[ptr++]; - return new IfcCShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, Width, WallThickness, Girth, InternalFilletRadius); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Depth); - args.push(this.Width); - args.push(this.WallThickness); - args.push(this.Girth); - args.push(this.InternalFilletRadius); - return args; - } -}; -var IfcCableCarrierFitting = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableCarrierFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableCarrierFittingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableCarrierFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableCarrierSegment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableCarrierSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableCarrierSegmentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableCarrierSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableFitting = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableFittingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableSegment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCableSegmentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCableSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCaissonFoundation = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCaissonFoundation(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCaissonFoundationType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCaissonFoundationType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCartesianPoint = class { - constructor(expressID, type, Coordinates) { - this.expressID = expressID; - this.type = type; - this.Coordinates = Coordinates; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Coordinates = tape[ptr++]; - return new IfcCartesianPoint(expressID, type, Coordinates); - } - ToTape() { - let args = []; - args.push(this.Coordinates); - return args; - } -}; -var IfcCartesianPointList = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcCartesianPointList(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcCartesianPointList2D = class { - constructor(expressID, type, CoordList, TagList) { - this.expressID = expressID; - this.type = type; - this.CoordList = CoordList; - this.TagList = TagList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CoordList = tape[ptr++]; - let TagList = tape[ptr++]; - return new IfcCartesianPointList2D(expressID, type, CoordList, TagList); - } - ToTape() { - let args = []; - args.push(this.CoordList); - args.push(this.TagList); - return args; - } -}; -var IfcCartesianPointList3D = class { - constructor(expressID, type, CoordList, TagList) { - this.expressID = expressID; - this.type = type; - this.CoordList = CoordList; - this.TagList = TagList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CoordList = tape[ptr++]; - let TagList = tape[ptr++]; - return new IfcCartesianPointList3D(expressID, type, CoordList, TagList); - } - ToTape() { - let args = []; - args.push(this.CoordList); - args.push(this.TagList); - return args; - } -}; -var IfcCartesianTransformationOperator = class { - constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale) { - this.expressID = expressID; - this.type = type; - this.Axis1 = Axis1; - this.Axis2 = Axis2; - this.LocalOrigin = LocalOrigin; - this.Scale = Scale; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Axis1 = tape[ptr++]; - let Axis2 = tape[ptr++]; - let LocalOrigin = tape[ptr++]; - let Scale = tape[ptr++]; - return new IfcCartesianTransformationOperator(expressID, type, Axis1, Axis2, LocalOrigin, Scale); - } - ToTape() { - let args = []; - args.push(this.Axis1); - args.push(this.Axis2); - args.push(this.LocalOrigin); - args.push(this.Scale); - return args; - } -}; -var IfcCartesianTransformationOperator2D = class { - constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale) { - this.expressID = expressID; - this.type = type; - this.Axis1 = Axis1; - this.Axis2 = Axis2; - this.LocalOrigin = LocalOrigin; - this.Scale = Scale; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Axis1 = tape[ptr++]; - let Axis2 = tape[ptr++]; - let LocalOrigin = tape[ptr++]; - let Scale = tape[ptr++]; - return new IfcCartesianTransformationOperator2D(expressID, type, Axis1, Axis2, LocalOrigin, Scale); - } - ToTape() { - let args = []; - args.push(this.Axis1); - args.push(this.Axis2); - args.push(this.LocalOrigin); - args.push(this.Scale); - return args; - } -}; -var IfcCartesianTransformationOperator2DnonUniform = class { - constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Scale2) { - this.expressID = expressID; - this.type = type; - this.Axis1 = Axis1; - this.Axis2 = Axis2; - this.LocalOrigin = LocalOrigin; - this.Scale = Scale; - this.Scale2 = Scale2; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Axis1 = tape[ptr++]; - let Axis2 = tape[ptr++]; - let LocalOrigin = tape[ptr++]; - let Scale = tape[ptr++]; - let Scale2 = tape[ptr++]; - return new IfcCartesianTransformationOperator2DnonUniform(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Scale2); - } - ToTape() { - let args = []; - args.push(this.Axis1); - args.push(this.Axis2); - args.push(this.LocalOrigin); - args.push(this.Scale); - args.push(this.Scale2); - return args; - } -}; -var IfcCartesianTransformationOperator3D = class { - constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3) { - this.expressID = expressID; - this.type = type; - this.Axis1 = Axis1; - this.Axis2 = Axis2; - this.LocalOrigin = LocalOrigin; - this.Scale = Scale; - this.Axis3 = Axis3; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Axis1 = tape[ptr++]; - let Axis2 = tape[ptr++]; - let LocalOrigin = tape[ptr++]; - let Scale = tape[ptr++]; - let Axis3 = tape[ptr++]; - return new IfcCartesianTransformationOperator3D(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3); - } - ToTape() { - let args = []; - args.push(this.Axis1); - args.push(this.Axis2); - args.push(this.LocalOrigin); - args.push(this.Scale); - args.push(this.Axis3); - return args; - } -}; -var IfcCartesianTransformationOperator3DnonUniform = class { - constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3, Scale2, Scale3) { - this.expressID = expressID; - this.type = type; - this.Axis1 = Axis1; - this.Axis2 = Axis2; - this.LocalOrigin = LocalOrigin; - this.Scale = Scale; - this.Axis3 = Axis3; - this.Scale2 = Scale2; - this.Scale3 = Scale3; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Axis1 = tape[ptr++]; - let Axis2 = tape[ptr++]; - let LocalOrigin = tape[ptr++]; - let Scale = tape[ptr++]; - let Axis3 = tape[ptr++]; - let Scale2 = tape[ptr++]; - let Scale3 = tape[ptr++]; - return new IfcCartesianTransformationOperator3DnonUniform(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3, Scale2, Scale3); - } - ToTape() { - let args = []; - args.push(this.Axis1); - args.push(this.Axis2); - args.push(this.LocalOrigin); - args.push(this.Scale); - args.push(this.Axis3); - args.push(this.Scale2); - args.push(this.Scale3); - return args; - } -}; -var IfcCenterLineProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Curve, Thickness) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Curve = Curve; - this.Thickness = Thickness; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Curve = tape[ptr++]; - let Thickness = tape[ptr++]; - return new IfcCenterLineProfileDef(expressID, type, ProfileType, ProfileName, Curve, Thickness); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Curve); - args.push(this.Thickness); - return args; - } -}; -var IfcChiller = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcChiller(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcChillerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcChillerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcChimney = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcChimney(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcChimneyType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcChimneyType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCircle = class { - constructor(expressID, type, Position, Radius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.Radius = Radius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - return new IfcCircle(expressID, type, Position, Radius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.Radius); - return args; - } -}; -var IfcCircleHollowProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Radius, WallThickness) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Radius = Radius; - this.WallThickness = WallThickness; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - let WallThickness = tape[ptr++]; - return new IfcCircleHollowProfileDef(expressID, type, ProfileType, ProfileName, Position, Radius, WallThickness); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Radius); - args.push(this.WallThickness); - return args; - } -}; -var IfcCircleProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Radius) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Radius = Radius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - return new IfcCircleProfileDef(expressID, type, ProfileType, ProfileName, Position, Radius); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Radius); - return args; - } -}; -var IfcCircularArcSegment2D = class { - constructor(expressID, type, StartPoint, StartDirection, SegmentLength, Radius, IsCCW) { - this.expressID = expressID; - this.type = type; - this.StartPoint = StartPoint; - this.StartDirection = StartDirection; - this.SegmentLength = SegmentLength; - this.Radius = Radius; - this.IsCCW = IsCCW; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let StartPoint = tape[ptr++]; - let StartDirection = tape[ptr++]; - let SegmentLength = tape[ptr++]; - let Radius = tape[ptr++]; - let IsCCW = tape[ptr++]; - return new IfcCircularArcSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength, Radius, IsCCW); - } - ToTape() { - let args = []; - args.push(this.StartPoint); - args.push(this.StartDirection); - args.push(this.SegmentLength); - args.push(this.Radius); - args.push(this.IsCCW); - return args; - } -}; -var IfcCivilElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcCivilElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcCivilElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcCivilElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcClassification = class { - constructor(expressID, type, Source, Edition, EditionDate, Name, Description, Location, ReferenceTokens) { - this.expressID = expressID; - this.type = type; - this.Source = Source; - this.Edition = Edition; - this.EditionDate = EditionDate; - this.Name = Name; - this.Description = Description; - this.Location = Location; - this.ReferenceTokens = ReferenceTokens; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Source = tape[ptr++]; - let Edition = tape[ptr++]; - let EditionDate = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Location = tape[ptr++]; - let ReferenceTokens = tape[ptr++]; - return new IfcClassification(expressID, type, Source, Edition, EditionDate, Name, Description, Location, ReferenceTokens); - } - ToTape() { - let args = []; - args.push(this.Source); - args.push(this.Edition); - args.push(this.EditionDate); - args.push(this.Name); - args.push(this.Description); - args.push(this.Location); - args.push(this.ReferenceTokens); - return args; - } -}; -var IfcClassificationReference = class { - constructor(expressID, type, Location, Identification, Name, ReferencedSource, Description, Sort) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - this.ReferencedSource = ReferencedSource; - this.Description = Description; - this.Sort = Sort; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - let ReferencedSource = tape[ptr++]; - let Description = tape[ptr++]; - let Sort = tape[ptr++]; - return new IfcClassificationReference(expressID, type, Location, Identification, Name, ReferencedSource, Description, Sort); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - args.push(this.ReferencedSource); - args.push(this.Description); - args.push(this.Sort); - return args; - } -}; -var IfcClosedShell = class { - constructor(expressID, type, CfsFaces) { - this.expressID = expressID; - this.type = type; - this.CfsFaces = CfsFaces; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CfsFaces = tape[ptr++]; - return new IfcClosedShell(expressID, type, CfsFaces); - } - ToTape() { - let args = []; - args.push(this.CfsFaces); - return args; - } -}; -var IfcCoil = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCoil(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCoilType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCoilType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcColourRgb = class { - constructor(expressID, type, Name, Red, Green, Blue) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Red = Red; - this.Green = Green; - this.Blue = Blue; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Red = tape[ptr++]; - let Green = tape[ptr++]; - let Blue = tape[ptr++]; - return new IfcColourRgb(expressID, type, Name, Red, Green, Blue); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Red); - args.push(this.Green); - args.push(this.Blue); - return args; - } -}; -var IfcColourRgbList = class { - constructor(expressID, type, ColourList) { - this.expressID = expressID; - this.type = type; - this.ColourList = ColourList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ColourList = tape[ptr++]; - return new IfcColourRgbList(expressID, type, ColourList); - } - ToTape() { - let args = []; - args.push(this.ColourList); - return args; - } -}; -var IfcColourSpecification = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcColourSpecification(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcColumn = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcColumn(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcColumnStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcColumnStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcColumnType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcColumnType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCommunicationsAppliance = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCommunicationsAppliance(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCommunicationsApplianceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCommunicationsApplianceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcComplexProperty = class { - constructor(expressID, type, Name, Description, UsageName, HasProperties) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.UsageName = UsageName; - this.HasProperties = HasProperties; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let UsageName = tape[ptr++]; - let HasProperties = tape[ptr++]; - return new IfcComplexProperty(expressID, type, Name, Description, UsageName, HasProperties); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.UsageName); - args.push(this.HasProperties); - return args; - } -}; -var IfcComplexPropertyTemplate = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, UsageName, TemplateType, HasPropertyTemplates) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.UsageName = UsageName; - this.TemplateType = TemplateType; - this.HasPropertyTemplates = HasPropertyTemplates; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let UsageName = tape[ptr++]; - let TemplateType = tape[ptr++]; - let HasPropertyTemplates = tape[ptr++]; - return new IfcComplexPropertyTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, UsageName, TemplateType, HasPropertyTemplates); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.UsageName); - args.push(this.TemplateType); - args.push(this.HasPropertyTemplates); - return args; - } -}; -var IfcCompositeCurve = class { - constructor(expressID, type, Segments, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.Segments = Segments; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Segments = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcCompositeCurve(expressID, type, Segments, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.Segments); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcCompositeCurveOnSurface = class { - constructor(expressID, type, Segments, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.Segments = Segments; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Segments = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcCompositeCurveOnSurface(expressID, type, Segments, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.Segments); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcCompositeCurveSegment = class { - constructor(expressID, type, Transition, SameSense, ParentCurve) { - this.expressID = expressID; - this.type = type; - this.Transition = Transition; - this.SameSense = SameSense; - this.ParentCurve = ParentCurve; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Transition = tape[ptr++]; - let SameSense = tape[ptr++]; - let ParentCurve = tape[ptr++]; - return new IfcCompositeCurveSegment(expressID, type, Transition, SameSense, ParentCurve); - } - ToTape() { - let args = []; - args.push(this.Transition); - args.push(this.SameSense); - args.push(this.ParentCurve); - return args; - } -}; -var IfcCompositeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Profiles, Label) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Profiles = Profiles; - this.Label = Label; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Profiles = tape[ptr++]; - let Label = tape[ptr++]; - return new IfcCompositeProfileDef(expressID, type, ProfileType, ProfileName, Profiles, Label); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Profiles); - args.push(this.Label); - return args; - } -}; -var IfcCompressor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCompressor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCompressorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCompressorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCondenser = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCondenser(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCondenserType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCondenserType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConic = class { - constructor(expressID, type, Position) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - return new IfcConic(expressID, type, Position); - } - ToTape() { - let args = []; - args.push(this.Position); - return args; - } -}; -var IfcConnectedFaceSet = class { - constructor(expressID, type, CfsFaces) { - this.expressID = expressID; - this.type = type; - this.CfsFaces = CfsFaces; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CfsFaces = tape[ptr++]; - return new IfcConnectedFaceSet(expressID, type, CfsFaces); - } - ToTape() { - let args = []; - args.push(this.CfsFaces); - return args; - } -}; -var IfcConnectionCurveGeometry = class { - constructor(expressID, type, CurveOnRelatingElement, CurveOnRelatedElement) { - this.expressID = expressID; - this.type = type; - this.CurveOnRelatingElement = CurveOnRelatingElement; - this.CurveOnRelatedElement = CurveOnRelatedElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CurveOnRelatingElement = tape[ptr++]; - let CurveOnRelatedElement = tape[ptr++]; - return new IfcConnectionCurveGeometry(expressID, type, CurveOnRelatingElement, CurveOnRelatedElement); - } - ToTape() { - let args = []; - args.push(this.CurveOnRelatingElement); - args.push(this.CurveOnRelatedElement); - return args; - } -}; -var IfcConnectionGeometry = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcConnectionGeometry(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcConnectionPointEccentricity = class { - constructor(expressID, type, PointOnRelatingElement, PointOnRelatedElement, EccentricityInX, EccentricityInY, EccentricityInZ) { - this.expressID = expressID; - this.type = type; - this.PointOnRelatingElement = PointOnRelatingElement; - this.PointOnRelatedElement = PointOnRelatedElement; - this.EccentricityInX = EccentricityInX; - this.EccentricityInY = EccentricityInY; - this.EccentricityInZ = EccentricityInZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let PointOnRelatingElement = tape[ptr++]; - let PointOnRelatedElement = tape[ptr++]; - let EccentricityInX = tape[ptr++]; - let EccentricityInY = tape[ptr++]; - let EccentricityInZ = tape[ptr++]; - return new IfcConnectionPointEccentricity(expressID, type, PointOnRelatingElement, PointOnRelatedElement, EccentricityInX, EccentricityInY, EccentricityInZ); - } - ToTape() { - let args = []; - args.push(this.PointOnRelatingElement); - args.push(this.PointOnRelatedElement); - args.push(this.EccentricityInX); - args.push(this.EccentricityInY); - args.push(this.EccentricityInZ); - return args; - } -}; -var IfcConnectionPointGeometry = class { - constructor(expressID, type, PointOnRelatingElement, PointOnRelatedElement) { - this.expressID = expressID; - this.type = type; - this.PointOnRelatingElement = PointOnRelatingElement; - this.PointOnRelatedElement = PointOnRelatedElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let PointOnRelatingElement = tape[ptr++]; - let PointOnRelatedElement = tape[ptr++]; - return new IfcConnectionPointGeometry(expressID, type, PointOnRelatingElement, PointOnRelatedElement); - } - ToTape() { - let args = []; - args.push(this.PointOnRelatingElement); - args.push(this.PointOnRelatedElement); - return args; - } -}; -var IfcConnectionSurfaceGeometry = class { - constructor(expressID, type, SurfaceOnRelatingElement, SurfaceOnRelatedElement) { - this.expressID = expressID; - this.type = type; - this.SurfaceOnRelatingElement = SurfaceOnRelatingElement; - this.SurfaceOnRelatedElement = SurfaceOnRelatedElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SurfaceOnRelatingElement = tape[ptr++]; - let SurfaceOnRelatedElement = tape[ptr++]; - return new IfcConnectionSurfaceGeometry(expressID, type, SurfaceOnRelatingElement, SurfaceOnRelatedElement); - } - ToTape() { - let args = []; - args.push(this.SurfaceOnRelatingElement); - args.push(this.SurfaceOnRelatedElement); - return args; - } -}; -var IfcConnectionVolumeGeometry = class { - constructor(expressID, type, VolumeOnRelatingElement, VolumeOnRelatedElement) { - this.expressID = expressID; - this.type = type; - this.VolumeOnRelatingElement = VolumeOnRelatingElement; - this.VolumeOnRelatedElement = VolumeOnRelatedElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let VolumeOnRelatingElement = tape[ptr++]; - let VolumeOnRelatedElement = tape[ptr++]; - return new IfcConnectionVolumeGeometry(expressID, type, VolumeOnRelatingElement, VolumeOnRelatedElement); - } - ToTape() { - let args = []; - args.push(this.VolumeOnRelatingElement); - args.push(this.VolumeOnRelatedElement); - return args; - } -}; -var IfcConstraint = class { - constructor(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.ConstraintGrade = ConstraintGrade; - this.ConstraintSource = ConstraintSource; - this.CreatingActor = CreatingActor; - this.CreationTime = CreationTime; - this.UserDefinedGrade = UserDefinedGrade; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ConstraintGrade = tape[ptr++]; - let ConstraintSource = tape[ptr++]; - let CreatingActor = tape[ptr++]; - let CreationTime = tape[ptr++]; - let UserDefinedGrade = tape[ptr++]; - return new IfcConstraint(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.ConstraintGrade); - args.push(this.ConstraintSource); - args.push(this.CreatingActor); - args.push(this.CreationTime); - args.push(this.UserDefinedGrade); - return args; - } -}; -var IfcConstructionEquipmentResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcConstructionEquipmentResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConstructionEquipmentResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcConstructionEquipmentResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConstructionMaterialResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcConstructionMaterialResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConstructionMaterialResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcConstructionMaterialResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConstructionProductResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcConstructionProductResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConstructionProductResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcConstructionProductResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConstructionResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - return new IfcConstructionResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - return args; - } -}; -var IfcConstructionResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - return new IfcConstructionResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - return args; - } -}; -var IfcContext = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.LongName = LongName; - this.Phase = Phase; - this.RepresentationContexts = RepresentationContexts; - this.UnitsInContext = UnitsInContext; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let LongName = tape[ptr++]; - let Phase = tape[ptr++]; - let RepresentationContexts = tape[ptr++]; - let UnitsInContext = tape[ptr++]; - return new IfcContext(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.LongName); - args.push(this.Phase); - args.push(this.RepresentationContexts); - args.push(this.UnitsInContext); - return args; - } -}; -var IfcContextDependentUnit = class { - constructor(expressID, type, Dimensions, UnitType, Name) { - this.expressID = expressID; - this.type = type; - this.Dimensions = Dimensions; - this.UnitType = UnitType; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Dimensions = tape[ptr++]; - let UnitType = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcContextDependentUnit(expressID, type, Dimensions, UnitType, Name); - } - ToTape() { - let args = []; - args.push(this.Dimensions); - args.push(this.UnitType); - args.push(this.Name); - return args; - } -}; -var IfcControl = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - return new IfcControl(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - return args; - } -}; -var IfcController = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcController(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcControllerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcControllerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcConversionBasedUnit = class { - constructor(expressID, type, Dimensions, UnitType, Name, ConversionFactor) { - this.expressID = expressID; - this.type = type; - this.Dimensions = Dimensions; - this.UnitType = UnitType; - this.Name = Name; - this.ConversionFactor = ConversionFactor; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Dimensions = tape[ptr++]; - let UnitType = tape[ptr++]; - let Name = tape[ptr++]; - let ConversionFactor = tape[ptr++]; - return new IfcConversionBasedUnit(expressID, type, Dimensions, UnitType, Name, ConversionFactor); - } - ToTape() { - let args = []; - args.push(this.Dimensions); - args.push(this.UnitType); - args.push(this.Name); - args.push(this.ConversionFactor); - return args; - } -}; -var IfcConversionBasedUnitWithOffset = class { - constructor(expressID, type, Dimensions, UnitType, Name, ConversionFactor, ConversionOffset) { - this.expressID = expressID; - this.type = type; - this.Dimensions = Dimensions; - this.UnitType = UnitType; - this.Name = Name; - this.ConversionFactor = ConversionFactor; - this.ConversionOffset = ConversionOffset; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Dimensions = tape[ptr++]; - let UnitType = tape[ptr++]; - let Name = tape[ptr++]; - let ConversionFactor = tape[ptr++]; - let ConversionOffset = tape[ptr++]; - return new IfcConversionBasedUnitWithOffset(expressID, type, Dimensions, UnitType, Name, ConversionFactor, ConversionOffset); - } - ToTape() { - let args = []; - args.push(this.Dimensions); - args.push(this.UnitType); - args.push(this.Name); - args.push(this.ConversionFactor); - args.push(this.ConversionOffset); - return args; - } -}; -var IfcCooledBeam = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCooledBeam(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCooledBeamType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCooledBeamType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCoolingTower = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCoolingTower(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCoolingTowerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCoolingTowerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCoordinateOperation = class { - constructor(expressID, type, SourceCRS, TargetCRS) { - this.expressID = expressID; - this.type = type; - this.SourceCRS = SourceCRS; - this.TargetCRS = TargetCRS; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SourceCRS = tape[ptr++]; - let TargetCRS = tape[ptr++]; - return new IfcCoordinateOperation(expressID, type, SourceCRS, TargetCRS); - } - ToTape() { - let args = []; - args.push(this.SourceCRS); - args.push(this.TargetCRS); - return args; - } -}; -var IfcCoordinateReferenceSystem = class { - constructor(expressID, type, Name, Description, GeodeticDatum, VerticalDatum) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.GeodeticDatum = GeodeticDatum; - this.VerticalDatum = VerticalDatum; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let GeodeticDatum = tape[ptr++]; - let VerticalDatum = tape[ptr++]; - return new IfcCoordinateReferenceSystem(expressID, type, Name, Description, GeodeticDatum, VerticalDatum); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.GeodeticDatum); - args.push(this.VerticalDatum); - return args; - } -}; -var IfcCostItem = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, CostValues, CostQuantities) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.PredefinedType = PredefinedType; - this.CostValues = CostValues; - this.CostQuantities = CostQuantities; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let CostValues = tape[ptr++]; - let CostQuantities = tape[ptr++]; - return new IfcCostItem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, CostValues, CostQuantities); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.PredefinedType); - args.push(this.CostValues); - args.push(this.CostQuantities); - return args; - } -}; -var IfcCostSchedule = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, SubmittedOn, UpdateDate) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.PredefinedType = PredefinedType; - this.Status = Status; - this.SubmittedOn = SubmittedOn; - this.UpdateDate = UpdateDate; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Status = tape[ptr++]; - let SubmittedOn = tape[ptr++]; - let UpdateDate = tape[ptr++]; - return new IfcCostSchedule(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, SubmittedOn, UpdateDate); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.PredefinedType); - args.push(this.Status); - args.push(this.SubmittedOn); - args.push(this.UpdateDate); - return args; - } -}; -var IfcCostValue = class { - constructor(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.AppliedValue = AppliedValue; - this.UnitBasis = UnitBasis; - this.ApplicableDate = ApplicableDate; - this.FixedUntilDate = FixedUntilDate; - this.Category = Category; - this.Condition = Condition; - this.ArithmeticOperator = ArithmeticOperator; - this.Components = Components; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let AppliedValue = tape[ptr++]; - let UnitBasis = tape[ptr++]; - let ApplicableDate = tape[ptr++]; - let FixedUntilDate = tape[ptr++]; - let Category = tape[ptr++]; - let Condition = tape[ptr++]; - let ArithmeticOperator = tape[ptr++]; - let Components = tape[ptr++]; - return new IfcCostValue(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.AppliedValue); - args.push(this.UnitBasis); - args.push(this.ApplicableDate); - args.push(this.FixedUntilDate); - args.push(this.Category); - args.push(this.Condition); - args.push(this.ArithmeticOperator); - args.push(this.Components); - return args; - } -}; -var IfcCovering = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCovering(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCoveringType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCoveringType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCrewResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCrewResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCrewResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCrewResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCsgPrimitive3D = class { - constructor(expressID, type, Position) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - return new IfcCsgPrimitive3D(expressID, type, Position); - } - ToTape() { - let args = []; - args.push(this.Position); - return args; - } -}; -var IfcCsgSolid = class { - constructor(expressID, type, TreeRootExpression) { - this.expressID = expressID; - this.type = type; - this.TreeRootExpression = TreeRootExpression; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TreeRootExpression = tape[ptr++]; - return new IfcCsgSolid(expressID, type, TreeRootExpression); - } - ToTape() { - let args = []; - args.push(this.TreeRootExpression); - return args; - } -}; -var IfcCurrencyRelationship = class { - constructor(expressID, type, Name, Description, RelatingMonetaryUnit, RelatedMonetaryUnit, ExchangeRate, RateDateTime, RateSource) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingMonetaryUnit = RelatingMonetaryUnit; - this.RelatedMonetaryUnit = RelatedMonetaryUnit; - this.ExchangeRate = ExchangeRate; - this.RateDateTime = RateDateTime; - this.RateSource = RateSource; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingMonetaryUnit = tape[ptr++]; - let RelatedMonetaryUnit = tape[ptr++]; - let ExchangeRate = tape[ptr++]; - let RateDateTime = tape[ptr++]; - let RateSource = tape[ptr++]; - return new IfcCurrencyRelationship(expressID, type, Name, Description, RelatingMonetaryUnit, RelatedMonetaryUnit, ExchangeRate, RateDateTime, RateSource); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingMonetaryUnit); - args.push(this.RelatedMonetaryUnit); - args.push(this.ExchangeRate); - args.push(this.RateDateTime); - args.push(this.RateSource); - return args; - } -}; -var IfcCurtainWall = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCurtainWall(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCurtainWallType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcCurtainWallType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcCurve = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcCurve(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcCurveBoundedPlane = class { - constructor(expressID, type, BasisSurface, OuterBoundary, InnerBoundaries) { - this.expressID = expressID; - this.type = type; - this.BasisSurface = BasisSurface; - this.OuterBoundary = OuterBoundary; - this.InnerBoundaries = InnerBoundaries; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisSurface = tape[ptr++]; - let OuterBoundary = tape[ptr++]; - let InnerBoundaries = tape[ptr++]; - return new IfcCurveBoundedPlane(expressID, type, BasisSurface, OuterBoundary, InnerBoundaries); - } - ToTape() { - let args = []; - args.push(this.BasisSurface); - args.push(this.OuterBoundary); - args.push(this.InnerBoundaries); - return args; - } -}; -var IfcCurveBoundedSurface = class { - constructor(expressID, type, BasisSurface, Boundaries, ImplicitOuter) { - this.expressID = expressID; - this.type = type; - this.BasisSurface = BasisSurface; - this.Boundaries = Boundaries; - this.ImplicitOuter = ImplicitOuter; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisSurface = tape[ptr++]; - let Boundaries = tape[ptr++]; - let ImplicitOuter = tape[ptr++]; - return new IfcCurveBoundedSurface(expressID, type, BasisSurface, Boundaries, ImplicitOuter); - } - ToTape() { - let args = []; - args.push(this.BasisSurface); - args.push(this.Boundaries); - args.push(this.ImplicitOuter); - return args; - } -}; -var IfcCurveSegment2D = class { - constructor(expressID, type, StartPoint, StartDirection, SegmentLength) { - this.expressID = expressID; - this.type = type; - this.StartPoint = StartPoint; - this.StartDirection = StartDirection; - this.SegmentLength = SegmentLength; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let StartPoint = tape[ptr++]; - let StartDirection = tape[ptr++]; - let SegmentLength = tape[ptr++]; - return new IfcCurveSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength); - } - ToTape() { - let args = []; - args.push(this.StartPoint); - args.push(this.StartDirection); - args.push(this.SegmentLength); - return args; - } -}; -var IfcCurveStyle = class { - constructor(expressID, type, Name, CurveFont, CurveWidth, CurveColour, ModelOrDraughting) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.CurveFont = CurveFont; - this.CurveWidth = CurveWidth; - this.CurveColour = CurveColour; - this.ModelOrDraughting = ModelOrDraughting; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let CurveFont = tape[ptr++]; - let CurveWidth = tape[ptr++]; - let CurveColour = tape[ptr++]; - let ModelOrDraughting = tape[ptr++]; - return new IfcCurveStyle(expressID, type, Name, CurveFont, CurveWidth, CurveColour, ModelOrDraughting); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.CurveFont); - args.push(this.CurveWidth); - args.push(this.CurveColour); - args.push(this.ModelOrDraughting); - return args; - } -}; -var IfcCurveStyleFont = class { - constructor(expressID, type, Name, PatternList) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.PatternList = PatternList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let PatternList = tape[ptr++]; - return new IfcCurveStyleFont(expressID, type, Name, PatternList); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.PatternList); - return args; - } -}; -var IfcCurveStyleFontAndScaling = class { - constructor(expressID, type, Name, CurveFont, CurveFontScaling) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.CurveFont = CurveFont; - this.CurveFontScaling = CurveFontScaling; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let CurveFont = tape[ptr++]; - let CurveFontScaling = tape[ptr++]; - return new IfcCurveStyleFontAndScaling(expressID, type, Name, CurveFont, CurveFontScaling); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.CurveFont); - args.push(this.CurveFontScaling); - return args; - } -}; -var IfcCurveStyleFontPattern = class { - constructor(expressID, type, VisibleSegmentLength, InvisibleSegmentLength) { - this.expressID = expressID; - this.type = type; - this.VisibleSegmentLength = VisibleSegmentLength; - this.InvisibleSegmentLength = InvisibleSegmentLength; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let VisibleSegmentLength = tape[ptr++]; - let InvisibleSegmentLength = tape[ptr++]; - return new IfcCurveStyleFontPattern(expressID, type, VisibleSegmentLength, InvisibleSegmentLength); - } - ToTape() { - let args = []; - args.push(this.VisibleSegmentLength); - args.push(this.InvisibleSegmentLength); - return args; - } -}; -var IfcCylindricalSurface = class { - constructor(expressID, type, Position, Radius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.Radius = Radius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - return new IfcCylindricalSurface(expressID, type, Position, Radius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.Radius); - return args; - } -}; -var IfcDamper = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDamper(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDamperType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDamperType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDeepFoundation = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcDeepFoundation(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcDeepFoundationType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcDeepFoundationType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcDerivedProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.ParentProfile = ParentProfile; - this.Operator = Operator; - this.Label = Label; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let ParentProfile = tape[ptr++]; - let Operator = tape[ptr++]; - let Label = tape[ptr++]; - return new IfcDerivedProfileDef(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.ParentProfile); - args.push(this.Operator); - args.push(this.Label); - return args; - } -}; -var IfcDerivedUnit = class { - constructor(expressID, type, Elements, UnitType, UserDefinedType) { - this.expressID = expressID; - this.type = type; - this.Elements = Elements; - this.UnitType = UnitType; - this.UserDefinedType = UserDefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Elements = tape[ptr++]; - let UnitType = tape[ptr++]; - let UserDefinedType = tape[ptr++]; - return new IfcDerivedUnit(expressID, type, Elements, UnitType, UserDefinedType); - } - ToTape() { - let args = []; - args.push(this.Elements); - args.push(this.UnitType); - args.push(this.UserDefinedType); - return args; - } -}; -var IfcDerivedUnitElement = class { - constructor(expressID, type, Unit, Exponent) { - this.expressID = expressID; - this.type = type; - this.Unit = Unit; - this.Exponent = Exponent; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Unit = tape[ptr++]; - let Exponent = tape[ptr++]; - return new IfcDerivedUnitElement(expressID, type, Unit, Exponent); - } - ToTape() { - let args = []; - args.push(this.Unit); - args.push(this.Exponent); - return args; - } -}; -var IfcDimensionalExponents = class { - constructor(expressID, type, LengthExponent, MassExponent, TimeExponent, ElectricCurrentExponent, ThermodynamicTemperatureExponent, AmountOfSubstanceExponent, LuminousIntensityExponent) { - this.expressID = expressID; - this.type = type; - this.LengthExponent = LengthExponent; - this.MassExponent = MassExponent; - this.TimeExponent = TimeExponent; - this.ElectricCurrentExponent = ElectricCurrentExponent; - this.ThermodynamicTemperatureExponent = ThermodynamicTemperatureExponent; - this.AmountOfSubstanceExponent = AmountOfSubstanceExponent; - this.LuminousIntensityExponent = LuminousIntensityExponent; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let LengthExponent = tape[ptr++]; - let MassExponent = tape[ptr++]; - let TimeExponent = tape[ptr++]; - let ElectricCurrentExponent = tape[ptr++]; - let ThermodynamicTemperatureExponent = tape[ptr++]; - let AmountOfSubstanceExponent = tape[ptr++]; - let LuminousIntensityExponent = tape[ptr++]; - return new IfcDimensionalExponents(expressID, type, LengthExponent, MassExponent, TimeExponent, ElectricCurrentExponent, ThermodynamicTemperatureExponent, AmountOfSubstanceExponent, LuminousIntensityExponent); - } - ToTape() { - let args = []; - args.push(this.LengthExponent); - args.push(this.MassExponent); - args.push(this.TimeExponent); - args.push(this.ElectricCurrentExponent); - args.push(this.ThermodynamicTemperatureExponent); - args.push(this.AmountOfSubstanceExponent); - args.push(this.LuminousIntensityExponent); - return args; - } -}; -var IfcDirection = class { - constructor(expressID, type, DirectionRatios) { - this.expressID = expressID; - this.type = type; - this.DirectionRatios = DirectionRatios; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let DirectionRatios = tape[ptr++]; - return new IfcDirection(expressID, type, DirectionRatios); - } - ToTape() { - let args = []; - args.push(this.DirectionRatios); - return args; - } -}; -var IfcDiscreteAccessory = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDiscreteAccessory(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDiscreteAccessoryType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDiscreteAccessoryType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDistanceExpression = class { - constructor(expressID, type, DistanceAlong, OffsetLateral, OffsetVertical, OffsetLongitudinal, AlongHorizontal) { - this.expressID = expressID; - this.type = type; - this.DistanceAlong = DistanceAlong; - this.OffsetLateral = OffsetLateral; - this.OffsetVertical = OffsetVertical; - this.OffsetLongitudinal = OffsetLongitudinal; - this.AlongHorizontal = AlongHorizontal; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let DistanceAlong = tape[ptr++]; - let OffsetLateral = tape[ptr++]; - let OffsetVertical = tape[ptr++]; - let OffsetLongitudinal = tape[ptr++]; - let AlongHorizontal = tape[ptr++]; - return new IfcDistanceExpression(expressID, type, DistanceAlong, OffsetLateral, OffsetVertical, OffsetLongitudinal, AlongHorizontal); - } - ToTape() { - let args = []; - args.push(this.DistanceAlong); - args.push(this.OffsetLateral); - args.push(this.OffsetVertical); - args.push(this.OffsetLongitudinal); - args.push(this.AlongHorizontal); - return args; - } -}; -var IfcDistributionChamberElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDistributionChamberElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDistributionChamberElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDistributionChamberElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDistributionCircuit = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.LongName = LongName; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let LongName = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDistributionCircuit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.LongName); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDistributionControlElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcDistributionControlElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcDistributionControlElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcDistributionControlElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcDistributionElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcDistributionElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcDistributionElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcDistributionElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcDistributionFlowElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcDistributionFlowElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcDistributionFlowElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcDistributionFlowElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcDistributionPort = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, FlowDirection, PredefinedType, SystemType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.FlowDirection = FlowDirection; - this.PredefinedType = PredefinedType; - this.SystemType = SystemType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let FlowDirection = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let SystemType = tape[ptr++]; - return new IfcDistributionPort(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, FlowDirection, PredefinedType, SystemType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.FlowDirection); - args.push(this.PredefinedType); - args.push(this.SystemType); - return args; - } -}; -var IfcDistributionSystem = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.LongName = LongName; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let LongName = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDistributionSystem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.LongName); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDocumentInformation = class { - constructor(expressID, type, Identification, Name, Description, Location, Purpose, IntendedUse, Scope, Revision, DocumentOwner, Editors, CreationTime, LastRevisionTime, ElectronicFormat, ValidFrom, ValidUntil, Confidentiality, Status) { - this.expressID = expressID; - this.type = type; - this.Identification = Identification; - this.Name = Name; - this.Description = Description; - this.Location = Location; - this.Purpose = Purpose; - this.IntendedUse = IntendedUse; - this.Scope = Scope; - this.Revision = Revision; - this.DocumentOwner = DocumentOwner; - this.Editors = Editors; - this.CreationTime = CreationTime; - this.LastRevisionTime = LastRevisionTime; - this.ElectronicFormat = ElectronicFormat; - this.ValidFrom = ValidFrom; - this.ValidUntil = ValidUntil; - this.Confidentiality = Confidentiality; - this.Status = Status; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Location = tape[ptr++]; - let Purpose = tape[ptr++]; - let IntendedUse = tape[ptr++]; - let Scope = tape[ptr++]; - let Revision = tape[ptr++]; - let DocumentOwner = tape[ptr++]; - let Editors = tape[ptr++]; - let CreationTime = tape[ptr++]; - let LastRevisionTime = tape[ptr++]; - let ElectronicFormat = tape[ptr++]; - let ValidFrom = tape[ptr++]; - let ValidUntil = tape[ptr++]; - let Confidentiality = tape[ptr++]; - let Status = tape[ptr++]; - return new IfcDocumentInformation(expressID, type, Identification, Name, Description, Location, Purpose, IntendedUse, Scope, Revision, DocumentOwner, Editors, CreationTime, LastRevisionTime, ElectronicFormat, ValidFrom, ValidUntil, Confidentiality, Status); - } - ToTape() { - let args = []; - args.push(this.Identification); - args.push(this.Name); - args.push(this.Description); - args.push(this.Location); - args.push(this.Purpose); - args.push(this.IntendedUse); - args.push(this.Scope); - args.push(this.Revision); - args.push(this.DocumentOwner); - args.push(this.Editors); - args.push(this.CreationTime); - args.push(this.LastRevisionTime); - args.push(this.ElectronicFormat); - args.push(this.ValidFrom); - args.push(this.ValidUntil); - args.push(this.Confidentiality); - args.push(this.Status); - return args; - } -}; -var IfcDocumentInformationRelationship = class { - constructor(expressID, type, Name, Description, RelatingDocument, RelatedDocuments, RelationshipType) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingDocument = RelatingDocument; - this.RelatedDocuments = RelatedDocuments; - this.RelationshipType = RelationshipType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingDocument = tape[ptr++]; - let RelatedDocuments = tape[ptr++]; - let RelationshipType = tape[ptr++]; - return new IfcDocumentInformationRelationship(expressID, type, Name, Description, RelatingDocument, RelatedDocuments, RelationshipType); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingDocument); - args.push(this.RelatedDocuments); - args.push(this.RelationshipType); - return args; - } -}; -var IfcDocumentReference = class { - constructor(expressID, type, Location, Identification, Name, Description, ReferencedDocument) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - this.Description = Description; - this.ReferencedDocument = ReferencedDocument; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ReferencedDocument = tape[ptr++]; - return new IfcDocumentReference(expressID, type, Location, Identification, Name, Description, ReferencedDocument); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - args.push(this.Description); - args.push(this.ReferencedDocument); - return args; - } -}; -var IfcDoor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.OverallHeight = OverallHeight; - this.OverallWidth = OverallWidth; - this.PredefinedType = PredefinedType; - this.OperationType = OperationType; - this.UserDefinedOperationType = UserDefinedOperationType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let OverallHeight = tape[ptr++]; - let OverallWidth = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let OperationType = tape[ptr++]; - let UserDefinedOperationType = tape[ptr++]; - return new IfcDoor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.OverallHeight); - args.push(this.OverallWidth); - args.push(this.PredefinedType); - args.push(this.OperationType); - args.push(this.UserDefinedOperationType); - return args; - } -}; -var IfcDoorLiningProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, ThresholdDepth, ThresholdThickness, TransomThickness, TransomOffset, LiningOffset, ThresholdOffset, CasingThickness, CasingDepth, ShapeAspectStyle, LiningToPanelOffsetX, LiningToPanelOffsetY) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.LiningDepth = LiningDepth; - this.LiningThickness = LiningThickness; - this.ThresholdDepth = ThresholdDepth; - this.ThresholdThickness = ThresholdThickness; - this.TransomThickness = TransomThickness; - this.TransomOffset = TransomOffset; - this.LiningOffset = LiningOffset; - this.ThresholdOffset = ThresholdOffset; - this.CasingThickness = CasingThickness; - this.CasingDepth = CasingDepth; - this.ShapeAspectStyle = ShapeAspectStyle; - this.LiningToPanelOffsetX = LiningToPanelOffsetX; - this.LiningToPanelOffsetY = LiningToPanelOffsetY; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let LiningDepth = tape[ptr++]; - let LiningThickness = tape[ptr++]; - let ThresholdDepth = tape[ptr++]; - let ThresholdThickness = tape[ptr++]; - let TransomThickness = tape[ptr++]; - let TransomOffset = tape[ptr++]; - let LiningOffset = tape[ptr++]; - let ThresholdOffset = tape[ptr++]; - let CasingThickness = tape[ptr++]; - let CasingDepth = tape[ptr++]; - let ShapeAspectStyle = tape[ptr++]; - let LiningToPanelOffsetX = tape[ptr++]; - let LiningToPanelOffsetY = tape[ptr++]; - return new IfcDoorLiningProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, ThresholdDepth, ThresholdThickness, TransomThickness, TransomOffset, LiningOffset, ThresholdOffset, CasingThickness, CasingDepth, ShapeAspectStyle, LiningToPanelOffsetX, LiningToPanelOffsetY); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.LiningDepth); - args.push(this.LiningThickness); - args.push(this.ThresholdDepth); - args.push(this.ThresholdThickness); - args.push(this.TransomThickness); - args.push(this.TransomOffset); - args.push(this.LiningOffset); - args.push(this.ThresholdOffset); - args.push(this.CasingThickness); - args.push(this.CasingDepth); - args.push(this.ShapeAspectStyle); - args.push(this.LiningToPanelOffsetX); - args.push(this.LiningToPanelOffsetY); - return args; - } -}; -var IfcDoorPanelProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, PanelDepth, PanelOperation, PanelWidth, PanelPosition, ShapeAspectStyle) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.PanelDepth = PanelDepth; - this.PanelOperation = PanelOperation; - this.PanelWidth = PanelWidth; - this.PanelPosition = PanelPosition; - this.ShapeAspectStyle = ShapeAspectStyle; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let PanelDepth = tape[ptr++]; - let PanelOperation = tape[ptr++]; - let PanelWidth = tape[ptr++]; - let PanelPosition = tape[ptr++]; - let ShapeAspectStyle = tape[ptr++]; - return new IfcDoorPanelProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, PanelDepth, PanelOperation, PanelWidth, PanelPosition, ShapeAspectStyle); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.PanelDepth); - args.push(this.PanelOperation); - args.push(this.PanelWidth); - args.push(this.PanelPosition); - args.push(this.ShapeAspectStyle); - return args; - } -}; -var IfcDoorStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.OverallHeight = OverallHeight; - this.OverallWidth = OverallWidth; - this.PredefinedType = PredefinedType; - this.OperationType = OperationType; - this.UserDefinedOperationType = UserDefinedOperationType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let OverallHeight = tape[ptr++]; - let OverallWidth = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let OperationType = tape[ptr++]; - let UserDefinedOperationType = tape[ptr++]; - return new IfcDoorStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.OverallHeight); - args.push(this.OverallWidth); - args.push(this.PredefinedType); - args.push(this.OperationType); - args.push(this.UserDefinedOperationType); - return args; - } -}; -var IfcDoorStyle = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, OperationType, ConstructionType, ParameterTakesPrecedence, Sizeable) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.OperationType = OperationType; - this.ConstructionType = ConstructionType; - this.ParameterTakesPrecedence = ParameterTakesPrecedence; - this.Sizeable = Sizeable; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let OperationType = tape[ptr++]; - let ConstructionType = tape[ptr++]; - let ParameterTakesPrecedence = tape[ptr++]; - let Sizeable = tape[ptr++]; - return new IfcDoorStyle(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, OperationType, ConstructionType, ParameterTakesPrecedence, Sizeable); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.OperationType); - args.push(this.ConstructionType); - args.push(this.ParameterTakesPrecedence); - args.push(this.Sizeable); - return args; - } -}; -var IfcDoorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, OperationType, ParameterTakesPrecedence, UserDefinedOperationType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.OperationType = OperationType; - this.ParameterTakesPrecedence = ParameterTakesPrecedence; - this.UserDefinedOperationType = UserDefinedOperationType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let OperationType = tape[ptr++]; - let ParameterTakesPrecedence = tape[ptr++]; - let UserDefinedOperationType = tape[ptr++]; - return new IfcDoorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, OperationType, ParameterTakesPrecedence, UserDefinedOperationType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.OperationType); - args.push(this.ParameterTakesPrecedence); - args.push(this.UserDefinedOperationType); - return args; - } -}; -var IfcDraughtingPreDefinedColour = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcDraughtingPreDefinedColour(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcDraughtingPreDefinedCurveFont = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcDraughtingPreDefinedCurveFont(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcDuctFitting = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDuctFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDuctFittingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDuctFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDuctSegment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDuctSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDuctSegmentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDuctSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDuctSilencer = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDuctSilencer(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcDuctSilencerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcDuctSilencerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEdge = class { - constructor(expressID, type, EdgeStart, EdgeEnd) { - this.expressID = expressID; - this.type = type; - this.EdgeStart = EdgeStart; - this.EdgeEnd = EdgeEnd; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let EdgeStart = tape[ptr++]; - let EdgeEnd = tape[ptr++]; - return new IfcEdge(expressID, type, EdgeStart, EdgeEnd); - } - ToTape() { - let args = []; - args.push(this.EdgeStart); - args.push(this.EdgeEnd); - return args; - } -}; -var IfcEdgeCurve = class { - constructor(expressID, type, EdgeStart, EdgeEnd, EdgeGeometry, SameSense) { - this.expressID = expressID; - this.type = type; - this.EdgeStart = EdgeStart; - this.EdgeEnd = EdgeEnd; - this.EdgeGeometry = EdgeGeometry; - this.SameSense = SameSense; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let EdgeStart = tape[ptr++]; - let EdgeEnd = tape[ptr++]; - let EdgeGeometry = tape[ptr++]; - let SameSense = tape[ptr++]; - return new IfcEdgeCurve(expressID, type, EdgeStart, EdgeEnd, EdgeGeometry, SameSense); - } - ToTape() { - let args = []; - args.push(this.EdgeStart); - args.push(this.EdgeEnd); - args.push(this.EdgeGeometry); - args.push(this.SameSense); - return args; - } -}; -var IfcEdgeLoop = class { - constructor(expressID, type, EdgeList) { - this.expressID = expressID; - this.type = type; - this.EdgeList = EdgeList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let EdgeList = tape[ptr++]; - return new IfcEdgeLoop(expressID, type, EdgeList); - } - ToTape() { - let args = []; - args.push(this.EdgeList); - return args; - } -}; -var IfcElectricAppliance = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricAppliance(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricApplianceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricApplianceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricDistributionBoard = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricDistributionBoard(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricDistributionBoardType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricDistributionBoardType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricFlowStorageDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricFlowStorageDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricFlowStorageDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricFlowStorageDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricGenerator = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricGenerator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricGeneratorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricGeneratorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricMotor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricMotor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricMotorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricMotorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricTimeControl = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricTimeControl(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElectricTimeControlType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElectricTimeControlType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcElementAssembly = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, AssemblyPlace, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.AssemblyPlace = AssemblyPlace; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let AssemblyPlace = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElementAssembly(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, AssemblyPlace, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.AssemblyPlace); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElementAssemblyType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcElementAssemblyType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcElementComponent = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcElementComponent(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcElementComponentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcElementComponentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcElementQuantity = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, MethodOfMeasurement, Quantities) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.MethodOfMeasurement = MethodOfMeasurement; - this.Quantities = Quantities; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let MethodOfMeasurement = tape[ptr++]; - let Quantities = tape[ptr++]; - return new IfcElementQuantity(expressID, type, GlobalId, OwnerHistory, Name, Description, MethodOfMeasurement, Quantities); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.MethodOfMeasurement); - args.push(this.Quantities); - return args; - } -}; -var IfcElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcElementarySurface = class { - constructor(expressID, type, Position) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - return new IfcElementarySurface(expressID, type, Position); - } - ToTape() { - let args = []; - args.push(this.Position); - return args; - } -}; -var IfcEllipse = class { - constructor(expressID, type, Position, SemiAxis1, SemiAxis2) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.SemiAxis1 = SemiAxis1; - this.SemiAxis2 = SemiAxis2; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let SemiAxis1 = tape[ptr++]; - let SemiAxis2 = tape[ptr++]; - return new IfcEllipse(expressID, type, Position, SemiAxis1, SemiAxis2); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.SemiAxis1); - args.push(this.SemiAxis2); - return args; - } -}; -var IfcEllipseProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, SemiAxis1, SemiAxis2) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.SemiAxis1 = SemiAxis1; - this.SemiAxis2 = SemiAxis2; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let SemiAxis1 = tape[ptr++]; - let SemiAxis2 = tape[ptr++]; - return new IfcEllipseProfileDef(expressID, type, ProfileType, ProfileName, Position, SemiAxis1, SemiAxis2); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.SemiAxis1); - args.push(this.SemiAxis2); - return args; - } -}; -var IfcEnergyConversionDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcEnergyConversionDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcEnergyConversionDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcEnergyConversionDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcEngine = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcEngine(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEngineType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcEngineType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEvaporativeCooler = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcEvaporativeCooler(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEvaporativeCoolerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcEvaporativeCoolerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEvaporator = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcEvaporator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEvaporatorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcEvaporatorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcEvent = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType, EventTriggerType, UserDefinedEventTriggerType, EventOccurenceTime) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.PredefinedType = PredefinedType; - this.EventTriggerType = EventTriggerType; - this.UserDefinedEventTriggerType = UserDefinedEventTriggerType; - this.EventOccurenceTime = EventOccurenceTime; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let EventTriggerType = tape[ptr++]; - let UserDefinedEventTriggerType = tape[ptr++]; - let EventOccurenceTime = tape[ptr++]; - return new IfcEvent(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType, EventTriggerType, UserDefinedEventTriggerType, EventOccurenceTime); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.PredefinedType); - args.push(this.EventTriggerType); - args.push(this.UserDefinedEventTriggerType); - args.push(this.EventOccurenceTime); - return args; - } -}; -var IfcEventTime = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ActualDate, EarlyDate, LateDate, ScheduleDate) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.ActualDate = ActualDate; - this.EarlyDate = EarlyDate; - this.LateDate = LateDate; - this.ScheduleDate = ScheduleDate; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let ActualDate = tape[ptr++]; - let EarlyDate = tape[ptr++]; - let LateDate = tape[ptr++]; - let ScheduleDate = tape[ptr++]; - return new IfcEventTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ActualDate, EarlyDate, LateDate, ScheduleDate); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.ActualDate); - args.push(this.EarlyDate); - args.push(this.LateDate); - args.push(this.ScheduleDate); - return args; - } -}; -var IfcEventType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, EventTriggerType, UserDefinedEventTriggerType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ProcessType = ProcessType; - this.PredefinedType = PredefinedType; - this.EventTriggerType = EventTriggerType; - this.UserDefinedEventTriggerType = UserDefinedEventTriggerType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ProcessType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let EventTriggerType = tape[ptr++]; - let UserDefinedEventTriggerType = tape[ptr++]; - return new IfcEventType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, EventTriggerType, UserDefinedEventTriggerType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ProcessType); - args.push(this.PredefinedType); - args.push(this.EventTriggerType); - args.push(this.UserDefinedEventTriggerType); - return args; - } -}; -var IfcExtendedProperties = class { - constructor(expressID, type, Name, Description, Properties2) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Properties = Properties2; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Properties2 = tape[ptr++]; - return new IfcExtendedProperties(expressID, type, Name, Description, Properties2); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Properties); - return args; - } -}; -var IfcExternalInformation = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcExternalInformation(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcExternalReference = class { - constructor(expressID, type, Location, Identification, Name) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcExternalReference(expressID, type, Location, Identification, Name); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - return args; - } -}; -var IfcExternalReferenceRelationship = class { - constructor(expressID, type, Name, Description, RelatingReference, RelatedResourceObjects) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingReference = RelatingReference; - this.RelatedResourceObjects = RelatedResourceObjects; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingReference = tape[ptr++]; - let RelatedResourceObjects = tape[ptr++]; - return new IfcExternalReferenceRelationship(expressID, type, Name, Description, RelatingReference, RelatedResourceObjects); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingReference); - args.push(this.RelatedResourceObjects); - return args; - } -}; -var IfcExternalSpatialElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcExternalSpatialElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.PredefinedType); - return args; - } -}; -var IfcExternalSpatialStructureElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - return new IfcExternalSpatialStructureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - return args; - } -}; -var IfcExternallyDefinedHatchStyle = class { - constructor(expressID, type, Location, Identification, Name) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcExternallyDefinedHatchStyle(expressID, type, Location, Identification, Name); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - return args; - } -}; -var IfcExternallyDefinedSurfaceStyle = class { - constructor(expressID, type, Location, Identification, Name) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcExternallyDefinedSurfaceStyle(expressID, type, Location, Identification, Name); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - return args; - } -}; -var IfcExternallyDefinedTextFont = class { - constructor(expressID, type, Location, Identification, Name) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcExternallyDefinedTextFont(expressID, type, Location, Identification, Name); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - return args; - } -}; -var IfcExtrudedAreaSolid = class { - constructor(expressID, type, SweptArea, Position, ExtrudedDirection, Depth) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - this.ExtrudedDirection = ExtrudedDirection; - this.Depth = Depth; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - let ExtrudedDirection = tape[ptr++]; - let Depth = tape[ptr++]; - return new IfcExtrudedAreaSolid(expressID, type, SweptArea, Position, ExtrudedDirection, Depth); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - args.push(this.ExtrudedDirection); - args.push(this.Depth); - return args; - } -}; -var IfcExtrudedAreaSolidTapered = class { - constructor(expressID, type, SweptArea, Position, ExtrudedDirection, Depth, EndSweptArea) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - this.ExtrudedDirection = ExtrudedDirection; - this.Depth = Depth; - this.EndSweptArea = EndSweptArea; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - let ExtrudedDirection = tape[ptr++]; - let Depth = tape[ptr++]; - let EndSweptArea = tape[ptr++]; - return new IfcExtrudedAreaSolidTapered(expressID, type, SweptArea, Position, ExtrudedDirection, Depth, EndSweptArea); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - args.push(this.ExtrudedDirection); - args.push(this.Depth); - args.push(this.EndSweptArea); - return args; - } -}; -var IfcFace = class { - constructor(expressID, type, Bounds) { - this.expressID = expressID; - this.type = type; - this.Bounds = Bounds; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Bounds = tape[ptr++]; - return new IfcFace(expressID, type, Bounds); - } - ToTape() { - let args = []; - args.push(this.Bounds); - return args; - } -}; -var IfcFaceBasedSurfaceModel = class { - constructor(expressID, type, FbsmFaces) { - this.expressID = expressID; - this.type = type; - this.FbsmFaces = FbsmFaces; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let FbsmFaces = tape[ptr++]; - return new IfcFaceBasedSurfaceModel(expressID, type, FbsmFaces); - } - ToTape() { - let args = []; - args.push(this.FbsmFaces); - return args; - } -}; -var IfcFaceBound = class { - constructor(expressID, type, Bound, Orientation) { - this.expressID = expressID; - this.type = type; - this.Bound = Bound; - this.Orientation = Orientation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Bound = tape[ptr++]; - let Orientation = tape[ptr++]; - return new IfcFaceBound(expressID, type, Bound, Orientation); - } - ToTape() { - let args = []; - args.push(this.Bound); - args.push(this.Orientation); - return args; - } -}; -var IfcFaceOuterBound = class { - constructor(expressID, type, Bound, Orientation) { - this.expressID = expressID; - this.type = type; - this.Bound = Bound; - this.Orientation = Orientation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Bound = tape[ptr++]; - let Orientation = tape[ptr++]; - return new IfcFaceOuterBound(expressID, type, Bound, Orientation); - } - ToTape() { - let args = []; - args.push(this.Bound); - args.push(this.Orientation); - return args; - } -}; -var IfcFaceSurface = class { - constructor(expressID, type, Bounds, FaceSurface, SameSense) { - this.expressID = expressID; - this.type = type; - this.Bounds = Bounds; - this.FaceSurface = FaceSurface; - this.SameSense = SameSense; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Bounds = tape[ptr++]; - let FaceSurface = tape[ptr++]; - let SameSense = tape[ptr++]; - return new IfcFaceSurface(expressID, type, Bounds, FaceSurface, SameSense); - } - ToTape() { - let args = []; - args.push(this.Bounds); - args.push(this.FaceSurface); - args.push(this.SameSense); - return args; - } -}; -var IfcFacetedBrep = class { - constructor(expressID, type, Outer) { - this.expressID = expressID; - this.type = type; - this.Outer = Outer; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Outer = tape[ptr++]; - return new IfcFacetedBrep(expressID, type, Outer); - } - ToTape() { - let args = []; - args.push(this.Outer); - return args; - } -}; -var IfcFacetedBrepWithVoids = class { - constructor(expressID, type, Outer, Voids) { - this.expressID = expressID; - this.type = type; - this.Outer = Outer; - this.Voids = Voids; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Outer = tape[ptr++]; - let Voids = tape[ptr++]; - return new IfcFacetedBrepWithVoids(expressID, type, Outer, Voids); - } - ToTape() { - let args = []; - args.push(this.Outer); - args.push(this.Voids); - return args; - } -}; -var IfcFacility = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - return new IfcFacility(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - return args; - } -}; -var IfcFacilityPart = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - return new IfcFacilityPart(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - return args; - } -}; -var IfcFailureConnectionCondition = class { - constructor(expressID, type, Name, TensionFailureX, TensionFailureY, TensionFailureZ, CompressionFailureX, CompressionFailureY, CompressionFailureZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.TensionFailureX = TensionFailureX; - this.TensionFailureY = TensionFailureY; - this.TensionFailureZ = TensionFailureZ; - this.CompressionFailureX = CompressionFailureX; - this.CompressionFailureY = CompressionFailureY; - this.CompressionFailureZ = CompressionFailureZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let TensionFailureX = tape[ptr++]; - let TensionFailureY = tape[ptr++]; - let TensionFailureZ = tape[ptr++]; - let CompressionFailureX = tape[ptr++]; - let CompressionFailureY = tape[ptr++]; - let CompressionFailureZ = tape[ptr++]; - return new IfcFailureConnectionCondition(expressID, type, Name, TensionFailureX, TensionFailureY, TensionFailureZ, CompressionFailureX, CompressionFailureY, CompressionFailureZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.TensionFailureX); - args.push(this.TensionFailureY); - args.push(this.TensionFailureZ); - args.push(this.CompressionFailureX); - args.push(this.CompressionFailureY); - args.push(this.CompressionFailureZ); - return args; - } -}; -var IfcFan = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFan(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFanType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFanType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFastener = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFastener(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFastenerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFastenerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFeatureElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFeatureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFeatureElementAddition = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFeatureElementAddition(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFeatureElementSubtraction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFeatureElementSubtraction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFillAreaStyle = class { - constructor(expressID, type, Name, FillStyles, ModelorDraughting) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.FillStyles = FillStyles; - this.ModelorDraughting = ModelorDraughting; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let FillStyles = tape[ptr++]; - let ModelorDraughting = tape[ptr++]; - return new IfcFillAreaStyle(expressID, type, Name, FillStyles, ModelorDraughting); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.FillStyles); - args.push(this.ModelorDraughting); - return args; - } -}; -var IfcFillAreaStyleHatching = class { - constructor(expressID, type, HatchLineAppearance, StartOfNextHatchLine, PointOfReferenceHatchLine, PatternStart, HatchLineAngle) { - this.expressID = expressID; - this.type = type; - this.HatchLineAppearance = HatchLineAppearance; - this.StartOfNextHatchLine = StartOfNextHatchLine; - this.PointOfReferenceHatchLine = PointOfReferenceHatchLine; - this.PatternStart = PatternStart; - this.HatchLineAngle = HatchLineAngle; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let HatchLineAppearance = tape[ptr++]; - let StartOfNextHatchLine = tape[ptr++]; - let PointOfReferenceHatchLine = tape[ptr++]; - let PatternStart = tape[ptr++]; - let HatchLineAngle = tape[ptr++]; - return new IfcFillAreaStyleHatching(expressID, type, HatchLineAppearance, StartOfNextHatchLine, PointOfReferenceHatchLine, PatternStart, HatchLineAngle); - } - ToTape() { - let args = []; - args.push(this.HatchLineAppearance); - args.push(this.StartOfNextHatchLine); - args.push(this.PointOfReferenceHatchLine); - args.push(this.PatternStart); - args.push(this.HatchLineAngle); - return args; - } -}; -var IfcFillAreaStyleTiles = class { - constructor(expressID, type, TilingPattern, Tiles, TilingScale) { - this.expressID = expressID; - this.type = type; - this.TilingPattern = TilingPattern; - this.Tiles = Tiles; - this.TilingScale = TilingScale; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TilingPattern = tape[ptr++]; - let Tiles = tape[ptr++]; - let TilingScale = tape[ptr++]; - return new IfcFillAreaStyleTiles(expressID, type, TilingPattern, Tiles, TilingScale); - } - ToTape() { - let args = []; - args.push(this.TilingPattern); - args.push(this.Tiles); - args.push(this.TilingScale); - return args; - } -}; -var IfcFilter = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFilter(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFilterType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFilterType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFireSuppressionTerminal = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFireSuppressionTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFireSuppressionTerminalType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFireSuppressionTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFixedReferenceSweptAreaSolid = class { - constructor(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, FixedReference) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - this.Directrix = Directrix; - this.StartParam = StartParam; - this.EndParam = EndParam; - this.FixedReference = FixedReference; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - let Directrix = tape[ptr++]; - let StartParam = tape[ptr++]; - let EndParam = tape[ptr++]; - let FixedReference = tape[ptr++]; - return new IfcFixedReferenceSweptAreaSolid(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, FixedReference); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - args.push(this.Directrix); - args.push(this.StartParam); - args.push(this.EndParam); - args.push(this.FixedReference); - return args; - } -}; -var IfcFlowController = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowController(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowControllerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowControllerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFlowFitting = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowFittingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFlowInstrument = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFlowInstrument(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFlowInstrumentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFlowInstrumentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFlowMeter = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFlowMeter(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFlowMeterType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFlowMeterType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFlowMovingDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowMovingDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowMovingDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowMovingDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFlowSegment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowSegmentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFlowStorageDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowStorageDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowStorageDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowStorageDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFlowTerminal = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowTerminalType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFlowTreatmentDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFlowTreatmentDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFlowTreatmentDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFlowTreatmentDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFooting = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFooting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFootingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFootingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFurnishingElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcFurnishingElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcFurnishingElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcFurnishingElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcFurniture = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFurniture(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcFurnitureType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, AssemblyPlace, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.AssemblyPlace = AssemblyPlace; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let AssemblyPlace = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcFurnitureType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, AssemblyPlace, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.AssemblyPlace); - args.push(this.PredefinedType); - return args; - } -}; -var IfcGeographicElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcGeographicElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcGeographicElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcGeographicElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcGeometricCurveSet = class { - constructor(expressID, type, Elements) { - this.expressID = expressID; - this.type = type; - this.Elements = Elements; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Elements = tape[ptr++]; - return new IfcGeometricCurveSet(expressID, type, Elements); - } - ToTape() { - let args = []; - args.push(this.Elements); - return args; - } -}; -var IfcGeometricRepresentationContext = class { - constructor(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth) { - this.expressID = expressID; - this.type = type; - this.ContextIdentifier = ContextIdentifier; - this.ContextType = ContextType; - this.CoordinateSpaceDimension = CoordinateSpaceDimension; - this.Precision = Precision; - this.WorldCoordinateSystem = WorldCoordinateSystem; - this.TrueNorth = TrueNorth; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextIdentifier = tape[ptr++]; - let ContextType = tape[ptr++]; - let CoordinateSpaceDimension = tape[ptr++]; - let Precision = tape[ptr++]; - let WorldCoordinateSystem = tape[ptr++]; - let TrueNorth = tape[ptr++]; - return new IfcGeometricRepresentationContext(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth); - } - ToTape() { - let args = []; - args.push(this.ContextIdentifier); - args.push(this.ContextType); - args.push(this.CoordinateSpaceDimension); - args.push(this.Precision); - args.push(this.WorldCoordinateSystem); - args.push(this.TrueNorth); - return args; - } -}; -var IfcGeometricRepresentationItem = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcGeometricRepresentationItem(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcGeometricRepresentationSubContext = class { - constructor(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth, ParentContext, TargetScale, TargetView, UserDefinedTargetView) { - this.expressID = expressID; - this.type = type; - this.ContextIdentifier = ContextIdentifier; - this.ContextType = ContextType; - this.CoordinateSpaceDimension = CoordinateSpaceDimension; - this.Precision = Precision; - this.WorldCoordinateSystem = WorldCoordinateSystem; - this.TrueNorth = TrueNorth; - this.ParentContext = ParentContext; - this.TargetScale = TargetScale; - this.TargetView = TargetView; - this.UserDefinedTargetView = UserDefinedTargetView; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextIdentifier = tape[ptr++]; - let ContextType = tape[ptr++]; - let CoordinateSpaceDimension = tape[ptr++]; - let Precision = tape[ptr++]; - let WorldCoordinateSystem = tape[ptr++]; - let TrueNorth = tape[ptr++]; - let ParentContext = tape[ptr++]; - let TargetScale = tape[ptr++]; - let TargetView = tape[ptr++]; - let UserDefinedTargetView = tape[ptr++]; - return new IfcGeometricRepresentationSubContext(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth, ParentContext, TargetScale, TargetView, UserDefinedTargetView); - } - ToTape() { - let args = []; - args.push(this.ContextIdentifier); - args.push(this.ContextType); - args.push(this.CoordinateSpaceDimension); - args.push(this.Precision); - args.push(this.WorldCoordinateSystem); - args.push(this.TrueNorth); - args.push(this.ParentContext); - args.push(this.TargetScale); - args.push(this.TargetView); - args.push(this.UserDefinedTargetView); - return args; - } -}; -var IfcGeometricSet = class { - constructor(expressID, type, Elements) { - this.expressID = expressID; - this.type = type; - this.Elements = Elements; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Elements = tape[ptr++]; - return new IfcGeometricSet(expressID, type, Elements); - } - ToTape() { - let args = []; - args.push(this.Elements); - return args; - } -}; -var IfcGrid = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, UAxes, VAxes, WAxes, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.UAxes = UAxes; - this.VAxes = VAxes; - this.WAxes = WAxes; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let UAxes = tape[ptr++]; - let VAxes = tape[ptr++]; - let WAxes = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcGrid(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, UAxes, VAxes, WAxes, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.UAxes); - args.push(this.VAxes); - args.push(this.WAxes); - args.push(this.PredefinedType); - return args; - } -}; -var IfcGridAxis = class { - constructor(expressID, type, AxisTag, AxisCurve, SameSense) { - this.expressID = expressID; - this.type = type; - this.AxisTag = AxisTag; - this.AxisCurve = AxisCurve; - this.SameSense = SameSense; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let AxisTag = tape[ptr++]; - let AxisCurve = tape[ptr++]; - let SameSense = tape[ptr++]; - return new IfcGridAxis(expressID, type, AxisTag, AxisCurve, SameSense); - } - ToTape() { - let args = []; - args.push(this.AxisTag); - args.push(this.AxisCurve); - args.push(this.SameSense); - return args; - } -}; -var IfcGridPlacement = class { - constructor(expressID, type, PlacementRelTo, PlacementLocation, PlacementRefDirection) { - this.expressID = expressID; - this.type = type; - this.PlacementRelTo = PlacementRelTo; - this.PlacementLocation = PlacementLocation; - this.PlacementRefDirection = PlacementRefDirection; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let PlacementRelTo = tape[ptr++]; - let PlacementLocation = tape[ptr++]; - let PlacementRefDirection = tape[ptr++]; - return new IfcGridPlacement(expressID, type, PlacementRelTo, PlacementLocation, PlacementRefDirection); - } - ToTape() { - let args = []; - args.push(this.PlacementRelTo); - args.push(this.PlacementLocation); - args.push(this.PlacementRefDirection); - return args; - } -}; -var IfcGroup = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - return new IfcGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - return args; - } -}; -var IfcHalfSpaceSolid = class { - constructor(expressID, type, BaseSurface, AgreementFlag) { - this.expressID = expressID; - this.type = type; - this.BaseSurface = BaseSurface; - this.AgreementFlag = AgreementFlag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BaseSurface = tape[ptr++]; - let AgreementFlag = tape[ptr++]; - return new IfcHalfSpaceSolid(expressID, type, BaseSurface, AgreementFlag); - } - ToTape() { - let args = []; - args.push(this.BaseSurface); - args.push(this.AgreementFlag); - return args; - } -}; -var IfcHeatExchanger = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcHeatExchanger(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcHeatExchangerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcHeatExchangerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcHumidifier = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcHumidifier(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcHumidifierType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcHumidifierType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcIShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, OverallWidth, OverallDepth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, FlangeSlope) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.OverallWidth = OverallWidth; - this.OverallDepth = OverallDepth; - this.WebThickness = WebThickness; - this.FlangeThickness = FlangeThickness; - this.FilletRadius = FilletRadius; - this.FlangeEdgeRadius = FlangeEdgeRadius; - this.FlangeSlope = FlangeSlope; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let OverallWidth = tape[ptr++]; - let OverallDepth = tape[ptr++]; - let WebThickness = tape[ptr++]; - let FlangeThickness = tape[ptr++]; - let FilletRadius = tape[ptr++]; - let FlangeEdgeRadius = tape[ptr++]; - let FlangeSlope = tape[ptr++]; - return new IfcIShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, OverallWidth, OverallDepth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, FlangeSlope); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.OverallWidth); - args.push(this.OverallDepth); - args.push(this.WebThickness); - args.push(this.FlangeThickness); - args.push(this.FilletRadius); - args.push(this.FlangeEdgeRadius); - args.push(this.FlangeSlope); - return args; - } -}; -var IfcImageTexture = class { - constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, URLReference) { - this.expressID = expressID; - this.type = type; - this.RepeatS = RepeatS; - this.RepeatT = RepeatT; - this.Mode = Mode; - this.TextureTransform = TextureTransform; - this.Parameter = Parameter; - this.URLReference = URLReference; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RepeatS = tape[ptr++]; - let RepeatT = tape[ptr++]; - let Mode = tape[ptr++]; - let TextureTransform = tape[ptr++]; - let Parameter = tape[ptr++]; - let URLReference = tape[ptr++]; - return new IfcImageTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, URLReference); - } - ToTape() { - let args = []; - args.push(this.RepeatS); - args.push(this.RepeatT); - args.push(this.Mode); - args.push(this.TextureTransform); - args.push(this.Parameter); - args.push(this.URLReference); - return args; - } -}; -var IfcIndexedColourMap = class { - constructor(expressID, type, MappedTo, Opacity, Colours, ColourIndex) { - this.expressID = expressID; - this.type = type; - this.MappedTo = MappedTo; - this.Opacity = Opacity; - this.Colours = Colours; - this.ColourIndex = ColourIndex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let MappedTo = tape[ptr++]; - let Opacity = tape[ptr++]; - let Colours = tape[ptr++]; - let ColourIndex = tape[ptr++]; - return new IfcIndexedColourMap(expressID, type, MappedTo, Opacity, Colours, ColourIndex); - } - ToTape() { - let args = []; - args.push(this.MappedTo); - args.push(this.Opacity); - args.push(this.Colours); - args.push(this.ColourIndex); - return args; - } -}; -var IfcIndexedPolyCurve = class { - constructor(expressID, type, Points, Segments, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.Points = Points; - this.Segments = Segments; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Points = tape[ptr++]; - let Segments = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcIndexedPolyCurve(expressID, type, Points, Segments, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.Points); - args.push(this.Segments); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcIndexedPolygonalFace = class { - constructor(expressID, type, CoordIndex) { - this.expressID = expressID; - this.type = type; - this.CoordIndex = CoordIndex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CoordIndex = tape[ptr++]; - return new IfcIndexedPolygonalFace(expressID, type, CoordIndex); - } - ToTape() { - let args = []; - args.push(this.CoordIndex); - return args; - } -}; -var IfcIndexedPolygonalFaceWithVoids = class { - constructor(expressID, type, CoordIndex, InnerCoordIndices) { - this.expressID = expressID; - this.type = type; - this.CoordIndex = CoordIndex; - this.InnerCoordIndices = InnerCoordIndices; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CoordIndex = tape[ptr++]; - let InnerCoordIndices = tape[ptr++]; - return new IfcIndexedPolygonalFaceWithVoids(expressID, type, CoordIndex, InnerCoordIndices); - } - ToTape() { - let args = []; - args.push(this.CoordIndex); - args.push(this.InnerCoordIndices); - return args; - } -}; -var IfcIndexedTextureMap = class { - constructor(expressID, type, Maps, MappedTo, TexCoords) { - this.expressID = expressID; - this.type = type; - this.Maps = Maps; - this.MappedTo = MappedTo; - this.TexCoords = TexCoords; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Maps = tape[ptr++]; - let MappedTo = tape[ptr++]; - let TexCoords = tape[ptr++]; - return new IfcIndexedTextureMap(expressID, type, Maps, MappedTo, TexCoords); - } - ToTape() { - let args = []; - args.push(this.Maps); - args.push(this.MappedTo); - args.push(this.TexCoords); - return args; - } -}; -var IfcIndexedTriangleTextureMap = class { - constructor(expressID, type, Maps, MappedTo, TexCoords, TexCoordIndex) { - this.expressID = expressID; - this.type = type; - this.Maps = Maps; - this.MappedTo = MappedTo; - this.TexCoords = TexCoords; - this.TexCoordIndex = TexCoordIndex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Maps = tape[ptr++]; - let MappedTo = tape[ptr++]; - let TexCoords = tape[ptr++]; - let TexCoordIndex = tape[ptr++]; - return new IfcIndexedTriangleTextureMap(expressID, type, Maps, MappedTo, TexCoords, TexCoordIndex); - } - ToTape() { - let args = []; - args.push(this.Maps); - args.push(this.MappedTo); - args.push(this.TexCoords); - args.push(this.TexCoordIndex); - return args; - } -}; -var IfcInterceptor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcInterceptor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcInterceptorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcInterceptorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcIntersectionCurve = class { - constructor(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation) { - this.expressID = expressID; - this.type = type; - this.Curve3D = Curve3D; - this.AssociatedGeometry = AssociatedGeometry; - this.MasterRepresentation = MasterRepresentation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Curve3D = tape[ptr++]; - let AssociatedGeometry = tape[ptr++]; - let MasterRepresentation = tape[ptr++]; - return new IfcIntersectionCurve(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation); - } - ToTape() { - let args = []; - args.push(this.Curve3D); - args.push(this.AssociatedGeometry); - args.push(this.MasterRepresentation); - return args; - } -}; -var IfcInventory = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, Jurisdiction, ResponsiblePersons, LastUpdateDate, CurrentValue, OriginalValue) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.PredefinedType = PredefinedType; - this.Jurisdiction = Jurisdiction; - this.ResponsiblePersons = ResponsiblePersons; - this.LastUpdateDate = LastUpdateDate; - this.CurrentValue = CurrentValue; - this.OriginalValue = OriginalValue; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Jurisdiction = tape[ptr++]; - let ResponsiblePersons = tape[ptr++]; - let LastUpdateDate = tape[ptr++]; - let CurrentValue = tape[ptr++]; - let OriginalValue = tape[ptr++]; - return new IfcInventory(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, Jurisdiction, ResponsiblePersons, LastUpdateDate, CurrentValue, OriginalValue); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.PredefinedType); - args.push(this.Jurisdiction); - args.push(this.ResponsiblePersons); - args.push(this.LastUpdateDate); - args.push(this.CurrentValue); - args.push(this.OriginalValue); - return args; - } -}; -var IfcIrregularTimeSeries = class { - constructor(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, Values) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.StartTime = StartTime; - this.EndTime = EndTime; - this.TimeSeriesDataType = TimeSeriesDataType; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.Unit = Unit; - this.Values = Values; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let StartTime = tape[ptr++]; - let EndTime = tape[ptr++]; - let TimeSeriesDataType = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let Unit = tape[ptr++]; - let Values = tape[ptr++]; - return new IfcIrregularTimeSeries(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, Values); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.StartTime); - args.push(this.EndTime); - args.push(this.TimeSeriesDataType); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.Unit); - args.push(this.Values); - return args; - } -}; -var IfcIrregularTimeSeriesValue = class { - constructor(expressID, type, TimeStamp, ListValues) { - this.expressID = expressID; - this.type = type; - this.TimeStamp = TimeStamp; - this.ListValues = ListValues; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TimeStamp = tape[ptr++]; - let ListValues = tape[ptr++]; - return new IfcIrregularTimeSeriesValue(expressID, type, TimeStamp, ListValues); - } - ToTape() { - let args = []; - args.push(this.TimeStamp); - args.push(this.ListValues); - return args; - } -}; -var IfcJunctionBox = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcJunctionBox(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcJunctionBoxType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcJunctionBoxType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Depth, Width, Thickness, FilletRadius, EdgeRadius, LegSlope) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Depth = Depth; - this.Width = Width; - this.Thickness = Thickness; - this.FilletRadius = FilletRadius; - this.EdgeRadius = EdgeRadius; - this.LegSlope = LegSlope; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Depth = tape[ptr++]; - let Width = tape[ptr++]; - let Thickness = tape[ptr++]; - let FilletRadius = tape[ptr++]; - let EdgeRadius = tape[ptr++]; - let LegSlope = tape[ptr++]; - return new IfcLShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, Width, Thickness, FilletRadius, EdgeRadius, LegSlope); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Depth); - args.push(this.Width); - args.push(this.Thickness); - args.push(this.FilletRadius); - args.push(this.EdgeRadius); - args.push(this.LegSlope); - return args; - } -}; -var IfcLaborResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcLaborResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLaborResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcLaborResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLagTime = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, LagValue, DurationType) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.LagValue = LagValue; - this.DurationType = DurationType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let LagValue = tape[ptr++]; - let DurationType = tape[ptr++]; - return new IfcLagTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, LagValue, DurationType); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.LagValue); - args.push(this.DurationType); - return args; - } -}; -var IfcLamp = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcLamp(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLampType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcLampType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLibraryInformation = class { - constructor(expressID, type, Name, Version, Publisher, VersionDate, Location, Description) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Version = Version; - this.Publisher = Publisher; - this.VersionDate = VersionDate; - this.Location = Location; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Version = tape[ptr++]; - let Publisher = tape[ptr++]; - let VersionDate = tape[ptr++]; - let Location = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcLibraryInformation(expressID, type, Name, Version, Publisher, VersionDate, Location, Description); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Version); - args.push(this.Publisher); - args.push(this.VersionDate); - args.push(this.Location); - args.push(this.Description); - return args; - } -}; -var IfcLibraryReference = class { - constructor(expressID, type, Location, Identification, Name, Description, Language, ReferencedLibrary) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - this.Identification = Identification; - this.Name = Name; - this.Description = Description; - this.Language = Language; - this.ReferencedLibrary = ReferencedLibrary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Language = tape[ptr++]; - let ReferencedLibrary = tape[ptr++]; - return new IfcLibraryReference(expressID, type, Location, Identification, Name, Description, Language, ReferencedLibrary); - } - ToTape() { - let args = []; - args.push(this.Location); - args.push(this.Identification); - args.push(this.Name); - args.push(this.Description); - args.push(this.Language); - args.push(this.ReferencedLibrary); - return args; - } -}; -var IfcLightDistributionData = class { - constructor(expressID, type, MainPlaneAngle, SecondaryPlaneAngle, LuminousIntensity) { - this.expressID = expressID; - this.type = type; - this.MainPlaneAngle = MainPlaneAngle; - this.SecondaryPlaneAngle = SecondaryPlaneAngle; - this.LuminousIntensity = LuminousIntensity; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let MainPlaneAngle = tape[ptr++]; - let SecondaryPlaneAngle = tape[ptr++]; - let LuminousIntensity = tape[ptr++]; - return new IfcLightDistributionData(expressID, type, MainPlaneAngle, SecondaryPlaneAngle, LuminousIntensity); - } - ToTape() { - let args = []; - args.push(this.MainPlaneAngle); - args.push(this.SecondaryPlaneAngle); - args.push(this.LuminousIntensity); - return args; - } -}; -var IfcLightFixture = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcLightFixture(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLightFixtureType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcLightFixtureType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcLightIntensityDistribution = class { - constructor(expressID, type, LightDistributionCurve, DistributionData) { - this.expressID = expressID; - this.type = type; - this.LightDistributionCurve = LightDistributionCurve; - this.DistributionData = DistributionData; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let LightDistributionCurve = tape[ptr++]; - let DistributionData = tape[ptr++]; - return new IfcLightIntensityDistribution(expressID, type, LightDistributionCurve, DistributionData); - } - ToTape() { - let args = []; - args.push(this.LightDistributionCurve); - args.push(this.DistributionData); - return args; - } -}; -var IfcLightSource = class { - constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LightColour = LightColour; - this.AmbientIntensity = AmbientIntensity; - this.Intensity = Intensity; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LightColour = tape[ptr++]; - let AmbientIntensity = tape[ptr++]; - let Intensity = tape[ptr++]; - return new IfcLightSource(expressID, type, Name, LightColour, AmbientIntensity, Intensity); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LightColour); - args.push(this.AmbientIntensity); - args.push(this.Intensity); - return args; - } -}; -var IfcLightSourceAmbient = class { - constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LightColour = LightColour; - this.AmbientIntensity = AmbientIntensity; - this.Intensity = Intensity; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LightColour = tape[ptr++]; - let AmbientIntensity = tape[ptr++]; - let Intensity = tape[ptr++]; - return new IfcLightSourceAmbient(expressID, type, Name, LightColour, AmbientIntensity, Intensity); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LightColour); - args.push(this.AmbientIntensity); - args.push(this.Intensity); - return args; - } -}; -var IfcLightSourceDirectional = class { - constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Orientation) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LightColour = LightColour; - this.AmbientIntensity = AmbientIntensity; - this.Intensity = Intensity; - this.Orientation = Orientation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LightColour = tape[ptr++]; - let AmbientIntensity = tape[ptr++]; - let Intensity = tape[ptr++]; - let Orientation = tape[ptr++]; - return new IfcLightSourceDirectional(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Orientation); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LightColour); - args.push(this.AmbientIntensity); - args.push(this.Intensity); - args.push(this.Orientation); - return args; - } -}; -var IfcLightSourceGoniometric = class { - constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, ColourAppearance, ColourTemperature, LuminousFlux, LightEmissionSource, LightDistributionDataSource) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LightColour = LightColour; - this.AmbientIntensity = AmbientIntensity; - this.Intensity = Intensity; - this.Position = Position; - this.ColourAppearance = ColourAppearance; - this.ColourTemperature = ColourTemperature; - this.LuminousFlux = LuminousFlux; - this.LightEmissionSource = LightEmissionSource; - this.LightDistributionDataSource = LightDistributionDataSource; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LightColour = tape[ptr++]; - let AmbientIntensity = tape[ptr++]; - let Intensity = tape[ptr++]; - let Position = tape[ptr++]; - let ColourAppearance = tape[ptr++]; - let ColourTemperature = tape[ptr++]; - let LuminousFlux = tape[ptr++]; - let LightEmissionSource = tape[ptr++]; - let LightDistributionDataSource = tape[ptr++]; - return new IfcLightSourceGoniometric(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, ColourAppearance, ColourTemperature, LuminousFlux, LightEmissionSource, LightDistributionDataSource); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LightColour); - args.push(this.AmbientIntensity); - args.push(this.Intensity); - args.push(this.Position); - args.push(this.ColourAppearance); - args.push(this.ColourTemperature); - args.push(this.LuminousFlux); - args.push(this.LightEmissionSource); - args.push(this.LightDistributionDataSource); - return args; - } -}; -var IfcLightSourcePositional = class { - constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LightColour = LightColour; - this.AmbientIntensity = AmbientIntensity; - this.Intensity = Intensity; - this.Position = Position; - this.Radius = Radius; - this.ConstantAttenuation = ConstantAttenuation; - this.DistanceAttenuation = DistanceAttenuation; - this.QuadricAttenuation = QuadricAttenuation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LightColour = tape[ptr++]; - let AmbientIntensity = tape[ptr++]; - let Intensity = tape[ptr++]; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - let ConstantAttenuation = tape[ptr++]; - let DistanceAttenuation = tape[ptr++]; - let QuadricAttenuation = tape[ptr++]; - return new IfcLightSourcePositional(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LightColour); - args.push(this.AmbientIntensity); - args.push(this.Intensity); - args.push(this.Position); - args.push(this.Radius); - args.push(this.ConstantAttenuation); - args.push(this.DistanceAttenuation); - args.push(this.QuadricAttenuation); - return args; - } -}; -var IfcLightSourceSpot = class { - constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation, Orientation, ConcentrationExponent, SpreadAngle, BeamWidthAngle) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LightColour = LightColour; - this.AmbientIntensity = AmbientIntensity; - this.Intensity = Intensity; - this.Position = Position; - this.Radius = Radius; - this.ConstantAttenuation = ConstantAttenuation; - this.DistanceAttenuation = DistanceAttenuation; - this.QuadricAttenuation = QuadricAttenuation; - this.Orientation = Orientation; - this.ConcentrationExponent = ConcentrationExponent; - this.SpreadAngle = SpreadAngle; - this.BeamWidthAngle = BeamWidthAngle; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LightColour = tape[ptr++]; - let AmbientIntensity = tape[ptr++]; - let Intensity = tape[ptr++]; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - let ConstantAttenuation = tape[ptr++]; - let DistanceAttenuation = tape[ptr++]; - let QuadricAttenuation = tape[ptr++]; - let Orientation = tape[ptr++]; - let ConcentrationExponent = tape[ptr++]; - let SpreadAngle = tape[ptr++]; - let BeamWidthAngle = tape[ptr++]; - return new IfcLightSourceSpot(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation, Orientation, ConcentrationExponent, SpreadAngle, BeamWidthAngle); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LightColour); - args.push(this.AmbientIntensity); - args.push(this.Intensity); - args.push(this.Position); - args.push(this.Radius); - args.push(this.ConstantAttenuation); - args.push(this.DistanceAttenuation); - args.push(this.QuadricAttenuation); - args.push(this.Orientation); - args.push(this.ConcentrationExponent); - args.push(this.SpreadAngle); - args.push(this.BeamWidthAngle); - return args; - } -}; -var IfcLine = class { - constructor(expressID, type, Pnt, Dir) { - this.expressID = expressID; - this.type = type; - this.Pnt = Pnt; - this.Dir = Dir; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Pnt = tape[ptr++]; - let Dir = tape[ptr++]; - return new IfcLine(expressID, type, Pnt, Dir); - } - ToTape() { - let args = []; - args.push(this.Pnt); - args.push(this.Dir); - return args; - } -}; -var IfcLineSegment2D = class { - constructor(expressID, type, StartPoint, StartDirection, SegmentLength) { - this.expressID = expressID; - this.type = type; - this.StartPoint = StartPoint; - this.StartDirection = StartDirection; - this.SegmentLength = SegmentLength; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let StartPoint = tape[ptr++]; - let StartDirection = tape[ptr++]; - let SegmentLength = tape[ptr++]; - return new IfcLineSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength); - } - ToTape() { - let args = []; - args.push(this.StartPoint); - args.push(this.StartDirection); - args.push(this.SegmentLength); - return args; - } -}; -var IfcLinearPlacement = class { - constructor(expressID, type, PlacementRelTo, PlacementMeasuredAlong, Distance, Orientation, CartesianPosition) { - this.expressID = expressID; - this.type = type; - this.PlacementRelTo = PlacementRelTo; - this.PlacementMeasuredAlong = PlacementMeasuredAlong; - this.Distance = Distance; - this.Orientation = Orientation; - this.CartesianPosition = CartesianPosition; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let PlacementRelTo = tape[ptr++]; - let PlacementMeasuredAlong = tape[ptr++]; - let Distance = tape[ptr++]; - let Orientation = tape[ptr++]; - let CartesianPosition = tape[ptr++]; - return new IfcLinearPlacement(expressID, type, PlacementRelTo, PlacementMeasuredAlong, Distance, Orientation, CartesianPosition); - } - ToTape() { - let args = []; - args.push(this.PlacementRelTo); - args.push(this.PlacementMeasuredAlong); - args.push(this.Distance); - args.push(this.Orientation); - args.push(this.CartesianPosition); - return args; - } -}; -var IfcLinearPositioningElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Axis = Axis; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Axis = tape[ptr++]; - return new IfcLinearPositioningElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Axis); - return args; - } -}; -var IfcLocalPlacement = class { - constructor(expressID, type, PlacementRelTo, RelativePlacement) { - this.expressID = expressID; - this.type = type; - this.PlacementRelTo = PlacementRelTo; - this.RelativePlacement = RelativePlacement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let PlacementRelTo = tape[ptr++]; - let RelativePlacement = tape[ptr++]; - return new IfcLocalPlacement(expressID, type, PlacementRelTo, RelativePlacement); - } - ToTape() { - let args = []; - args.push(this.PlacementRelTo); - args.push(this.RelativePlacement); - return args; - } -}; -var IfcLoop = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcLoop(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcManifoldSolidBrep = class { - constructor(expressID, type, Outer) { - this.expressID = expressID; - this.type = type; - this.Outer = Outer; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Outer = tape[ptr++]; - return new IfcManifoldSolidBrep(expressID, type, Outer); - } - ToTape() { - let args = []; - args.push(this.Outer); - return args; - } -}; -var IfcMapConversion = class { - constructor(expressID, type, SourceCRS, TargetCRS, Eastings, Northings, OrthogonalHeight, XAxisAbscissa, XAxisOrdinate, Scale) { - this.expressID = expressID; - this.type = type; - this.SourceCRS = SourceCRS; - this.TargetCRS = TargetCRS; - this.Eastings = Eastings; - this.Northings = Northings; - this.OrthogonalHeight = OrthogonalHeight; - this.XAxisAbscissa = XAxisAbscissa; - this.XAxisOrdinate = XAxisOrdinate; - this.Scale = Scale; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SourceCRS = tape[ptr++]; - let TargetCRS = tape[ptr++]; - let Eastings = tape[ptr++]; - let Northings = tape[ptr++]; - let OrthogonalHeight = tape[ptr++]; - let XAxisAbscissa = tape[ptr++]; - let XAxisOrdinate = tape[ptr++]; - let Scale = tape[ptr++]; - return new IfcMapConversion(expressID, type, SourceCRS, TargetCRS, Eastings, Northings, OrthogonalHeight, XAxisAbscissa, XAxisOrdinate, Scale); - } - ToTape() { - let args = []; - args.push(this.SourceCRS); - args.push(this.TargetCRS); - args.push(this.Eastings); - args.push(this.Northings); - args.push(this.OrthogonalHeight); - args.push(this.XAxisAbscissa); - args.push(this.XAxisOrdinate); - args.push(this.Scale); - return args; - } -}; -var IfcMappedItem = class { - constructor(expressID, type, MappingSource, MappingTarget) { - this.expressID = expressID; - this.type = type; - this.MappingSource = MappingSource; - this.MappingTarget = MappingTarget; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let MappingSource = tape[ptr++]; - let MappingTarget = tape[ptr++]; - return new IfcMappedItem(expressID, type, MappingSource, MappingTarget); - } - ToTape() { - let args = []; - args.push(this.MappingSource); - args.push(this.MappingTarget); - return args; - } -}; -var IfcMaterial = class { - constructor(expressID, type, Name, Description, Category) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Category = Category; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Category = tape[ptr++]; - return new IfcMaterial(expressID, type, Name, Description, Category); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Category); - return args; - } -}; -var IfcMaterialClassificationRelationship = class { - constructor(expressID, type, MaterialClassifications, ClassifiedMaterial) { - this.expressID = expressID; - this.type = type; - this.MaterialClassifications = MaterialClassifications; - this.ClassifiedMaterial = ClassifiedMaterial; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let MaterialClassifications = tape[ptr++]; - let ClassifiedMaterial = tape[ptr++]; - return new IfcMaterialClassificationRelationship(expressID, type, MaterialClassifications, ClassifiedMaterial); - } - ToTape() { - let args = []; - args.push(this.MaterialClassifications); - args.push(this.ClassifiedMaterial); - return args; - } -}; -var IfcMaterialConstituent = class { - constructor(expressID, type, Name, Description, Material, Fraction, Category) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Material = Material; - this.Fraction = Fraction; - this.Category = Category; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Material = tape[ptr++]; - let Fraction = tape[ptr++]; - let Category = tape[ptr++]; - return new IfcMaterialConstituent(expressID, type, Name, Description, Material, Fraction, Category); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Material); - args.push(this.Fraction); - args.push(this.Category); - return args; - } -}; -var IfcMaterialConstituentSet = class { - constructor(expressID, type, Name, Description, MaterialConstituents) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.MaterialConstituents = MaterialConstituents; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let MaterialConstituents = tape[ptr++]; - return new IfcMaterialConstituentSet(expressID, type, Name, Description, MaterialConstituents); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.MaterialConstituents); - return args; - } -}; -var IfcMaterialDefinition = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcMaterialDefinition(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcMaterialDefinitionRepresentation = class { - constructor(expressID, type, Name, Description, Representations, RepresentedMaterial) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Representations = Representations; - this.RepresentedMaterial = RepresentedMaterial; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Representations = tape[ptr++]; - let RepresentedMaterial = tape[ptr++]; - return new IfcMaterialDefinitionRepresentation(expressID, type, Name, Description, Representations, RepresentedMaterial); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Representations); - args.push(this.RepresentedMaterial); - return args; - } -}; -var IfcMaterialLayer = class { - constructor(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority) { - this.expressID = expressID; - this.type = type; - this.Material = Material; - this.LayerThickness = LayerThickness; - this.IsVentilated = IsVentilated; - this.Name = Name; - this.Description = Description; - this.Category = Category; - this.Priority = Priority; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Material = tape[ptr++]; - let LayerThickness = tape[ptr++]; - let IsVentilated = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Category = tape[ptr++]; - let Priority = tape[ptr++]; - return new IfcMaterialLayer(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority); - } - ToTape() { - let args = []; - args.push(this.Material); - args.push(this.LayerThickness); - args.push(this.IsVentilated); - args.push(this.Name); - args.push(this.Description); - args.push(this.Category); - args.push(this.Priority); - return args; - } -}; -var IfcMaterialLayerSet = class { - constructor(expressID, type, MaterialLayers, LayerSetName, Description) { - this.expressID = expressID; - this.type = type; - this.MaterialLayers = MaterialLayers; - this.LayerSetName = LayerSetName; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let MaterialLayers = tape[ptr++]; - let LayerSetName = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcMaterialLayerSet(expressID, type, MaterialLayers, LayerSetName, Description); - } - ToTape() { - let args = []; - args.push(this.MaterialLayers); - args.push(this.LayerSetName); - args.push(this.Description); - return args; - } -}; -var IfcMaterialLayerSetUsage = class { - constructor(expressID, type, ForLayerSet, LayerSetDirection, DirectionSense, OffsetFromReferenceLine, ReferenceExtent) { - this.expressID = expressID; - this.type = type; - this.ForLayerSet = ForLayerSet; - this.LayerSetDirection = LayerSetDirection; - this.DirectionSense = DirectionSense; - this.OffsetFromReferenceLine = OffsetFromReferenceLine; - this.ReferenceExtent = ReferenceExtent; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ForLayerSet = tape[ptr++]; - let LayerSetDirection = tape[ptr++]; - let DirectionSense = tape[ptr++]; - let OffsetFromReferenceLine = tape[ptr++]; - let ReferenceExtent = tape[ptr++]; - return new IfcMaterialLayerSetUsage(expressID, type, ForLayerSet, LayerSetDirection, DirectionSense, OffsetFromReferenceLine, ReferenceExtent); - } - ToTape() { - let args = []; - args.push(this.ForLayerSet); - args.push(this.LayerSetDirection); - args.push(this.DirectionSense); - args.push(this.OffsetFromReferenceLine); - args.push(this.ReferenceExtent); - return args; - } -}; -var IfcMaterialLayerWithOffsets = class { - constructor(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority, OffsetDirection, OffsetValues) { - this.expressID = expressID; - this.type = type; - this.Material = Material; - this.LayerThickness = LayerThickness; - this.IsVentilated = IsVentilated; - this.Name = Name; - this.Description = Description; - this.Category = Category; - this.Priority = Priority; - this.OffsetDirection = OffsetDirection; - this.OffsetValues = OffsetValues; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Material = tape[ptr++]; - let LayerThickness = tape[ptr++]; - let IsVentilated = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Category = tape[ptr++]; - let Priority = tape[ptr++]; - let OffsetDirection = tape[ptr++]; - let OffsetValues = tape[ptr++]; - return new IfcMaterialLayerWithOffsets(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority, OffsetDirection, OffsetValues); - } - ToTape() { - let args = []; - args.push(this.Material); - args.push(this.LayerThickness); - args.push(this.IsVentilated); - args.push(this.Name); - args.push(this.Description); - args.push(this.Category); - args.push(this.Priority); - args.push(this.OffsetDirection); - args.push(this.OffsetValues); - return args; - } -}; -var IfcMaterialList = class { - constructor(expressID, type, Materials) { - this.expressID = expressID; - this.type = type; - this.Materials = Materials; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Materials = tape[ptr++]; - return new IfcMaterialList(expressID, type, Materials); - } - ToTape() { - let args = []; - args.push(this.Materials); - return args; - } -}; -var IfcMaterialProfile = class { - constructor(expressID, type, Name, Description, Material, Profile, Priority, Category) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Material = Material; - this.Profile = Profile; - this.Priority = Priority; - this.Category = Category; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Material = tape[ptr++]; - let Profile = tape[ptr++]; - let Priority = tape[ptr++]; - let Category = tape[ptr++]; - return new IfcMaterialProfile(expressID, type, Name, Description, Material, Profile, Priority, Category); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Material); - args.push(this.Profile); - args.push(this.Priority); - args.push(this.Category); - return args; - } -}; -var IfcMaterialProfileSet = class { - constructor(expressID, type, Name, Description, MaterialProfiles, CompositeProfile) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.MaterialProfiles = MaterialProfiles; - this.CompositeProfile = CompositeProfile; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let MaterialProfiles = tape[ptr++]; - let CompositeProfile = tape[ptr++]; - return new IfcMaterialProfileSet(expressID, type, Name, Description, MaterialProfiles, CompositeProfile); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.MaterialProfiles); - args.push(this.CompositeProfile); - return args; - } -}; -var IfcMaterialProfileSetUsage = class { - constructor(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent) { - this.expressID = expressID; - this.type = type; - this.ForProfileSet = ForProfileSet; - this.CardinalPoint = CardinalPoint; - this.ReferenceExtent = ReferenceExtent; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ForProfileSet = tape[ptr++]; - let CardinalPoint = tape[ptr++]; - let ReferenceExtent = tape[ptr++]; - return new IfcMaterialProfileSetUsage(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent); - } - ToTape() { - let args = []; - args.push(this.ForProfileSet); - args.push(this.CardinalPoint); - args.push(this.ReferenceExtent); - return args; - } -}; -var IfcMaterialProfileSetUsageTapering = class { - constructor(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent, ForProfileEndSet, CardinalEndPoint) { - this.expressID = expressID; - this.type = type; - this.ForProfileSet = ForProfileSet; - this.CardinalPoint = CardinalPoint; - this.ReferenceExtent = ReferenceExtent; - this.ForProfileEndSet = ForProfileEndSet; - this.CardinalEndPoint = CardinalEndPoint; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ForProfileSet = tape[ptr++]; - let CardinalPoint = tape[ptr++]; - let ReferenceExtent = tape[ptr++]; - let ForProfileEndSet = tape[ptr++]; - let CardinalEndPoint = tape[ptr++]; - return new IfcMaterialProfileSetUsageTapering(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent, ForProfileEndSet, CardinalEndPoint); - } - ToTape() { - let args = []; - args.push(this.ForProfileSet); - args.push(this.CardinalPoint); - args.push(this.ReferenceExtent); - args.push(this.ForProfileEndSet); - args.push(this.CardinalEndPoint); - return args; - } -}; -var IfcMaterialProfileWithOffsets = class { - constructor(expressID, type, Name, Description, Material, Profile, Priority, Category, OffsetValues) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Material = Material; - this.Profile = Profile; - this.Priority = Priority; - this.Category = Category; - this.OffsetValues = OffsetValues; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Material = tape[ptr++]; - let Profile = tape[ptr++]; - let Priority = tape[ptr++]; - let Category = tape[ptr++]; - let OffsetValues = tape[ptr++]; - return new IfcMaterialProfileWithOffsets(expressID, type, Name, Description, Material, Profile, Priority, Category, OffsetValues); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Material); - args.push(this.Profile); - args.push(this.Priority); - args.push(this.Category); - args.push(this.OffsetValues); - return args; - } -}; -var IfcMaterialProperties = class { - constructor(expressID, type, Name, Description, Properties2, Material) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Properties = Properties2; - this.Material = Material; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Properties2 = tape[ptr++]; - let Material = tape[ptr++]; - return new IfcMaterialProperties(expressID, type, Name, Description, Properties2, Material); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Properties); - args.push(this.Material); - return args; - } -}; -var IfcMaterialRelationship = class { - constructor(expressID, type, Name, Description, RelatingMaterial, RelatedMaterials, Expression) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingMaterial = RelatingMaterial; - this.RelatedMaterials = RelatedMaterials; - this.Expression = Expression; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingMaterial = tape[ptr++]; - let RelatedMaterials = tape[ptr++]; - let Expression = tape[ptr++]; - return new IfcMaterialRelationship(expressID, type, Name, Description, RelatingMaterial, RelatedMaterials, Expression); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingMaterial); - args.push(this.RelatedMaterials); - args.push(this.Expression); - return args; - } -}; -var IfcMaterialUsageDefinition = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcMaterialUsageDefinition(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcMeasureWithUnit = class { - constructor(expressID, type, ValueComponent, UnitComponent) { - this.expressID = expressID; - this.type = type; - this.ValueComponent = ValueComponent; - this.UnitComponent = UnitComponent; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ValueComponent = tape[ptr++]; - let UnitComponent = tape[ptr++]; - return new IfcMeasureWithUnit(expressID, type, ValueComponent, UnitComponent); - } - ToTape() { - let args = []; - args.push(this.ValueComponent); - args.push(this.UnitComponent); - return args; - } -}; -var IfcMechanicalFastener = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NominalDiameter, NominalLength, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.NominalDiameter = NominalDiameter; - this.NominalLength = NominalLength; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let NominalDiameter = tape[ptr++]; - let NominalLength = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMechanicalFastener(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NominalDiameter, NominalLength, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.NominalDiameter); - args.push(this.NominalLength); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMechanicalFastenerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, NominalLength) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.NominalDiameter = NominalDiameter; - this.NominalLength = NominalLength; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let NominalDiameter = tape[ptr++]; - let NominalLength = tape[ptr++]; - return new IfcMechanicalFastenerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, NominalLength); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.NominalDiameter); - args.push(this.NominalLength); - return args; - } -}; -var IfcMedicalDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMedicalDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMedicalDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMedicalDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMember = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMemberStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMemberStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMemberType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMemberType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMetric = class { - constructor(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, Benchmark, ValueSource, DataValue, ReferencePath) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.ConstraintGrade = ConstraintGrade; - this.ConstraintSource = ConstraintSource; - this.CreatingActor = CreatingActor; - this.CreationTime = CreationTime; - this.UserDefinedGrade = UserDefinedGrade; - this.Benchmark = Benchmark; - this.ValueSource = ValueSource; - this.DataValue = DataValue; - this.ReferencePath = ReferencePath; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ConstraintGrade = tape[ptr++]; - let ConstraintSource = tape[ptr++]; - let CreatingActor = tape[ptr++]; - let CreationTime = tape[ptr++]; - let UserDefinedGrade = tape[ptr++]; - let Benchmark = tape[ptr++]; - let ValueSource = tape[ptr++]; - let DataValue = tape[ptr++]; - let ReferencePath = tape[ptr++]; - return new IfcMetric(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, Benchmark, ValueSource, DataValue, ReferencePath); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.ConstraintGrade); - args.push(this.ConstraintSource); - args.push(this.CreatingActor); - args.push(this.CreationTime); - args.push(this.UserDefinedGrade); - args.push(this.Benchmark); - args.push(this.ValueSource); - args.push(this.DataValue); - args.push(this.ReferencePath); - return args; - } -}; -var IfcMirroredProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.ParentProfile = ParentProfile; - this.Operator = Operator; - this.Label = Label; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let ParentProfile = tape[ptr++]; - let Operator = tape[ptr++]; - let Label = tape[ptr++]; - return new IfcMirroredProfileDef(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.ParentProfile); - args.push(this.Operator); - args.push(this.Label); - return args; - } -}; -var IfcMonetaryUnit = class { - constructor(expressID, type, Currency) { - this.expressID = expressID; - this.type = type; - this.Currency = Currency; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Currency = tape[ptr++]; - return new IfcMonetaryUnit(expressID, type, Currency); - } - ToTape() { - let args = []; - args.push(this.Currency); - return args; - } -}; -var IfcMotorConnection = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMotorConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcMotorConnectionType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcMotorConnectionType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcNamedUnit = class { - constructor(expressID, type, Dimensions, UnitType) { - this.expressID = expressID; - this.type = type; - this.Dimensions = Dimensions; - this.UnitType = UnitType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Dimensions = tape[ptr++]; - let UnitType = tape[ptr++]; - return new IfcNamedUnit(expressID, type, Dimensions, UnitType); - } - ToTape() { - let args = []; - args.push(this.Dimensions); - args.push(this.UnitType); - return args; - } -}; -var IfcObject = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - return new IfcObject(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - return args; - } -}; -var IfcObjectDefinition = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcObjectDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcObjectPlacement = class { - constructor(expressID, type, PlacementRelTo) { - this.expressID = expressID; - this.type = type; - this.PlacementRelTo = PlacementRelTo; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let PlacementRelTo = tape[ptr++]; - return new IfcObjectPlacement(expressID, type, PlacementRelTo); - } - ToTape() { - let args = []; - args.push(this.PlacementRelTo); - return args; - } -}; -var IfcObjective = class { - constructor(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, BenchmarkValues, LogicalAggregator, ObjectiveQualifier, UserDefinedQualifier) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.ConstraintGrade = ConstraintGrade; - this.ConstraintSource = ConstraintSource; - this.CreatingActor = CreatingActor; - this.CreationTime = CreationTime; - this.UserDefinedGrade = UserDefinedGrade; - this.BenchmarkValues = BenchmarkValues; - this.LogicalAggregator = LogicalAggregator; - this.ObjectiveQualifier = ObjectiveQualifier; - this.UserDefinedQualifier = UserDefinedQualifier; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ConstraintGrade = tape[ptr++]; - let ConstraintSource = tape[ptr++]; - let CreatingActor = tape[ptr++]; - let CreationTime = tape[ptr++]; - let UserDefinedGrade = tape[ptr++]; - let BenchmarkValues = tape[ptr++]; - let LogicalAggregator = tape[ptr++]; - let ObjectiveQualifier = tape[ptr++]; - let UserDefinedQualifier = tape[ptr++]; - return new IfcObjective(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, BenchmarkValues, LogicalAggregator, ObjectiveQualifier, UserDefinedQualifier); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.ConstraintGrade); - args.push(this.ConstraintSource); - args.push(this.CreatingActor); - args.push(this.CreationTime); - args.push(this.UserDefinedGrade); - args.push(this.BenchmarkValues); - args.push(this.LogicalAggregator); - args.push(this.ObjectiveQualifier); - args.push(this.UserDefinedQualifier); - return args; - } -}; -var IfcOccupant = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.TheActor = TheActor; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let TheActor = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcOccupant(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.TheActor); - args.push(this.PredefinedType); - return args; - } -}; -var IfcOffsetCurve = class { - constructor(expressID, type, BasisCurve) { - this.expressID = expressID; - this.type = type; - this.BasisCurve = BasisCurve; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisCurve = tape[ptr++]; - return new IfcOffsetCurve(expressID, type, BasisCurve); - } - ToTape() { - let args = []; - args.push(this.BasisCurve); - return args; - } -}; -var IfcOffsetCurve2D = class { - constructor(expressID, type, BasisCurve, Distance, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.BasisCurve = BasisCurve; - this.Distance = Distance; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisCurve = tape[ptr++]; - let Distance = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcOffsetCurve2D(expressID, type, BasisCurve, Distance, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.BasisCurve); - args.push(this.Distance); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcOffsetCurve3D = class { - constructor(expressID, type, BasisCurve, Distance, SelfIntersect, RefDirection) { - this.expressID = expressID; - this.type = type; - this.BasisCurve = BasisCurve; - this.Distance = Distance; - this.SelfIntersect = SelfIntersect; - this.RefDirection = RefDirection; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisCurve = tape[ptr++]; - let Distance = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - let RefDirection = tape[ptr++]; - return new IfcOffsetCurve3D(expressID, type, BasisCurve, Distance, SelfIntersect, RefDirection); - } - ToTape() { - let args = []; - args.push(this.BasisCurve); - args.push(this.Distance); - args.push(this.SelfIntersect); - args.push(this.RefDirection); - return args; - } -}; -var IfcOffsetCurveByDistances = class { - constructor(expressID, type, BasisCurve, OffsetValues, Tag) { - this.expressID = expressID; - this.type = type; - this.BasisCurve = BasisCurve; - this.OffsetValues = OffsetValues; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisCurve = tape[ptr++]; - let OffsetValues = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcOffsetCurveByDistances(expressID, type, BasisCurve, OffsetValues, Tag); - } - ToTape() { - let args = []; - args.push(this.BasisCurve); - args.push(this.OffsetValues); - args.push(this.Tag); - return args; - } -}; -var IfcOpenShell = class { - constructor(expressID, type, CfsFaces) { - this.expressID = expressID; - this.type = type; - this.CfsFaces = CfsFaces; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let CfsFaces = tape[ptr++]; - return new IfcOpenShell(expressID, type, CfsFaces); - } - ToTape() { - let args = []; - args.push(this.CfsFaces); - return args; - } -}; -var IfcOpeningElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcOpeningElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcOpeningStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcOpeningStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcOrganization = class { - constructor(expressID, type, Identification, Name, Description, Roles, Addresses) { - this.expressID = expressID; - this.type = type; - this.Identification = Identification; - this.Name = Name; - this.Description = Description; - this.Roles = Roles; - this.Addresses = Addresses; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Identification = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Roles = tape[ptr++]; - let Addresses = tape[ptr++]; - return new IfcOrganization(expressID, type, Identification, Name, Description, Roles, Addresses); - } - ToTape() { - let args = []; - args.push(this.Identification); - args.push(this.Name); - args.push(this.Description); - args.push(this.Roles); - args.push(this.Addresses); - return args; - } -}; -var IfcOrganizationRelationship = class { - constructor(expressID, type, Name, Description, RelatingOrganization, RelatedOrganizations) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingOrganization = RelatingOrganization; - this.RelatedOrganizations = RelatedOrganizations; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingOrganization = tape[ptr++]; - let RelatedOrganizations = tape[ptr++]; - return new IfcOrganizationRelationship(expressID, type, Name, Description, RelatingOrganization, RelatedOrganizations); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingOrganization); - args.push(this.RelatedOrganizations); - return args; - } -}; -var IfcOrientationExpression = class { - constructor(expressID, type, LateralAxisDirection, VerticalAxisDirection) { - this.expressID = expressID; - this.type = type; - this.LateralAxisDirection = LateralAxisDirection; - this.VerticalAxisDirection = VerticalAxisDirection; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let LateralAxisDirection = tape[ptr++]; - let VerticalAxisDirection = tape[ptr++]; - return new IfcOrientationExpression(expressID, type, LateralAxisDirection, VerticalAxisDirection); - } - ToTape() { - let args = []; - args.push(this.LateralAxisDirection); - args.push(this.VerticalAxisDirection); - return args; - } -}; -var IfcOrientedEdge = class { - constructor(expressID, type, EdgeStart, EdgeEnd, EdgeElement, Orientation) { - this.expressID = expressID; - this.type = type; - this.EdgeStart = EdgeStart; - this.EdgeEnd = EdgeEnd; - this.EdgeElement = EdgeElement; - this.Orientation = Orientation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let EdgeStart = tape[ptr++]; - let EdgeEnd = tape[ptr++]; - let EdgeElement = tape[ptr++]; - let Orientation = tape[ptr++]; - return new IfcOrientedEdge(expressID, type, EdgeStart, EdgeEnd, EdgeElement, Orientation); - } - ToTape() { - let args = []; - args.push(this.EdgeStart); - args.push(this.EdgeEnd); - args.push(this.EdgeElement); - args.push(this.Orientation); - return args; - } -}; -var IfcOuterBoundaryCurve = class { - constructor(expressID, type, Segments, SelfIntersect) { - this.expressID = expressID; - this.type = type; - this.Segments = Segments; - this.SelfIntersect = SelfIntersect; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Segments = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - return new IfcOuterBoundaryCurve(expressID, type, Segments, SelfIntersect); - } - ToTape() { - let args = []; - args.push(this.Segments); - args.push(this.SelfIntersect); - return args; - } -}; -var IfcOutlet = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcOutlet(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcOutletType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcOutletType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcOwnerHistory = class { - constructor(expressID, type, OwningUser, OwningApplication, State, ChangeAction, LastModifiedDate, LastModifyingUser, LastModifyingApplication, CreationDate) { - this.expressID = expressID; - this.type = type; - this.OwningUser = OwningUser; - this.OwningApplication = OwningApplication; - this.State = State; - this.ChangeAction = ChangeAction; - this.LastModifiedDate = LastModifiedDate; - this.LastModifyingUser = LastModifyingUser; - this.LastModifyingApplication = LastModifyingApplication; - this.CreationDate = CreationDate; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let OwningUser = tape[ptr++]; - let OwningApplication = tape[ptr++]; - let State = tape[ptr++]; - let ChangeAction = tape[ptr++]; - let LastModifiedDate = tape[ptr++]; - let LastModifyingUser = tape[ptr++]; - let LastModifyingApplication = tape[ptr++]; - let CreationDate = tape[ptr++]; - return new IfcOwnerHistory(expressID, type, OwningUser, OwningApplication, State, ChangeAction, LastModifiedDate, LastModifyingUser, LastModifyingApplication, CreationDate); - } - ToTape() { - let args = []; - args.push(this.OwningUser); - args.push(this.OwningApplication); - args.push(this.State); - args.push(this.ChangeAction); - args.push(this.LastModifiedDate); - args.push(this.LastModifyingUser); - args.push(this.LastModifyingApplication); - args.push(this.CreationDate); - return args; - } -}; -var IfcParameterizedProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - return new IfcParameterizedProfileDef(expressID, type, ProfileType, ProfileName, Position); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - return args; - } -}; -var IfcPath = class { - constructor(expressID, type, EdgeList) { - this.expressID = expressID; - this.type = type; - this.EdgeList = EdgeList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let EdgeList = tape[ptr++]; - return new IfcPath(expressID, type, EdgeList); - } - ToTape() { - let args = []; - args.push(this.EdgeList); - return args; - } -}; -var IfcPcurve = class { - constructor(expressID, type, BasisSurface, ReferenceCurve) { - this.expressID = expressID; - this.type = type; - this.BasisSurface = BasisSurface; - this.ReferenceCurve = ReferenceCurve; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisSurface = tape[ptr++]; - let ReferenceCurve = tape[ptr++]; - return new IfcPcurve(expressID, type, BasisSurface, ReferenceCurve); - } - ToTape() { - let args = []; - args.push(this.BasisSurface); - args.push(this.ReferenceCurve); - return args; - } -}; -var IfcPerformanceHistory = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LifeCyclePhase, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LifeCyclePhase = LifeCyclePhase; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LifeCyclePhase = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPerformanceHistory(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LifeCyclePhase, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LifeCyclePhase); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPermeableCoveringProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.OperationType = OperationType; - this.PanelPosition = PanelPosition; - this.FrameDepth = FrameDepth; - this.FrameThickness = FrameThickness; - this.ShapeAspectStyle = ShapeAspectStyle; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let OperationType = tape[ptr++]; - let PanelPosition = tape[ptr++]; - let FrameDepth = tape[ptr++]; - let FrameThickness = tape[ptr++]; - let ShapeAspectStyle = tape[ptr++]; - return new IfcPermeableCoveringProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.OperationType); - args.push(this.PanelPosition); - args.push(this.FrameDepth); - args.push(this.FrameThickness); - args.push(this.ShapeAspectStyle); - return args; - } -}; -var IfcPermit = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.PredefinedType = PredefinedType; - this.Status = Status; - this.LongDescription = LongDescription; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Status = tape[ptr++]; - let LongDescription = tape[ptr++]; - return new IfcPermit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.PredefinedType); - args.push(this.Status); - args.push(this.LongDescription); - return args; - } -}; -var IfcPerson = class { - constructor(expressID, type, Identification, FamilyName, GivenName, MiddleNames, PrefixTitles, SuffixTitles, Roles, Addresses) { - this.expressID = expressID; - this.type = type; - this.Identification = Identification; - this.FamilyName = FamilyName; - this.GivenName = GivenName; - this.MiddleNames = MiddleNames; - this.PrefixTitles = PrefixTitles; - this.SuffixTitles = SuffixTitles; - this.Roles = Roles; - this.Addresses = Addresses; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Identification = tape[ptr++]; - let FamilyName = tape[ptr++]; - let GivenName = tape[ptr++]; - let MiddleNames = tape[ptr++]; - let PrefixTitles = tape[ptr++]; - let SuffixTitles = tape[ptr++]; - let Roles = tape[ptr++]; - let Addresses = tape[ptr++]; - return new IfcPerson(expressID, type, Identification, FamilyName, GivenName, MiddleNames, PrefixTitles, SuffixTitles, Roles, Addresses); - } - ToTape() { - let args = []; - args.push(this.Identification); - args.push(this.FamilyName); - args.push(this.GivenName); - args.push(this.MiddleNames); - args.push(this.PrefixTitles); - args.push(this.SuffixTitles); - args.push(this.Roles); - args.push(this.Addresses); - return args; - } -}; -var IfcPersonAndOrganization = class { - constructor(expressID, type, ThePerson, TheOrganization, Roles) { - this.expressID = expressID; - this.type = type; - this.ThePerson = ThePerson; - this.TheOrganization = TheOrganization; - this.Roles = Roles; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ThePerson = tape[ptr++]; - let TheOrganization = tape[ptr++]; - let Roles = tape[ptr++]; - return new IfcPersonAndOrganization(expressID, type, ThePerson, TheOrganization, Roles); - } - ToTape() { - let args = []; - args.push(this.ThePerson); - args.push(this.TheOrganization); - args.push(this.Roles); - return args; - } -}; -var IfcPhysicalComplexQuantity = class { - constructor(expressID, type, Name, Description, HasQuantities, Discrimination, Quality, Usage) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.HasQuantities = HasQuantities; - this.Discrimination = Discrimination; - this.Quality = Quality; - this.Usage = Usage; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let HasQuantities = tape[ptr++]; - let Discrimination = tape[ptr++]; - let Quality = tape[ptr++]; - let Usage = tape[ptr++]; - return new IfcPhysicalComplexQuantity(expressID, type, Name, Description, HasQuantities, Discrimination, Quality, Usage); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.HasQuantities); - args.push(this.Discrimination); - args.push(this.Quality); - args.push(this.Usage); - return args; - } -}; -var IfcPhysicalQuantity = class { - constructor(expressID, type, Name, Description) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcPhysicalQuantity(expressID, type, Name, Description); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcPhysicalSimpleQuantity = class { - constructor(expressID, type, Name, Description, Unit) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - return new IfcPhysicalSimpleQuantity(expressID, type, Name, Description, Unit); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - return args; - } -}; -var IfcPile = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType, ConstructionType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - this.ConstructionType = ConstructionType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let ConstructionType = tape[ptr++]; - return new IfcPile(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType, ConstructionType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - args.push(this.ConstructionType); - return args; - } -}; -var IfcPileType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPileType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPipeFitting = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPipeFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPipeFittingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPipeFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPipeSegment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPipeSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPipeSegmentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPipeSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPixelTexture = class { - constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, Width, Height, ColourComponents, Pixel) { - this.expressID = expressID; - this.type = type; - this.RepeatS = RepeatS; - this.RepeatT = RepeatT; - this.Mode = Mode; - this.TextureTransform = TextureTransform; - this.Parameter = Parameter; - this.Width = Width; - this.Height = Height; - this.ColourComponents = ColourComponents; - this.Pixel = Pixel; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RepeatS = tape[ptr++]; - let RepeatT = tape[ptr++]; - let Mode = tape[ptr++]; - let TextureTransform = tape[ptr++]; - let Parameter = tape[ptr++]; - let Width = tape[ptr++]; - let Height = tape[ptr++]; - let ColourComponents = tape[ptr++]; - let Pixel = tape[ptr++]; - return new IfcPixelTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, Width, Height, ColourComponents, Pixel); - } - ToTape() { - let args = []; - args.push(this.RepeatS); - args.push(this.RepeatT); - args.push(this.Mode); - args.push(this.TextureTransform); - args.push(this.Parameter); - args.push(this.Width); - args.push(this.Height); - args.push(this.ColourComponents); - args.push(this.Pixel); - return args; - } -}; -var IfcPlacement = class { - constructor(expressID, type, Location) { - this.expressID = expressID; - this.type = type; - this.Location = Location; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Location = tape[ptr++]; - return new IfcPlacement(expressID, type, Location); - } - ToTape() { - let args = []; - args.push(this.Location); - return args; - } -}; -var IfcPlanarBox = class { - constructor(expressID, type, SizeInX, SizeInY, Placement) { - this.expressID = expressID; - this.type = type; - this.SizeInX = SizeInX; - this.SizeInY = SizeInY; - this.Placement = Placement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SizeInX = tape[ptr++]; - let SizeInY = tape[ptr++]; - let Placement = tape[ptr++]; - return new IfcPlanarBox(expressID, type, SizeInX, SizeInY, Placement); - } - ToTape() { - let args = []; - args.push(this.SizeInX); - args.push(this.SizeInY); - args.push(this.Placement); - return args; - } -}; -var IfcPlanarExtent = class { - constructor(expressID, type, SizeInX, SizeInY) { - this.expressID = expressID; - this.type = type; - this.SizeInX = SizeInX; - this.SizeInY = SizeInY; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SizeInX = tape[ptr++]; - let SizeInY = tape[ptr++]; - return new IfcPlanarExtent(expressID, type, SizeInX, SizeInY); - } - ToTape() { - let args = []; - args.push(this.SizeInX); - args.push(this.SizeInY); - return args; - } -}; -var IfcPlane = class { - constructor(expressID, type, Position) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - return new IfcPlane(expressID, type, Position); - } - ToTape() { - let args = []; - args.push(this.Position); - return args; - } -}; -var IfcPlate = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPlate(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPlateStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPlateStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPlateType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPlateType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPoint = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcPoint(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcPointOnCurve = class { - constructor(expressID, type, BasisCurve, PointParameter) { - this.expressID = expressID; - this.type = type; - this.BasisCurve = BasisCurve; - this.PointParameter = PointParameter; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisCurve = tape[ptr++]; - let PointParameter = tape[ptr++]; - return new IfcPointOnCurve(expressID, type, BasisCurve, PointParameter); - } - ToTape() { - let args = []; - args.push(this.BasisCurve); - args.push(this.PointParameter); - return args; - } -}; -var IfcPointOnSurface = class { - constructor(expressID, type, BasisSurface, PointParameterU, PointParameterV) { - this.expressID = expressID; - this.type = type; - this.BasisSurface = BasisSurface; - this.PointParameterU = PointParameterU; - this.PointParameterV = PointParameterV; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisSurface = tape[ptr++]; - let PointParameterU = tape[ptr++]; - let PointParameterV = tape[ptr++]; - return new IfcPointOnSurface(expressID, type, BasisSurface, PointParameterU, PointParameterV); - } - ToTape() { - let args = []; - args.push(this.BasisSurface); - args.push(this.PointParameterU); - args.push(this.PointParameterV); - return args; - } -}; -var IfcPolyLoop = class { - constructor(expressID, type, Polygon) { - this.expressID = expressID; - this.type = type; - this.Polygon = Polygon; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Polygon = tape[ptr++]; - return new IfcPolyLoop(expressID, type, Polygon); - } - ToTape() { - let args = []; - args.push(this.Polygon); - return args; - } -}; -var IfcPolygonalBoundedHalfSpace = class { - constructor(expressID, type, BaseSurface, AgreementFlag, Position, PolygonalBoundary) { - this.expressID = expressID; - this.type = type; - this.BaseSurface = BaseSurface; - this.AgreementFlag = AgreementFlag; - this.Position = Position; - this.PolygonalBoundary = PolygonalBoundary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BaseSurface = tape[ptr++]; - let AgreementFlag = tape[ptr++]; - let Position = tape[ptr++]; - let PolygonalBoundary = tape[ptr++]; - return new IfcPolygonalBoundedHalfSpace(expressID, type, BaseSurface, AgreementFlag, Position, PolygonalBoundary); - } - ToTape() { - let args = []; - args.push(this.BaseSurface); - args.push(this.AgreementFlag); - args.push(this.Position); - args.push(this.PolygonalBoundary); - return args; - } -}; -var IfcPolygonalFaceSet = class { - constructor(expressID, type, Coordinates, Closed, Faces, PnIndex) { - this.expressID = expressID; - this.type = type; - this.Coordinates = Coordinates; - this.Closed = Closed; - this.Faces = Faces; - this.PnIndex = PnIndex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Coordinates = tape[ptr++]; - let Closed = tape[ptr++]; - let Faces = tape[ptr++]; - let PnIndex = tape[ptr++]; - return new IfcPolygonalFaceSet(expressID, type, Coordinates, Closed, Faces, PnIndex); - } - ToTape() { - let args = []; - args.push(this.Coordinates); - args.push(this.Closed); - args.push(this.Faces); - args.push(this.PnIndex); - return args; - } -}; -var IfcPolyline = class { - constructor(expressID, type, Points) { - this.expressID = expressID; - this.type = type; - this.Points = Points; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Points = tape[ptr++]; - return new IfcPolyline(expressID, type, Points); - } - ToTape() { - let args = []; - args.push(this.Points); - return args; - } -}; -var IfcPort = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - return new IfcPort(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - return args; - } -}; -var IfcPositioningElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - return new IfcPositioningElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - return args; - } -}; -var IfcPostalAddress = class { - constructor(expressID, type, Purpose, Description, UserDefinedPurpose, InternalLocation, AddressLines, PostalBox, Town, Region, PostalCode, Country) { - this.expressID = expressID; - this.type = type; - this.Purpose = Purpose; - this.Description = Description; - this.UserDefinedPurpose = UserDefinedPurpose; - this.InternalLocation = InternalLocation; - this.AddressLines = AddressLines; - this.PostalBox = PostalBox; - this.Town = Town; - this.Region = Region; - this.PostalCode = PostalCode; - this.Country = Country; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Purpose = tape[ptr++]; - let Description = tape[ptr++]; - let UserDefinedPurpose = tape[ptr++]; - let InternalLocation = tape[ptr++]; - let AddressLines = tape[ptr++]; - let PostalBox = tape[ptr++]; - let Town = tape[ptr++]; - let Region = tape[ptr++]; - let PostalCode = tape[ptr++]; - let Country = tape[ptr++]; - return new IfcPostalAddress(expressID, type, Purpose, Description, UserDefinedPurpose, InternalLocation, AddressLines, PostalBox, Town, Region, PostalCode, Country); - } - ToTape() { - let args = []; - args.push(this.Purpose); - args.push(this.Description); - args.push(this.UserDefinedPurpose); - args.push(this.InternalLocation); - args.push(this.AddressLines); - args.push(this.PostalBox); - args.push(this.Town); - args.push(this.Region); - args.push(this.PostalCode); - args.push(this.Country); - return args; - } -}; -var IfcPreDefinedColour = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcPreDefinedColour(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcPreDefinedCurveFont = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcPreDefinedCurveFont(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcPreDefinedItem = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcPreDefinedItem(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcPreDefinedProperties = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcPreDefinedProperties(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcPreDefinedPropertySet = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcPreDefinedPropertySet(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcPreDefinedTextFont = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcPreDefinedTextFont(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcPresentationItem = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcPresentationItem(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcPresentationLayerAssignment = class { - constructor(expressID, type, Name, Description, AssignedItems, Identifier) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.AssignedItems = AssignedItems; - this.Identifier = Identifier; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let AssignedItems = tape[ptr++]; - let Identifier = tape[ptr++]; - return new IfcPresentationLayerAssignment(expressID, type, Name, Description, AssignedItems, Identifier); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.AssignedItems); - args.push(this.Identifier); - return args; - } -}; -var IfcPresentationLayerWithStyle = class { - constructor(expressID, type, Name, Description, AssignedItems, Identifier, LayerOn, LayerFrozen, LayerBlocked, LayerStyles) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.AssignedItems = AssignedItems; - this.Identifier = Identifier; - this.LayerOn = LayerOn; - this.LayerFrozen = LayerFrozen; - this.LayerBlocked = LayerBlocked; - this.LayerStyles = LayerStyles; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let AssignedItems = tape[ptr++]; - let Identifier = tape[ptr++]; - let LayerOn = tape[ptr++]; - let LayerFrozen = tape[ptr++]; - let LayerBlocked = tape[ptr++]; - let LayerStyles = tape[ptr++]; - return new IfcPresentationLayerWithStyle(expressID, type, Name, Description, AssignedItems, Identifier, LayerOn, LayerFrozen, LayerBlocked, LayerStyles); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.AssignedItems); - args.push(this.Identifier); - args.push(this.LayerOn); - args.push(this.LayerFrozen); - args.push(this.LayerBlocked); - args.push(this.LayerStyles); - return args; - } -}; -var IfcPresentationStyle = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcPresentationStyle(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcPresentationStyleAssignment = class { - constructor(expressID, type, Styles) { - this.expressID = expressID; - this.type = type; - this.Styles = Styles; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Styles = tape[ptr++]; - return new IfcPresentationStyleAssignment(expressID, type, Styles); - } - ToTape() { - let args = []; - args.push(this.Styles); - return args; - } -}; -var IfcProcedure = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProcedure(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProcedureType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ProcessType = ProcessType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ProcessType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProcedureType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ProcessType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProcess = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - return new IfcProcess(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - return args; - } -}; -var IfcProduct = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - return new IfcProduct(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - return args; - } -}; -var IfcProductDefinitionShape = class { - constructor(expressID, type, Name, Description, Representations) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Representations = Representations; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Representations = tape[ptr++]; - return new IfcProductDefinitionShape(expressID, type, Name, Description, Representations); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Representations); - return args; - } -}; -var IfcProductRepresentation = class { - constructor(expressID, type, Name, Description, Representations) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Representations = Representations; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Representations = tape[ptr++]; - return new IfcProductRepresentation(expressID, type, Name, Description, Representations); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Representations); - return args; - } -}; -var IfcProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - return new IfcProfileDef(expressID, type, ProfileType, ProfileName); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - return args; - } -}; -var IfcProfileProperties = class { - constructor(expressID, type, Name, Description, Properties2, ProfileDefinition) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Properties = Properties2; - this.ProfileDefinition = ProfileDefinition; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Properties2 = tape[ptr++]; - let ProfileDefinition = tape[ptr++]; - return new IfcProfileProperties(expressID, type, Name, Description, Properties2, ProfileDefinition); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Properties); - args.push(this.ProfileDefinition); - return args; - } -}; -var IfcProject = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.LongName = LongName; - this.Phase = Phase; - this.RepresentationContexts = RepresentationContexts; - this.UnitsInContext = UnitsInContext; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let LongName = tape[ptr++]; - let Phase = tape[ptr++]; - let RepresentationContexts = tape[ptr++]; - let UnitsInContext = tape[ptr++]; - return new IfcProject(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.LongName); - args.push(this.Phase); - args.push(this.RepresentationContexts); - args.push(this.UnitsInContext); - return args; - } -}; -var IfcProjectLibrary = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.LongName = LongName; - this.Phase = Phase; - this.RepresentationContexts = RepresentationContexts; - this.UnitsInContext = UnitsInContext; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let LongName = tape[ptr++]; - let Phase = tape[ptr++]; - let RepresentationContexts = tape[ptr++]; - let UnitsInContext = tape[ptr++]; - return new IfcProjectLibrary(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.LongName); - args.push(this.Phase); - args.push(this.RepresentationContexts); - args.push(this.UnitsInContext); - return args; - } -}; -var IfcProjectOrder = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.PredefinedType = PredefinedType; - this.Status = Status; - this.LongDescription = LongDescription; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Status = tape[ptr++]; - let LongDescription = tape[ptr++]; - return new IfcProjectOrder(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.PredefinedType); - args.push(this.Status); - args.push(this.LongDescription); - return args; - } -}; -var IfcProjectedCRS = class { - constructor(expressID, type, Name, Description, GeodeticDatum, VerticalDatum, MapProjection, MapZone, MapUnit) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.GeodeticDatum = GeodeticDatum; - this.VerticalDatum = VerticalDatum; - this.MapProjection = MapProjection; - this.MapZone = MapZone; - this.MapUnit = MapUnit; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let GeodeticDatum = tape[ptr++]; - let VerticalDatum = tape[ptr++]; - let MapProjection = tape[ptr++]; - let MapZone = tape[ptr++]; - let MapUnit = tape[ptr++]; - return new IfcProjectedCRS(expressID, type, Name, Description, GeodeticDatum, VerticalDatum, MapProjection, MapZone, MapUnit); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.GeodeticDatum); - args.push(this.VerticalDatum); - args.push(this.MapProjection); - args.push(this.MapZone); - args.push(this.MapUnit); - return args; - } -}; -var IfcProjectionElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProjectionElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProperty = class { - constructor(expressID, type, Name, Description) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcProperty(expressID, type, Name, Description); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcPropertyAbstraction = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcPropertyAbstraction(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcPropertyBoundedValue = class { - constructor(expressID, type, Name, Description, UpperBoundValue, LowerBoundValue, Unit, SetPointValue) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.UpperBoundValue = UpperBoundValue; - this.LowerBoundValue = LowerBoundValue; - this.Unit = Unit; - this.SetPointValue = SetPointValue; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let UpperBoundValue = tape[ptr++]; - let LowerBoundValue = tape[ptr++]; - let Unit = tape[ptr++]; - let SetPointValue = tape[ptr++]; - return new IfcPropertyBoundedValue(expressID, type, Name, Description, UpperBoundValue, LowerBoundValue, Unit, SetPointValue); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.UpperBoundValue); - args.push(this.LowerBoundValue); - args.push(this.Unit); - args.push(this.SetPointValue); - return args; - } -}; -var IfcPropertyDefinition = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcPropertyDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcPropertyDependencyRelationship = class { - constructor(expressID, type, Name, Description, DependingProperty, DependantProperty, Expression) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.DependingProperty = DependingProperty; - this.DependantProperty = DependantProperty; - this.Expression = Expression; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let DependingProperty = tape[ptr++]; - let DependantProperty = tape[ptr++]; - let Expression = tape[ptr++]; - return new IfcPropertyDependencyRelationship(expressID, type, Name, Description, DependingProperty, DependantProperty, Expression); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.DependingProperty); - args.push(this.DependantProperty); - args.push(this.Expression); - return args; - } -}; -var IfcPropertyEnumeratedValue = class { - constructor(expressID, type, Name, Description, EnumerationValues, EnumerationReference) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.EnumerationValues = EnumerationValues; - this.EnumerationReference = EnumerationReference; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let EnumerationValues = tape[ptr++]; - let EnumerationReference = tape[ptr++]; - return new IfcPropertyEnumeratedValue(expressID, type, Name, Description, EnumerationValues, EnumerationReference); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.EnumerationValues); - args.push(this.EnumerationReference); - return args; - } -}; -var IfcPropertyEnumeration = class { - constructor(expressID, type, Name, EnumerationValues, Unit) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.EnumerationValues = EnumerationValues; - this.Unit = Unit; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let EnumerationValues = tape[ptr++]; - let Unit = tape[ptr++]; - return new IfcPropertyEnumeration(expressID, type, Name, EnumerationValues, Unit); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.EnumerationValues); - args.push(this.Unit); - return args; - } -}; -var IfcPropertyListValue = class { - constructor(expressID, type, Name, Description, ListValues, Unit) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.ListValues = ListValues; - this.Unit = Unit; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ListValues = tape[ptr++]; - let Unit = tape[ptr++]; - return new IfcPropertyListValue(expressID, type, Name, Description, ListValues, Unit); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.ListValues); - args.push(this.Unit); - return args; - } -}; -var IfcPropertyReferenceValue = class { - constructor(expressID, type, Name, Description, UsageName, PropertyReference) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.UsageName = UsageName; - this.PropertyReference = PropertyReference; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let UsageName = tape[ptr++]; - let PropertyReference = tape[ptr++]; - return new IfcPropertyReferenceValue(expressID, type, Name, Description, UsageName, PropertyReference); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.UsageName); - args.push(this.PropertyReference); - return args; - } -}; -var IfcPropertySet = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, HasProperties) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.HasProperties = HasProperties; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let HasProperties = tape[ptr++]; - return new IfcPropertySet(expressID, type, GlobalId, OwnerHistory, Name, Description, HasProperties); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.HasProperties); - return args; - } -}; -var IfcPropertySetDefinition = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcPropertySetDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcPropertySetTemplate = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, ApplicableEntity, HasPropertyTemplates) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.TemplateType = TemplateType; - this.ApplicableEntity = ApplicableEntity; - this.HasPropertyTemplates = HasPropertyTemplates; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let TemplateType = tape[ptr++]; - let ApplicableEntity = tape[ptr++]; - let HasPropertyTemplates = tape[ptr++]; - return new IfcPropertySetTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, ApplicableEntity, HasPropertyTemplates); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.TemplateType); - args.push(this.ApplicableEntity); - args.push(this.HasPropertyTemplates); - return args; - } -}; -var IfcPropertySingleValue = class { - constructor(expressID, type, Name, Description, NominalValue, Unit) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.NominalValue = NominalValue; - this.Unit = Unit; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let NominalValue = tape[ptr++]; - let Unit = tape[ptr++]; - return new IfcPropertySingleValue(expressID, type, Name, Description, NominalValue, Unit); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.NominalValue); - args.push(this.Unit); - return args; - } -}; -var IfcPropertyTableValue = class { - constructor(expressID, type, Name, Description, DefiningValues, DefinedValues, Expression, DefiningUnit, DefinedUnit, CurveInterpolation) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.DefiningValues = DefiningValues; - this.DefinedValues = DefinedValues; - this.Expression = Expression; - this.DefiningUnit = DefiningUnit; - this.DefinedUnit = DefinedUnit; - this.CurveInterpolation = CurveInterpolation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let DefiningValues = tape[ptr++]; - let DefinedValues = tape[ptr++]; - let Expression = tape[ptr++]; - let DefiningUnit = tape[ptr++]; - let DefinedUnit = tape[ptr++]; - let CurveInterpolation = tape[ptr++]; - return new IfcPropertyTableValue(expressID, type, Name, Description, DefiningValues, DefinedValues, Expression, DefiningUnit, DefinedUnit, CurveInterpolation); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.DefiningValues); - args.push(this.DefinedValues); - args.push(this.Expression); - args.push(this.DefiningUnit); - args.push(this.DefinedUnit); - args.push(this.CurveInterpolation); - return args; - } -}; -var IfcPropertyTemplate = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcPropertyTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcPropertyTemplateDefinition = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcPropertyTemplateDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcProtectiveDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProtectiveDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProtectiveDeviceTrippingUnit = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProtectiveDeviceTrippingUnit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProtectiveDeviceTrippingUnitType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProtectiveDeviceTrippingUnitType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProtectiveDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcProtectiveDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcProxy = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, ProxyType, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.ProxyType = ProxyType; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let ProxyType = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcProxy(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, ProxyType, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.ProxyType); - args.push(this.Tag); - return args; - } -}; -var IfcPump = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPump(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcPumpType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcPumpType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcQuantityArea = class { - constructor(expressID, type, Name, Description, Unit, AreaValue, Formula) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.AreaValue = AreaValue; - this.Formula = Formula; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let AreaValue = tape[ptr++]; - let Formula = tape[ptr++]; - return new IfcQuantityArea(expressID, type, Name, Description, Unit, AreaValue, Formula); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.AreaValue); - args.push(this.Formula); - return args; - } -}; -var IfcQuantityCount = class { - constructor(expressID, type, Name, Description, Unit, CountValue, Formula) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.CountValue = CountValue; - this.Formula = Formula; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let CountValue = tape[ptr++]; - let Formula = tape[ptr++]; - return new IfcQuantityCount(expressID, type, Name, Description, Unit, CountValue, Formula); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.CountValue); - args.push(this.Formula); - return args; - } -}; -var IfcQuantityLength = class { - constructor(expressID, type, Name, Description, Unit, LengthValue, Formula) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.LengthValue = LengthValue; - this.Formula = Formula; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let LengthValue = tape[ptr++]; - let Formula = tape[ptr++]; - return new IfcQuantityLength(expressID, type, Name, Description, Unit, LengthValue, Formula); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.LengthValue); - args.push(this.Formula); - return args; - } -}; -var IfcQuantitySet = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcQuantitySet(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcQuantityTime = class { - constructor(expressID, type, Name, Description, Unit, TimeValue, Formula) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.TimeValue = TimeValue; - this.Formula = Formula; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let TimeValue = tape[ptr++]; - let Formula = tape[ptr++]; - return new IfcQuantityTime(expressID, type, Name, Description, Unit, TimeValue, Formula); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.TimeValue); - args.push(this.Formula); - return args; - } -}; -var IfcQuantityVolume = class { - constructor(expressID, type, Name, Description, Unit, VolumeValue, Formula) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.VolumeValue = VolumeValue; - this.Formula = Formula; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let VolumeValue = tape[ptr++]; - let Formula = tape[ptr++]; - return new IfcQuantityVolume(expressID, type, Name, Description, Unit, VolumeValue, Formula); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.VolumeValue); - args.push(this.Formula); - return args; - } -}; -var IfcQuantityWeight = class { - constructor(expressID, type, Name, Description, Unit, WeightValue, Formula) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.WeightValue = WeightValue; - this.Formula = Formula; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let WeightValue = tape[ptr++]; - let Formula = tape[ptr++]; - return new IfcQuantityWeight(expressID, type, Name, Description, Unit, WeightValue, Formula); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.WeightValue); - args.push(this.Formula); - return args; - } -}; -var IfcRailing = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRailing(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRailingType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRailingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRamp = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRamp(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRampFlight = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRampFlight(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRampFlightType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRampFlightType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRampType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRampType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRationalBSplineCurveWithKnots = class { - constructor(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec, WeightsData) { - this.expressID = expressID; - this.type = type; - this.Degree = Degree; - this.ControlPointsList = ControlPointsList; - this.CurveForm = CurveForm; - this.ClosedCurve = ClosedCurve; - this.SelfIntersect = SelfIntersect; - this.KnotMultiplicities = KnotMultiplicities; - this.Knots = Knots; - this.KnotSpec = KnotSpec; - this.WeightsData = WeightsData; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Degree = tape[ptr++]; - let ControlPointsList = tape[ptr++]; - let CurveForm = tape[ptr++]; - let ClosedCurve = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - let KnotMultiplicities = tape[ptr++]; - let Knots = tape[ptr++]; - let KnotSpec = tape[ptr++]; - let WeightsData = tape[ptr++]; - return new IfcRationalBSplineCurveWithKnots(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec, WeightsData); - } - ToTape() { - let args = []; - args.push(this.Degree); - args.push(this.ControlPointsList); - args.push(this.CurveForm); - args.push(this.ClosedCurve); - args.push(this.SelfIntersect); - args.push(this.KnotMultiplicities); - args.push(this.Knots); - args.push(this.KnotSpec); - args.push(this.WeightsData); - return args; - } -}; -var IfcRationalBSplineSurfaceWithKnots = class { - constructor(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec, WeightsData) { - this.expressID = expressID; - this.type = type; - this.UDegree = UDegree; - this.VDegree = VDegree; - this.ControlPointsList = ControlPointsList; - this.SurfaceForm = SurfaceForm; - this.UClosed = UClosed; - this.VClosed = VClosed; - this.SelfIntersect = SelfIntersect; - this.UMultiplicities = UMultiplicities; - this.VMultiplicities = VMultiplicities; - this.UKnots = UKnots; - this.VKnots = VKnots; - this.KnotSpec = KnotSpec; - this.WeightsData = WeightsData; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let UDegree = tape[ptr++]; - let VDegree = tape[ptr++]; - let ControlPointsList = tape[ptr++]; - let SurfaceForm = tape[ptr++]; - let UClosed = tape[ptr++]; - let VClosed = tape[ptr++]; - let SelfIntersect = tape[ptr++]; - let UMultiplicities = tape[ptr++]; - let VMultiplicities = tape[ptr++]; - let UKnots = tape[ptr++]; - let VKnots = tape[ptr++]; - let KnotSpec = tape[ptr++]; - let WeightsData = tape[ptr++]; - return new IfcRationalBSplineSurfaceWithKnots(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec, WeightsData); - } - ToTape() { - let args = []; - args.push(this.UDegree); - args.push(this.VDegree); - args.push(this.ControlPointsList); - args.push(this.SurfaceForm); - args.push(this.UClosed); - args.push(this.VClosed); - args.push(this.SelfIntersect); - args.push(this.UMultiplicities); - args.push(this.VMultiplicities); - args.push(this.UKnots); - args.push(this.VKnots); - args.push(this.KnotSpec); - args.push(this.WeightsData); - return args; - } -}; -var IfcRectangleHollowProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, WallThickness, InnerFilletRadius, OuterFilletRadius) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.XDim = XDim; - this.YDim = YDim; - this.WallThickness = WallThickness; - this.InnerFilletRadius = InnerFilletRadius; - this.OuterFilletRadius = OuterFilletRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let XDim = tape[ptr++]; - let YDim = tape[ptr++]; - let WallThickness = tape[ptr++]; - let InnerFilletRadius = tape[ptr++]; - let OuterFilletRadius = tape[ptr++]; - return new IfcRectangleHollowProfileDef(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, WallThickness, InnerFilletRadius, OuterFilletRadius); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.XDim); - args.push(this.YDim); - args.push(this.WallThickness); - args.push(this.InnerFilletRadius); - args.push(this.OuterFilletRadius); - return args; - } -}; -var IfcRectangleProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, XDim, YDim) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.XDim = XDim; - this.YDim = YDim; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let XDim = tape[ptr++]; - let YDim = tape[ptr++]; - return new IfcRectangleProfileDef(expressID, type, ProfileType, ProfileName, Position, XDim, YDim); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.XDim); - args.push(this.YDim); - return args; - } -}; -var IfcRectangularPyramid = class { - constructor(expressID, type, Position, XLength, YLength, Height) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.XLength = XLength; - this.YLength = YLength; - this.Height = Height; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let XLength = tape[ptr++]; - let YLength = tape[ptr++]; - let Height = tape[ptr++]; - return new IfcRectangularPyramid(expressID, type, Position, XLength, YLength, Height); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.XLength); - args.push(this.YLength); - args.push(this.Height); - return args; - } -}; -var IfcRectangularTrimmedSurface = class { - constructor(expressID, type, BasisSurface, U1, V1, U2, V2, Usense, Vsense) { - this.expressID = expressID; - this.type = type; - this.BasisSurface = BasisSurface; - this.U1 = U1; - this.V1 = V1; - this.U2 = U2; - this.V2 = V2; - this.Usense = Usense; - this.Vsense = Vsense; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisSurface = tape[ptr++]; - let U1 = tape[ptr++]; - let V1 = tape[ptr++]; - let U2 = tape[ptr++]; - let V2 = tape[ptr++]; - let Usense = tape[ptr++]; - let Vsense = tape[ptr++]; - return new IfcRectangularTrimmedSurface(expressID, type, BasisSurface, U1, V1, U2, V2, Usense, Vsense); - } - ToTape() { - let args = []; - args.push(this.BasisSurface); - args.push(this.U1); - args.push(this.V1); - args.push(this.U2); - args.push(this.V2); - args.push(this.Usense); - args.push(this.Vsense); - return args; - } -}; -var IfcRecurrencePattern = class { - constructor(expressID, type, RecurrenceType, DayComponent, WeekdayComponent, MonthComponent, Position, Interval, Occurrences, TimePeriods) { - this.expressID = expressID; - this.type = type; - this.RecurrenceType = RecurrenceType; - this.DayComponent = DayComponent; - this.WeekdayComponent = WeekdayComponent; - this.MonthComponent = MonthComponent; - this.Position = Position; - this.Interval = Interval; - this.Occurrences = Occurrences; - this.TimePeriods = TimePeriods; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RecurrenceType = tape[ptr++]; - let DayComponent = tape[ptr++]; - let WeekdayComponent = tape[ptr++]; - let MonthComponent = tape[ptr++]; - let Position = tape[ptr++]; - let Interval = tape[ptr++]; - let Occurrences = tape[ptr++]; - let TimePeriods = tape[ptr++]; - return new IfcRecurrencePattern(expressID, type, RecurrenceType, DayComponent, WeekdayComponent, MonthComponent, Position, Interval, Occurrences, TimePeriods); - } - ToTape() { - let args = []; - args.push(this.RecurrenceType); - args.push(this.DayComponent); - args.push(this.WeekdayComponent); - args.push(this.MonthComponent); - args.push(this.Position); - args.push(this.Interval); - args.push(this.Occurrences); - args.push(this.TimePeriods); - return args; - } -}; -var IfcReference = class { - constructor(expressID, type, TypeIdentifier, AttributeIdentifier, InstanceName, ListPositions, InnerReference) { - this.expressID = expressID; - this.type = type; - this.TypeIdentifier = TypeIdentifier; - this.AttributeIdentifier = AttributeIdentifier; - this.InstanceName = InstanceName; - this.ListPositions = ListPositions; - this.InnerReference = InnerReference; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TypeIdentifier = tape[ptr++]; - let AttributeIdentifier = tape[ptr++]; - let InstanceName = tape[ptr++]; - let ListPositions = tape[ptr++]; - let InnerReference = tape[ptr++]; - return new IfcReference(expressID, type, TypeIdentifier, AttributeIdentifier, InstanceName, ListPositions, InnerReference); - } - ToTape() { - let args = []; - args.push(this.TypeIdentifier); - args.push(this.AttributeIdentifier); - args.push(this.InstanceName); - args.push(this.ListPositions); - args.push(this.InnerReference); - return args; - } -}; -var IfcReferent = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, RestartDistance) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.PredefinedType = PredefinedType; - this.RestartDistance = RestartDistance; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let RestartDistance = tape[ptr++]; - return new IfcReferent(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, RestartDistance); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.PredefinedType); - args.push(this.RestartDistance); - return args; - } -}; -var IfcRegularTimeSeries = class { - constructor(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, TimeStep, Values) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.StartTime = StartTime; - this.EndTime = EndTime; - this.TimeSeriesDataType = TimeSeriesDataType; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.Unit = Unit; - this.TimeStep = TimeStep; - this.Values = Values; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let StartTime = tape[ptr++]; - let EndTime = tape[ptr++]; - let TimeSeriesDataType = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let Unit = tape[ptr++]; - let TimeStep = tape[ptr++]; - let Values = tape[ptr++]; - return new IfcRegularTimeSeries(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, TimeStep, Values); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.StartTime); - args.push(this.EndTime); - args.push(this.TimeSeriesDataType); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.Unit); - args.push(this.TimeStep); - args.push(this.Values); - return args; - } -}; -var IfcReinforcementBarProperties = class { - constructor(expressID, type, TotalCrossSectionArea, SteelGrade, BarSurface, EffectiveDepth, NominalBarDiameter, BarCount) { - this.expressID = expressID; - this.type = type; - this.TotalCrossSectionArea = TotalCrossSectionArea; - this.SteelGrade = SteelGrade; - this.BarSurface = BarSurface; - this.EffectiveDepth = EffectiveDepth; - this.NominalBarDiameter = NominalBarDiameter; - this.BarCount = BarCount; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TotalCrossSectionArea = tape[ptr++]; - let SteelGrade = tape[ptr++]; - let BarSurface = tape[ptr++]; - let EffectiveDepth = tape[ptr++]; - let NominalBarDiameter = tape[ptr++]; - let BarCount = tape[ptr++]; - return new IfcReinforcementBarProperties(expressID, type, TotalCrossSectionArea, SteelGrade, BarSurface, EffectiveDepth, NominalBarDiameter, BarCount); - } - ToTape() { - let args = []; - args.push(this.TotalCrossSectionArea); - args.push(this.SteelGrade); - args.push(this.BarSurface); - args.push(this.EffectiveDepth); - args.push(this.NominalBarDiameter); - args.push(this.BarCount); - return args; - } -}; -var IfcReinforcementDefinitionProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, DefinitionType, ReinforcementSectionDefinitions) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.DefinitionType = DefinitionType; - this.ReinforcementSectionDefinitions = ReinforcementSectionDefinitions; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let DefinitionType = tape[ptr++]; - let ReinforcementSectionDefinitions = tape[ptr++]; - return new IfcReinforcementDefinitionProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, DefinitionType, ReinforcementSectionDefinitions); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.DefinitionType); - args.push(this.ReinforcementSectionDefinitions); - return args; - } -}; -var IfcReinforcingBar = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, NominalDiameter, CrossSectionArea, BarLength, PredefinedType, BarSurface) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.SteelGrade = SteelGrade; - this.NominalDiameter = NominalDiameter; - this.CrossSectionArea = CrossSectionArea; - this.BarLength = BarLength; - this.PredefinedType = PredefinedType; - this.BarSurface = BarSurface; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let SteelGrade = tape[ptr++]; - let NominalDiameter = tape[ptr++]; - let CrossSectionArea = tape[ptr++]; - let BarLength = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let BarSurface = tape[ptr++]; - return new IfcReinforcingBar(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, NominalDiameter, CrossSectionArea, BarLength, PredefinedType, BarSurface); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.SteelGrade); - args.push(this.NominalDiameter); - args.push(this.CrossSectionArea); - args.push(this.BarLength); - args.push(this.PredefinedType); - args.push(this.BarSurface); - return args; - } -}; -var IfcReinforcingBarType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, BarLength, BarSurface, BendingShapeCode, BendingParameters) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.NominalDiameter = NominalDiameter; - this.CrossSectionArea = CrossSectionArea; - this.BarLength = BarLength; - this.BarSurface = BarSurface; - this.BendingShapeCode = BendingShapeCode; - this.BendingParameters = BendingParameters; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let NominalDiameter = tape[ptr++]; - let CrossSectionArea = tape[ptr++]; - let BarLength = tape[ptr++]; - let BarSurface = tape[ptr++]; - let BendingShapeCode = tape[ptr++]; - let BendingParameters = tape[ptr++]; - return new IfcReinforcingBarType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, BarLength, BarSurface, BendingShapeCode, BendingParameters); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.NominalDiameter); - args.push(this.CrossSectionArea); - args.push(this.BarLength); - args.push(this.BarSurface); - args.push(this.BendingShapeCode); - args.push(this.BendingParameters); - return args; - } -}; -var IfcReinforcingElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.SteelGrade = SteelGrade; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let SteelGrade = tape[ptr++]; - return new IfcReinforcingElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.SteelGrade); - return args; - } -}; -var IfcReinforcingElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcReinforcingElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcReinforcingMesh = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.SteelGrade = SteelGrade; - this.MeshLength = MeshLength; - this.MeshWidth = MeshWidth; - this.LongitudinalBarNominalDiameter = LongitudinalBarNominalDiameter; - this.TransverseBarNominalDiameter = TransverseBarNominalDiameter; - this.LongitudinalBarCrossSectionArea = LongitudinalBarCrossSectionArea; - this.TransverseBarCrossSectionArea = TransverseBarCrossSectionArea; - this.LongitudinalBarSpacing = LongitudinalBarSpacing; - this.TransverseBarSpacing = TransverseBarSpacing; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let SteelGrade = tape[ptr++]; - let MeshLength = tape[ptr++]; - let MeshWidth = tape[ptr++]; - let LongitudinalBarNominalDiameter = tape[ptr++]; - let TransverseBarNominalDiameter = tape[ptr++]; - let LongitudinalBarCrossSectionArea = tape[ptr++]; - let TransverseBarCrossSectionArea = tape[ptr++]; - let LongitudinalBarSpacing = tape[ptr++]; - let TransverseBarSpacing = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcReinforcingMesh(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.SteelGrade); - args.push(this.MeshLength); - args.push(this.MeshWidth); - args.push(this.LongitudinalBarNominalDiameter); - args.push(this.TransverseBarNominalDiameter); - args.push(this.LongitudinalBarCrossSectionArea); - args.push(this.TransverseBarCrossSectionArea); - args.push(this.LongitudinalBarSpacing); - args.push(this.TransverseBarSpacing); - args.push(this.PredefinedType); - return args; - } -}; -var IfcReinforcingMeshType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, BendingShapeCode, BendingParameters) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.MeshLength = MeshLength; - this.MeshWidth = MeshWidth; - this.LongitudinalBarNominalDiameter = LongitudinalBarNominalDiameter; - this.TransverseBarNominalDiameter = TransverseBarNominalDiameter; - this.LongitudinalBarCrossSectionArea = LongitudinalBarCrossSectionArea; - this.TransverseBarCrossSectionArea = TransverseBarCrossSectionArea; - this.LongitudinalBarSpacing = LongitudinalBarSpacing; - this.TransverseBarSpacing = TransverseBarSpacing; - this.BendingShapeCode = BendingShapeCode; - this.BendingParameters = BendingParameters; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let MeshLength = tape[ptr++]; - let MeshWidth = tape[ptr++]; - let LongitudinalBarNominalDiameter = tape[ptr++]; - let TransverseBarNominalDiameter = tape[ptr++]; - let LongitudinalBarCrossSectionArea = tape[ptr++]; - let TransverseBarCrossSectionArea = tape[ptr++]; - let LongitudinalBarSpacing = tape[ptr++]; - let TransverseBarSpacing = tape[ptr++]; - let BendingShapeCode = tape[ptr++]; - let BendingParameters = tape[ptr++]; - return new IfcReinforcingMeshType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, BendingShapeCode, BendingParameters); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.MeshLength); - args.push(this.MeshWidth); - args.push(this.LongitudinalBarNominalDiameter); - args.push(this.TransverseBarNominalDiameter); - args.push(this.LongitudinalBarCrossSectionArea); - args.push(this.TransverseBarCrossSectionArea); - args.push(this.LongitudinalBarSpacing); - args.push(this.TransverseBarSpacing); - args.push(this.BendingShapeCode); - args.push(this.BendingParameters); - return args; - } -}; -var IfcRelAggregates = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingObject = RelatingObject; - this.RelatedObjects = RelatedObjects; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingObject = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - return new IfcRelAggregates(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingObject); - args.push(this.RelatedObjects); - return args; - } -}; -var IfcRelAssigns = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - return new IfcRelAssigns(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - return args; - } -}; -var IfcRelAssignsToActor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingActor, ActingRole) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingActor = RelatingActor; - this.ActingRole = ActingRole; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingActor = tape[ptr++]; - let ActingRole = tape[ptr++]; - return new IfcRelAssignsToActor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingActor, ActingRole); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingActor); - args.push(this.ActingRole); - return args; - } -}; -var IfcRelAssignsToControl = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingControl) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingControl = RelatingControl; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingControl = tape[ptr++]; - return new IfcRelAssignsToControl(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingControl); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingControl); - return args; - } -}; -var IfcRelAssignsToGroup = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingGroup = RelatingGroup; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingGroup = tape[ptr++]; - return new IfcRelAssignsToGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingGroup); - return args; - } -}; -var IfcRelAssignsToGroupByFactor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup, Factor) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingGroup = RelatingGroup; - this.Factor = Factor; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingGroup = tape[ptr++]; - let Factor = tape[ptr++]; - return new IfcRelAssignsToGroupByFactor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup, Factor); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingGroup); - args.push(this.Factor); - return args; - } -}; -var IfcRelAssignsToProcess = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProcess, QuantityInProcess) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingProcess = RelatingProcess; - this.QuantityInProcess = QuantityInProcess; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingProcess = tape[ptr++]; - let QuantityInProcess = tape[ptr++]; - return new IfcRelAssignsToProcess(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProcess, QuantityInProcess); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingProcess); - args.push(this.QuantityInProcess); - return args; - } -}; -var IfcRelAssignsToProduct = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProduct) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingProduct = RelatingProduct; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingProduct = tape[ptr++]; - return new IfcRelAssignsToProduct(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProduct); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingProduct); - return args; - } -}; -var IfcRelAssignsToResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingResource) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatedObjectsType = RelatedObjectsType; - this.RelatingResource = RelatingResource; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatedObjectsType = tape[ptr++]; - let RelatingResource = tape[ptr++]; - return new IfcRelAssignsToResource(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingResource); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatedObjectsType); - args.push(this.RelatingResource); - return args; - } -}; -var IfcRelAssociates = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - return new IfcRelAssociates(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - return args; - } -}; -var IfcRelAssociatesApproval = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingApproval) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingApproval = RelatingApproval; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingApproval = tape[ptr++]; - return new IfcRelAssociatesApproval(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingApproval); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingApproval); - return args; - } -}; -var IfcRelAssociatesClassification = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingClassification) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingClassification = RelatingClassification; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingClassification = tape[ptr++]; - return new IfcRelAssociatesClassification(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingClassification); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingClassification); - return args; - } -}; -var IfcRelAssociatesConstraint = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, Intent, RelatingConstraint) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.Intent = Intent; - this.RelatingConstraint = RelatingConstraint; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let Intent = tape[ptr++]; - let RelatingConstraint = tape[ptr++]; - return new IfcRelAssociatesConstraint(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, Intent, RelatingConstraint); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.Intent); - args.push(this.RelatingConstraint); - return args; - } -}; -var IfcRelAssociatesDocument = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingDocument) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingDocument = RelatingDocument; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingDocument = tape[ptr++]; - return new IfcRelAssociatesDocument(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingDocument); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingDocument); - return args; - } -}; -var IfcRelAssociatesLibrary = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingLibrary) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingLibrary = RelatingLibrary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingLibrary = tape[ptr++]; - return new IfcRelAssociatesLibrary(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingLibrary); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingLibrary); - return args; - } -}; -var IfcRelAssociatesMaterial = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingMaterial) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingMaterial = RelatingMaterial; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingMaterial = tape[ptr++]; - return new IfcRelAssociatesMaterial(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingMaterial); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingMaterial); - return args; - } -}; -var IfcRelConnects = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcRelConnects(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcRelConnectsElements = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ConnectionGeometry = ConnectionGeometry; - this.RelatingElement = RelatingElement; - this.RelatedElement = RelatedElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ConnectionGeometry = tape[ptr++]; - let RelatingElement = tape[ptr++]; - let RelatedElement = tape[ptr++]; - return new IfcRelConnectsElements(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ConnectionGeometry); - args.push(this.RelatingElement); - args.push(this.RelatedElement); - return args; - } -}; -var IfcRelConnectsPathElements = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RelatingPriorities, RelatedPriorities, RelatedConnectionType, RelatingConnectionType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ConnectionGeometry = ConnectionGeometry; - this.RelatingElement = RelatingElement; - this.RelatedElement = RelatedElement; - this.RelatingPriorities = RelatingPriorities; - this.RelatedPriorities = RelatedPriorities; - this.RelatedConnectionType = RelatedConnectionType; - this.RelatingConnectionType = RelatingConnectionType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ConnectionGeometry = tape[ptr++]; - let RelatingElement = tape[ptr++]; - let RelatedElement = tape[ptr++]; - let RelatingPriorities = tape[ptr++]; - let RelatedPriorities = tape[ptr++]; - let RelatedConnectionType = tape[ptr++]; - let RelatingConnectionType = tape[ptr++]; - return new IfcRelConnectsPathElements(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RelatingPriorities, RelatedPriorities, RelatedConnectionType, RelatingConnectionType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ConnectionGeometry); - args.push(this.RelatingElement); - args.push(this.RelatedElement); - args.push(this.RelatingPriorities); - args.push(this.RelatedPriorities); - args.push(this.RelatedConnectionType); - args.push(this.RelatingConnectionType); - return args; - } -}; -var IfcRelConnectsPortToElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingPort = RelatingPort; - this.RelatedElement = RelatedElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingPort = tape[ptr++]; - let RelatedElement = tape[ptr++]; - return new IfcRelConnectsPortToElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingPort); - args.push(this.RelatedElement); - return args; - } -}; -var IfcRelConnectsPorts = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedPort, RealizingElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingPort = RelatingPort; - this.RelatedPort = RelatedPort; - this.RealizingElement = RealizingElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingPort = tape[ptr++]; - let RelatedPort = tape[ptr++]; - let RealizingElement = tape[ptr++]; - return new IfcRelConnectsPorts(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedPort, RealizingElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingPort); - args.push(this.RelatedPort); - args.push(this.RealizingElement); - return args; - } -}; -var IfcRelConnectsStructuralActivity = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedStructuralActivity) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingElement = RelatingElement; - this.RelatedStructuralActivity = RelatedStructuralActivity; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingElement = tape[ptr++]; - let RelatedStructuralActivity = tape[ptr++]; - return new IfcRelConnectsStructuralActivity(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedStructuralActivity); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingElement); - args.push(this.RelatedStructuralActivity); - return args; - } -}; -var IfcRelConnectsStructuralMember = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingStructuralMember = RelatingStructuralMember; - this.RelatedStructuralConnection = RelatedStructuralConnection; - this.AppliedCondition = AppliedCondition; - this.AdditionalConditions = AdditionalConditions; - this.SupportedLength = SupportedLength; - this.ConditionCoordinateSystem = ConditionCoordinateSystem; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingStructuralMember = tape[ptr++]; - let RelatedStructuralConnection = tape[ptr++]; - let AppliedCondition = tape[ptr++]; - let AdditionalConditions = tape[ptr++]; - let SupportedLength = tape[ptr++]; - let ConditionCoordinateSystem = tape[ptr++]; - return new IfcRelConnectsStructuralMember(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingStructuralMember); - args.push(this.RelatedStructuralConnection); - args.push(this.AppliedCondition); - args.push(this.AdditionalConditions); - args.push(this.SupportedLength); - args.push(this.ConditionCoordinateSystem); - return args; - } -}; -var IfcRelConnectsWithEccentricity = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem, ConnectionConstraint) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingStructuralMember = RelatingStructuralMember; - this.RelatedStructuralConnection = RelatedStructuralConnection; - this.AppliedCondition = AppliedCondition; - this.AdditionalConditions = AdditionalConditions; - this.SupportedLength = SupportedLength; - this.ConditionCoordinateSystem = ConditionCoordinateSystem; - this.ConnectionConstraint = ConnectionConstraint; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingStructuralMember = tape[ptr++]; - let RelatedStructuralConnection = tape[ptr++]; - let AppliedCondition = tape[ptr++]; - let AdditionalConditions = tape[ptr++]; - let SupportedLength = tape[ptr++]; - let ConditionCoordinateSystem = tape[ptr++]; - let ConnectionConstraint = tape[ptr++]; - return new IfcRelConnectsWithEccentricity(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem, ConnectionConstraint); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingStructuralMember); - args.push(this.RelatedStructuralConnection); - args.push(this.AppliedCondition); - args.push(this.AdditionalConditions); - args.push(this.SupportedLength); - args.push(this.ConditionCoordinateSystem); - args.push(this.ConnectionConstraint); - return args; - } -}; -var IfcRelConnectsWithRealizingElements = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RealizingElements, ConnectionType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ConnectionGeometry = ConnectionGeometry; - this.RelatingElement = RelatingElement; - this.RelatedElement = RelatedElement; - this.RealizingElements = RealizingElements; - this.ConnectionType = ConnectionType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ConnectionGeometry = tape[ptr++]; - let RelatingElement = tape[ptr++]; - let RelatedElement = tape[ptr++]; - let RealizingElements = tape[ptr++]; - let ConnectionType = tape[ptr++]; - return new IfcRelConnectsWithRealizingElements(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RealizingElements, ConnectionType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ConnectionGeometry); - args.push(this.RelatingElement); - args.push(this.RelatedElement); - args.push(this.RealizingElements); - args.push(this.ConnectionType); - return args; - } -}; -var IfcRelContainedInSpatialStructure = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedElements = RelatedElements; - this.RelatingStructure = RelatingStructure; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedElements = tape[ptr++]; - let RelatingStructure = tape[ptr++]; - return new IfcRelContainedInSpatialStructure(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedElements); - args.push(this.RelatingStructure); - return args; - } -}; -var IfcRelCoversBldgElements = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedCoverings) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingBuildingElement = RelatingBuildingElement; - this.RelatedCoverings = RelatedCoverings; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingBuildingElement = tape[ptr++]; - let RelatedCoverings = tape[ptr++]; - return new IfcRelCoversBldgElements(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedCoverings); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingBuildingElement); - args.push(this.RelatedCoverings); - return args; - } -}; -var IfcRelCoversSpaces = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedCoverings) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingSpace = RelatingSpace; - this.RelatedCoverings = RelatedCoverings; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingSpace = tape[ptr++]; - let RelatedCoverings = tape[ptr++]; - return new IfcRelCoversSpaces(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedCoverings); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingSpace); - args.push(this.RelatedCoverings); - return args; - } -}; -var IfcRelDeclares = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingContext, RelatedDefinitions) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingContext = RelatingContext; - this.RelatedDefinitions = RelatedDefinitions; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingContext = tape[ptr++]; - let RelatedDefinitions = tape[ptr++]; - return new IfcRelDeclares(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingContext, RelatedDefinitions); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingContext); - args.push(this.RelatedDefinitions); - return args; - } -}; -var IfcRelDecomposes = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcRelDecomposes(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcRelDefines = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcRelDefines(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcRelDefinesByObject = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingObject) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingObject = RelatingObject; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingObject = tape[ptr++]; - return new IfcRelDefinesByObject(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingObject); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingObject); - return args; - } -}; -var IfcRelDefinesByProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingPropertyDefinition) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingPropertyDefinition = RelatingPropertyDefinition; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingPropertyDefinition = tape[ptr++]; - return new IfcRelDefinesByProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingPropertyDefinition); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingPropertyDefinition); - return args; - } -}; -var IfcRelDefinesByTemplate = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedPropertySets, RelatingTemplate) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedPropertySets = RelatedPropertySets; - this.RelatingTemplate = RelatingTemplate; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedPropertySets = tape[ptr++]; - let RelatingTemplate = tape[ptr++]; - return new IfcRelDefinesByTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedPropertySets, RelatingTemplate); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedPropertySets); - args.push(this.RelatingTemplate); - return args; - } -}; -var IfcRelDefinesByType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedObjects = RelatedObjects; - this.RelatingType = RelatingType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - let RelatingType = tape[ptr++]; - return new IfcRelDefinesByType(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedObjects); - args.push(this.RelatingType); - return args; - } -}; -var IfcRelFillsElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingOpeningElement, RelatedBuildingElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingOpeningElement = RelatingOpeningElement; - this.RelatedBuildingElement = RelatedBuildingElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingOpeningElement = tape[ptr++]; - let RelatedBuildingElement = tape[ptr++]; - return new IfcRelFillsElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingOpeningElement, RelatedBuildingElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingOpeningElement); - args.push(this.RelatedBuildingElement); - return args; - } -}; -var IfcRelFlowControlElements = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedControlElements, RelatingFlowElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedControlElements = RelatedControlElements; - this.RelatingFlowElement = RelatingFlowElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedControlElements = tape[ptr++]; - let RelatingFlowElement = tape[ptr++]; - return new IfcRelFlowControlElements(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedControlElements, RelatingFlowElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedControlElements); - args.push(this.RelatingFlowElement); - return args; - } -}; -var IfcRelInterferesElements = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedElement, InterferenceGeometry, InterferenceType, ImpliedOrder) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingElement = RelatingElement; - this.RelatedElement = RelatedElement; - this.InterferenceGeometry = InterferenceGeometry; - this.InterferenceType = InterferenceType; - this.ImpliedOrder = ImpliedOrder; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingElement = tape[ptr++]; - let RelatedElement = tape[ptr++]; - let InterferenceGeometry = tape[ptr++]; - let InterferenceType = tape[ptr++]; - let ImpliedOrder = tape[ptr++]; - return new IfcRelInterferesElements(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedElement, InterferenceGeometry, InterferenceType, ImpliedOrder); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingElement); - args.push(this.RelatedElement); - args.push(this.InterferenceGeometry); - args.push(this.InterferenceType); - args.push(this.ImpliedOrder); - return args; - } -}; -var IfcRelNests = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingObject = RelatingObject; - this.RelatedObjects = RelatedObjects; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingObject = tape[ptr++]; - let RelatedObjects = tape[ptr++]; - return new IfcRelNests(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingObject); - args.push(this.RelatedObjects); - return args; - } -}; -var IfcRelPositions = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPositioningElement, RelatedProducts) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingPositioningElement = RelatingPositioningElement; - this.RelatedProducts = RelatedProducts; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingPositioningElement = tape[ptr++]; - let RelatedProducts = tape[ptr++]; - return new IfcRelPositions(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPositioningElement, RelatedProducts); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingPositioningElement); - args.push(this.RelatedProducts); - return args; - } -}; -var IfcRelProjectsElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedFeatureElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingElement = RelatingElement; - this.RelatedFeatureElement = RelatedFeatureElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingElement = tape[ptr++]; - let RelatedFeatureElement = tape[ptr++]; - return new IfcRelProjectsElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedFeatureElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingElement); - args.push(this.RelatedFeatureElement); - return args; - } -}; -var IfcRelReferencedInSpatialStructure = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatedElements = RelatedElements; - this.RelatingStructure = RelatingStructure; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedElements = tape[ptr++]; - let RelatingStructure = tape[ptr++]; - return new IfcRelReferencedInSpatialStructure(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedElements); - args.push(this.RelatingStructure); - return args; - } -}; -var IfcRelSequence = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingProcess, RelatedProcess, TimeLag, SequenceType, UserDefinedSequenceType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingProcess = RelatingProcess; - this.RelatedProcess = RelatedProcess; - this.TimeLag = TimeLag; - this.SequenceType = SequenceType; - this.UserDefinedSequenceType = UserDefinedSequenceType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingProcess = tape[ptr++]; - let RelatedProcess = tape[ptr++]; - let TimeLag = tape[ptr++]; - let SequenceType = tape[ptr++]; - let UserDefinedSequenceType = tape[ptr++]; - return new IfcRelSequence(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingProcess, RelatedProcess, TimeLag, SequenceType, UserDefinedSequenceType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingProcess); - args.push(this.RelatedProcess); - args.push(this.TimeLag); - args.push(this.SequenceType); - args.push(this.UserDefinedSequenceType); - return args; - } -}; -var IfcRelServicesBuildings = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSystem, RelatedBuildings) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingSystem = RelatingSystem; - this.RelatedBuildings = RelatedBuildings; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingSystem = tape[ptr++]; - let RelatedBuildings = tape[ptr++]; - return new IfcRelServicesBuildings(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSystem, RelatedBuildings); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingSystem); - args.push(this.RelatedBuildings); - return args; - } -}; -var IfcRelSpaceBoundary = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingSpace = RelatingSpace; - this.RelatedBuildingElement = RelatedBuildingElement; - this.ConnectionGeometry = ConnectionGeometry; - this.PhysicalOrVirtualBoundary = PhysicalOrVirtualBoundary; - this.InternalOrExternalBoundary = InternalOrExternalBoundary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingSpace = tape[ptr++]; - let RelatedBuildingElement = tape[ptr++]; - let ConnectionGeometry = tape[ptr++]; - let PhysicalOrVirtualBoundary = tape[ptr++]; - let InternalOrExternalBoundary = tape[ptr++]; - return new IfcRelSpaceBoundary(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingSpace); - args.push(this.RelatedBuildingElement); - args.push(this.ConnectionGeometry); - args.push(this.PhysicalOrVirtualBoundary); - args.push(this.InternalOrExternalBoundary); - return args; - } -}; -var IfcRelSpaceBoundary1stLevel = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingSpace = RelatingSpace; - this.RelatedBuildingElement = RelatedBuildingElement; - this.ConnectionGeometry = ConnectionGeometry; - this.PhysicalOrVirtualBoundary = PhysicalOrVirtualBoundary; - this.InternalOrExternalBoundary = InternalOrExternalBoundary; - this.ParentBoundary = ParentBoundary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingSpace = tape[ptr++]; - let RelatedBuildingElement = tape[ptr++]; - let ConnectionGeometry = tape[ptr++]; - let PhysicalOrVirtualBoundary = tape[ptr++]; - let InternalOrExternalBoundary = tape[ptr++]; - let ParentBoundary = tape[ptr++]; - return new IfcRelSpaceBoundary1stLevel(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingSpace); - args.push(this.RelatedBuildingElement); - args.push(this.ConnectionGeometry); - args.push(this.PhysicalOrVirtualBoundary); - args.push(this.InternalOrExternalBoundary); - args.push(this.ParentBoundary); - return args; - } -}; -var IfcRelSpaceBoundary2ndLevel = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary, CorrespondingBoundary) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingSpace = RelatingSpace; - this.RelatedBuildingElement = RelatedBuildingElement; - this.ConnectionGeometry = ConnectionGeometry; - this.PhysicalOrVirtualBoundary = PhysicalOrVirtualBoundary; - this.InternalOrExternalBoundary = InternalOrExternalBoundary; - this.ParentBoundary = ParentBoundary; - this.CorrespondingBoundary = CorrespondingBoundary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingSpace = tape[ptr++]; - let RelatedBuildingElement = tape[ptr++]; - let ConnectionGeometry = tape[ptr++]; - let PhysicalOrVirtualBoundary = tape[ptr++]; - let InternalOrExternalBoundary = tape[ptr++]; - let ParentBoundary = tape[ptr++]; - let CorrespondingBoundary = tape[ptr++]; - return new IfcRelSpaceBoundary2ndLevel(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary, CorrespondingBoundary); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingSpace); - args.push(this.RelatedBuildingElement); - args.push(this.ConnectionGeometry); - args.push(this.PhysicalOrVirtualBoundary); - args.push(this.InternalOrExternalBoundary); - args.push(this.ParentBoundary); - args.push(this.CorrespondingBoundary); - return args; - } -}; -var IfcRelVoidsElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedOpeningElement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.RelatingBuildingElement = RelatingBuildingElement; - this.RelatedOpeningElement = RelatedOpeningElement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingBuildingElement = tape[ptr++]; - let RelatedOpeningElement = tape[ptr++]; - return new IfcRelVoidsElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedOpeningElement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingBuildingElement); - args.push(this.RelatedOpeningElement); - return args; - } -}; -var IfcRelationship = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcRelationship(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcReparametrisedCompositeCurveSegment = class { - constructor(expressID, type, Transition, SameSense, ParentCurve, ParamLength) { - this.expressID = expressID; - this.type = type; - this.Transition = Transition; - this.SameSense = SameSense; - this.ParentCurve = ParentCurve; - this.ParamLength = ParamLength; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Transition = tape[ptr++]; - let SameSense = tape[ptr++]; - let ParentCurve = tape[ptr++]; - let ParamLength = tape[ptr++]; - return new IfcReparametrisedCompositeCurveSegment(expressID, type, Transition, SameSense, ParentCurve, ParamLength); - } - ToTape() { - let args = []; - args.push(this.Transition); - args.push(this.SameSense); - args.push(this.ParentCurve); - args.push(this.ParamLength); - return args; - } -}; -var IfcRepresentation = class { - constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { - this.expressID = expressID; - this.type = type; - this.ContextOfItems = ContextOfItems; - this.RepresentationIdentifier = RepresentationIdentifier; - this.RepresentationType = RepresentationType; - this.Items = Items; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextOfItems = tape[ptr++]; - let RepresentationIdentifier = tape[ptr++]; - let RepresentationType = tape[ptr++]; - let Items = tape[ptr++]; - return new IfcRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); - } - ToTape() { - let args = []; - args.push(this.ContextOfItems); - args.push(this.RepresentationIdentifier); - args.push(this.RepresentationType); - args.push(this.Items); - return args; - } -}; -var IfcRepresentationContext = class { - constructor(expressID, type, ContextIdentifier, ContextType) { - this.expressID = expressID; - this.type = type; - this.ContextIdentifier = ContextIdentifier; - this.ContextType = ContextType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextIdentifier = tape[ptr++]; - let ContextType = tape[ptr++]; - return new IfcRepresentationContext(expressID, type, ContextIdentifier, ContextType); - } - ToTape() { - let args = []; - args.push(this.ContextIdentifier); - args.push(this.ContextType); - return args; - } -}; -var IfcRepresentationItem = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcRepresentationItem(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcRepresentationMap = class { - constructor(expressID, type, MappingOrigin, MappedRepresentation) { - this.expressID = expressID; - this.type = type; - this.MappingOrigin = MappingOrigin; - this.MappedRepresentation = MappedRepresentation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let MappingOrigin = tape[ptr++]; - let MappedRepresentation = tape[ptr++]; - return new IfcRepresentationMap(expressID, type, MappingOrigin, MappedRepresentation); - } - ToTape() { - let args = []; - args.push(this.MappingOrigin); - args.push(this.MappedRepresentation); - return args; - } -}; -var IfcResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - return new IfcResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - return args; - } -}; -var IfcResourceApprovalRelationship = class { - constructor(expressID, type, Name, Description, RelatedResourceObjects, RelatingApproval) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatedResourceObjects = RelatedResourceObjects; - this.RelatingApproval = RelatingApproval; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatedResourceObjects = tape[ptr++]; - let RelatingApproval = tape[ptr++]; - return new IfcResourceApprovalRelationship(expressID, type, Name, Description, RelatedResourceObjects, RelatingApproval); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatedResourceObjects); - args.push(this.RelatingApproval); - return args; - } -}; -var IfcResourceConstraintRelationship = class { - constructor(expressID, type, Name, Description, RelatingConstraint, RelatedResourceObjects) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.RelatingConstraint = RelatingConstraint; - this.RelatedResourceObjects = RelatedResourceObjects; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let RelatingConstraint = tape[ptr++]; - let RelatedResourceObjects = tape[ptr++]; - return new IfcResourceConstraintRelationship(expressID, type, Name, Description, RelatingConstraint, RelatedResourceObjects); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.RelatingConstraint); - args.push(this.RelatedResourceObjects); - return args; - } -}; -var IfcResourceLevelRelationship = class { - constructor(expressID, type, Name, Description) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcResourceLevelRelationship(expressID, type, Name, Description); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcResourceTime = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ScheduleWork, ScheduleUsage, ScheduleStart, ScheduleFinish, ScheduleContour, LevelingDelay, IsOverAllocated, StatusTime, ActualWork, ActualUsage, ActualStart, ActualFinish, RemainingWork, RemainingUsage, Completion) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.ScheduleWork = ScheduleWork; - this.ScheduleUsage = ScheduleUsage; - this.ScheduleStart = ScheduleStart; - this.ScheduleFinish = ScheduleFinish; - this.ScheduleContour = ScheduleContour; - this.LevelingDelay = LevelingDelay; - this.IsOverAllocated = IsOverAllocated; - this.StatusTime = StatusTime; - this.ActualWork = ActualWork; - this.ActualUsage = ActualUsage; - this.ActualStart = ActualStart; - this.ActualFinish = ActualFinish; - this.RemainingWork = RemainingWork; - this.RemainingUsage = RemainingUsage; - this.Completion = Completion; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let ScheduleWork = tape[ptr++]; - let ScheduleUsage = tape[ptr++]; - let ScheduleStart = tape[ptr++]; - let ScheduleFinish = tape[ptr++]; - let ScheduleContour = tape[ptr++]; - let LevelingDelay = tape[ptr++]; - let IsOverAllocated = tape[ptr++]; - let StatusTime = tape[ptr++]; - let ActualWork = tape[ptr++]; - let ActualUsage = tape[ptr++]; - let ActualStart = tape[ptr++]; - let ActualFinish = tape[ptr++]; - let RemainingWork = tape[ptr++]; - let RemainingUsage = tape[ptr++]; - let Completion = tape[ptr++]; - return new IfcResourceTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ScheduleWork, ScheduleUsage, ScheduleStart, ScheduleFinish, ScheduleContour, LevelingDelay, IsOverAllocated, StatusTime, ActualWork, ActualUsage, ActualStart, ActualFinish, RemainingWork, RemainingUsage, Completion); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.ScheduleWork); - args.push(this.ScheduleUsage); - args.push(this.ScheduleStart); - args.push(this.ScheduleFinish); - args.push(this.ScheduleContour); - args.push(this.LevelingDelay); - args.push(this.IsOverAllocated); - args.push(this.StatusTime); - args.push(this.ActualWork); - args.push(this.ActualUsage); - args.push(this.ActualStart); - args.push(this.ActualFinish); - args.push(this.RemainingWork); - args.push(this.RemainingUsage); - args.push(this.Completion); - return args; - } -}; -var IfcRevolvedAreaSolid = class { - constructor(expressID, type, SweptArea, Position, Axis, Angle) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - this.Axis = Axis; - this.Angle = Angle; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - let Axis = tape[ptr++]; - let Angle = tape[ptr++]; - return new IfcRevolvedAreaSolid(expressID, type, SweptArea, Position, Axis, Angle); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - args.push(this.Axis); - args.push(this.Angle); - return args; - } -}; -var IfcRevolvedAreaSolidTapered = class { - constructor(expressID, type, SweptArea, Position, Axis, Angle, EndSweptArea) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - this.Axis = Axis; - this.Angle = Angle; - this.EndSweptArea = EndSweptArea; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - let Axis = tape[ptr++]; - let Angle = tape[ptr++]; - let EndSweptArea = tape[ptr++]; - return new IfcRevolvedAreaSolidTapered(expressID, type, SweptArea, Position, Axis, Angle, EndSweptArea); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - args.push(this.Axis); - args.push(this.Angle); - args.push(this.EndSweptArea); - return args; - } -}; -var IfcRightCircularCone = class { - constructor(expressID, type, Position, Height, BottomRadius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.Height = Height; - this.BottomRadius = BottomRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let Height = tape[ptr++]; - let BottomRadius = tape[ptr++]; - return new IfcRightCircularCone(expressID, type, Position, Height, BottomRadius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.Height); - args.push(this.BottomRadius); - return args; - } -}; -var IfcRightCircularCylinder = class { - constructor(expressID, type, Position, Height, Radius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.Height = Height; - this.Radius = Radius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let Height = tape[ptr++]; - let Radius = tape[ptr++]; - return new IfcRightCircularCylinder(expressID, type, Position, Height, Radius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.Height); - args.push(this.Radius); - return args; - } -}; -var IfcRoof = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRoof(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRoofType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcRoofType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcRoot = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcRoot(expressID, type, GlobalId, OwnerHistory, Name, Description); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcRoundedRectangleProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, RoundingRadius) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.XDim = XDim; - this.YDim = YDim; - this.RoundingRadius = RoundingRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let XDim = tape[ptr++]; - let YDim = tape[ptr++]; - let RoundingRadius = tape[ptr++]; - return new IfcRoundedRectangleProfileDef(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, RoundingRadius); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.XDim); - args.push(this.YDim); - args.push(this.RoundingRadius); - return args; - } -}; -var IfcSIUnit = class { - constructor(expressID, type, Dimensions, UnitType, Prefix, Name) { - this.expressID = expressID; - this.type = type; - this.Dimensions = Dimensions; - this.UnitType = UnitType; - this.Prefix = Prefix; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Dimensions = tape[ptr++]; - let UnitType = tape[ptr++]; - let Prefix = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcSIUnit(expressID, type, Dimensions, UnitType, Prefix, Name); - } - ToTape() { - let args = []; - args.push(this.Dimensions); - args.push(this.UnitType); - args.push(this.Prefix); - args.push(this.Name); - return args; - } -}; -var IfcSanitaryTerminal = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSanitaryTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSanitaryTerminalType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSanitaryTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSchedulingTime = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - return new IfcSchedulingTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - return args; - } -}; -var IfcSeamCurve = class { - constructor(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation) { - this.expressID = expressID; - this.type = type; - this.Curve3D = Curve3D; - this.AssociatedGeometry = AssociatedGeometry; - this.MasterRepresentation = MasterRepresentation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Curve3D = tape[ptr++]; - let AssociatedGeometry = tape[ptr++]; - let MasterRepresentation = tape[ptr++]; - return new IfcSeamCurve(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation); - } - ToTape() { - let args = []; - args.push(this.Curve3D); - args.push(this.AssociatedGeometry); - args.push(this.MasterRepresentation); - return args; - } -}; -var IfcSectionProperties = class { - constructor(expressID, type, SectionType, StartProfile, EndProfile) { - this.expressID = expressID; - this.type = type; - this.SectionType = SectionType; - this.StartProfile = StartProfile; - this.EndProfile = EndProfile; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SectionType = tape[ptr++]; - let StartProfile = tape[ptr++]; - let EndProfile = tape[ptr++]; - return new IfcSectionProperties(expressID, type, SectionType, StartProfile, EndProfile); - } - ToTape() { - let args = []; - args.push(this.SectionType); - args.push(this.StartProfile); - args.push(this.EndProfile); - return args; - } -}; -var IfcSectionReinforcementProperties = class { - constructor(expressID, type, LongitudinalStartPosition, LongitudinalEndPosition, TransversePosition, ReinforcementRole, SectionDefinition, CrossSectionReinforcementDefinitions) { - this.expressID = expressID; - this.type = type; - this.LongitudinalStartPosition = LongitudinalStartPosition; - this.LongitudinalEndPosition = LongitudinalEndPosition; - this.TransversePosition = TransversePosition; - this.ReinforcementRole = ReinforcementRole; - this.SectionDefinition = SectionDefinition; - this.CrossSectionReinforcementDefinitions = CrossSectionReinforcementDefinitions; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let LongitudinalStartPosition = tape[ptr++]; - let LongitudinalEndPosition = tape[ptr++]; - let TransversePosition = tape[ptr++]; - let ReinforcementRole = tape[ptr++]; - let SectionDefinition = tape[ptr++]; - let CrossSectionReinforcementDefinitions = tape[ptr++]; - return new IfcSectionReinforcementProperties(expressID, type, LongitudinalStartPosition, LongitudinalEndPosition, TransversePosition, ReinforcementRole, SectionDefinition, CrossSectionReinforcementDefinitions); - } - ToTape() { - let args = []; - args.push(this.LongitudinalStartPosition); - args.push(this.LongitudinalEndPosition); - args.push(this.TransversePosition); - args.push(this.ReinforcementRole); - args.push(this.SectionDefinition); - args.push(this.CrossSectionReinforcementDefinitions); - return args; - } -}; -var IfcSectionedSolid = class { - constructor(expressID, type, Directrix, CrossSections) { - this.expressID = expressID; - this.type = type; - this.Directrix = Directrix; - this.CrossSections = CrossSections; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Directrix = tape[ptr++]; - let CrossSections = tape[ptr++]; - return new IfcSectionedSolid(expressID, type, Directrix, CrossSections); - } - ToTape() { - let args = []; - args.push(this.Directrix); - args.push(this.CrossSections); - return args; - } -}; -var IfcSectionedSolidHorizontal = class { - constructor(expressID, type, Directrix, CrossSections, CrossSectionPositions, FixedAxisVertical) { - this.expressID = expressID; - this.type = type; - this.Directrix = Directrix; - this.CrossSections = CrossSections; - this.CrossSectionPositions = CrossSectionPositions; - this.FixedAxisVertical = FixedAxisVertical; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Directrix = tape[ptr++]; - let CrossSections = tape[ptr++]; - let CrossSectionPositions = tape[ptr++]; - let FixedAxisVertical = tape[ptr++]; - return new IfcSectionedSolidHorizontal(expressID, type, Directrix, CrossSections, CrossSectionPositions, FixedAxisVertical); - } - ToTape() { - let args = []; - args.push(this.Directrix); - args.push(this.CrossSections); - args.push(this.CrossSectionPositions); - args.push(this.FixedAxisVertical); - return args; - } -}; -var IfcSectionedSpine = class { - constructor(expressID, type, SpineCurve, CrossSections, CrossSectionPositions) { - this.expressID = expressID; - this.type = type; - this.SpineCurve = SpineCurve; - this.CrossSections = CrossSections; - this.CrossSectionPositions = CrossSectionPositions; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SpineCurve = tape[ptr++]; - let CrossSections = tape[ptr++]; - let CrossSectionPositions = tape[ptr++]; - return new IfcSectionedSpine(expressID, type, SpineCurve, CrossSections, CrossSectionPositions); - } - ToTape() { - let args = []; - args.push(this.SpineCurve); - args.push(this.CrossSections); - args.push(this.CrossSectionPositions); - return args; - } -}; -var IfcSensor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSensor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSensorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSensorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcShadingDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcShadingDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcShadingDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcShadingDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcShapeAspect = class { - constructor(expressID, type, ShapeRepresentations, Name, Description, ProductDefinitional, PartOfProductDefinitionShape) { - this.expressID = expressID; - this.type = type; - this.ShapeRepresentations = ShapeRepresentations; - this.Name = Name; - this.Description = Description; - this.ProductDefinitional = ProductDefinitional; - this.PartOfProductDefinitionShape = PartOfProductDefinitionShape; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ShapeRepresentations = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ProductDefinitional = tape[ptr++]; - let PartOfProductDefinitionShape = tape[ptr++]; - return new IfcShapeAspect(expressID, type, ShapeRepresentations, Name, Description, ProductDefinitional, PartOfProductDefinitionShape); - } - ToTape() { - let args = []; - args.push(this.ShapeRepresentations); - args.push(this.Name); - args.push(this.Description); - args.push(this.ProductDefinitional); - args.push(this.PartOfProductDefinitionShape); - return args; - } -}; -var IfcShapeModel = class { - constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { - this.expressID = expressID; - this.type = type; - this.ContextOfItems = ContextOfItems; - this.RepresentationIdentifier = RepresentationIdentifier; - this.RepresentationType = RepresentationType; - this.Items = Items; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextOfItems = tape[ptr++]; - let RepresentationIdentifier = tape[ptr++]; - let RepresentationType = tape[ptr++]; - let Items = tape[ptr++]; - return new IfcShapeModel(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); - } - ToTape() { - let args = []; - args.push(this.ContextOfItems); - args.push(this.RepresentationIdentifier); - args.push(this.RepresentationType); - args.push(this.Items); - return args; - } -}; -var IfcShapeRepresentation = class { - constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { - this.expressID = expressID; - this.type = type; - this.ContextOfItems = ContextOfItems; - this.RepresentationIdentifier = RepresentationIdentifier; - this.RepresentationType = RepresentationType; - this.Items = Items; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextOfItems = tape[ptr++]; - let RepresentationIdentifier = tape[ptr++]; - let RepresentationType = tape[ptr++]; - let Items = tape[ptr++]; - return new IfcShapeRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); - } - ToTape() { - let args = []; - args.push(this.ContextOfItems); - args.push(this.RepresentationIdentifier); - args.push(this.RepresentationType); - args.push(this.Items); - return args; - } -}; -var IfcShellBasedSurfaceModel = class { - constructor(expressID, type, SbsmBoundary) { - this.expressID = expressID; - this.type = type; - this.SbsmBoundary = SbsmBoundary; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SbsmBoundary = tape[ptr++]; - return new IfcShellBasedSurfaceModel(expressID, type, SbsmBoundary); - } - ToTape() { - let args = []; - args.push(this.SbsmBoundary); - return args; - } -}; -var IfcSimpleProperty = class { - constructor(expressID, type, Name, Description) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - return new IfcSimpleProperty(expressID, type, Name, Description); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - return args; - } -}; -var IfcSimplePropertyTemplate = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, PrimaryMeasureType, SecondaryMeasureType, Enumerators, PrimaryUnit, SecondaryUnit, Expression, AccessState) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.TemplateType = TemplateType; - this.PrimaryMeasureType = PrimaryMeasureType; - this.SecondaryMeasureType = SecondaryMeasureType; - this.Enumerators = Enumerators; - this.PrimaryUnit = PrimaryUnit; - this.SecondaryUnit = SecondaryUnit; - this.Expression = Expression; - this.AccessState = AccessState; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let TemplateType = tape[ptr++]; - let PrimaryMeasureType = tape[ptr++]; - let SecondaryMeasureType = tape[ptr++]; - let Enumerators = tape[ptr++]; - let PrimaryUnit = tape[ptr++]; - let SecondaryUnit = tape[ptr++]; - let Expression = tape[ptr++]; - let AccessState = tape[ptr++]; - return new IfcSimplePropertyTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, PrimaryMeasureType, SecondaryMeasureType, Enumerators, PrimaryUnit, SecondaryUnit, Expression, AccessState); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.TemplateType); - args.push(this.PrimaryMeasureType); - args.push(this.SecondaryMeasureType); - args.push(this.Enumerators); - args.push(this.PrimaryUnit); - args.push(this.SecondaryUnit); - args.push(this.Expression); - args.push(this.AccessState); - return args; - } -}; -var IfcSite = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, RefLatitude, RefLongitude, RefElevation, LandTitleNumber, SiteAddress) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - this.RefLatitude = RefLatitude; - this.RefLongitude = RefLongitude; - this.RefElevation = RefElevation; - this.LandTitleNumber = LandTitleNumber; - this.SiteAddress = SiteAddress; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - let RefLatitude = tape[ptr++]; - let RefLongitude = tape[ptr++]; - let RefElevation = tape[ptr++]; - let LandTitleNumber = tape[ptr++]; - let SiteAddress = tape[ptr++]; - return new IfcSite(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, RefLatitude, RefLongitude, RefElevation, LandTitleNumber, SiteAddress); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - args.push(this.RefLatitude); - args.push(this.RefLongitude); - args.push(this.RefElevation); - args.push(this.LandTitleNumber); - args.push(this.SiteAddress); - return args; - } -}; -var IfcSlab = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSlab(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSlabElementedCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSlabElementedCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSlabStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSlabStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSlabType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSlabType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSlippageConnectionCondition = class { - constructor(expressID, type, Name, SlippageX, SlippageY, SlippageZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.SlippageX = SlippageX; - this.SlippageY = SlippageY; - this.SlippageZ = SlippageZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let SlippageX = tape[ptr++]; - let SlippageY = tape[ptr++]; - let SlippageZ = tape[ptr++]; - return new IfcSlippageConnectionCondition(expressID, type, Name, SlippageX, SlippageY, SlippageZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.SlippageX); - args.push(this.SlippageY); - args.push(this.SlippageZ); - return args; - } -}; -var IfcSolarDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSolarDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSolarDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSolarDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSolidModel = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcSolidModel(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcSpace = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType, ElevationWithFlooring) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - this.PredefinedType = PredefinedType; - this.ElevationWithFlooring = ElevationWithFlooring; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let ElevationWithFlooring = tape[ptr++]; - return new IfcSpace(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType, ElevationWithFlooring); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - args.push(this.PredefinedType); - args.push(this.ElevationWithFlooring); - return args; - } -}; -var IfcSpaceHeater = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSpaceHeater(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSpaceHeaterType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSpaceHeaterType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSpaceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.LongName = LongName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let LongName = tape[ptr++]; - return new IfcSpaceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.LongName); - return args; - } -}; -var IfcSpatialElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - return new IfcSpatialElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - return args; - } -}; -var IfcSpatialElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcSpatialElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcSpatialStructureElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.CompositionType = CompositionType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let CompositionType = tape[ptr++]; - return new IfcSpatialStructureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.CompositionType); - return args; - } -}; -var IfcSpatialStructureElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - return new IfcSpatialStructureElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - return args; - } -}; -var IfcSpatialZone = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.LongName = LongName; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let LongName = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSpatialZone(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.LongName); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSpatialZoneType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.LongName = LongName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let LongName = tape[ptr++]; - return new IfcSpatialZoneType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.LongName); - return args; - } -}; -var IfcSphere = class { - constructor(expressID, type, Position, Radius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.Radius = Radius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - return new IfcSphere(expressID, type, Position, Radius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.Radius); - return args; - } -}; -var IfcSphericalSurface = class { - constructor(expressID, type, Position, Radius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.Radius = Radius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let Radius = tape[ptr++]; - return new IfcSphericalSurface(expressID, type, Position, Radius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.Radius); - return args; - } -}; -var IfcStackTerminal = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStackTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStackTerminalType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStackTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStair = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStair(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStairFlight = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NumberOfRisers, NumberOfTreads, RiserHeight, TreadLength, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.NumberOfRisers = NumberOfRisers; - this.NumberOfTreads = NumberOfTreads; - this.RiserHeight = RiserHeight; - this.TreadLength = TreadLength; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let NumberOfRisers = tape[ptr++]; - let NumberOfTreads = tape[ptr++]; - let RiserHeight = tape[ptr++]; - let TreadLength = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStairFlight(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NumberOfRisers, NumberOfTreads, RiserHeight, TreadLength, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.NumberOfRisers); - args.push(this.NumberOfTreads); - args.push(this.RiserHeight); - args.push(this.TreadLength); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStairFlightType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStairFlightType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStairType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStairType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStructuralAction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.DestabilizingLoad = DestabilizingLoad; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let DestabilizingLoad = tape[ptr++]; - return new IfcStructuralAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.DestabilizingLoad); - return args; - } -}; -var IfcStructuralActivity = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - return new IfcStructuralActivity(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - return args; - } -}; -var IfcStructuralAnalysisModel = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, OrientationOf2DPlane, LoadedBy, HasResults, SharedPlacement) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.PredefinedType = PredefinedType; - this.OrientationOf2DPlane = OrientationOf2DPlane; - this.LoadedBy = LoadedBy; - this.HasResults = HasResults; - this.SharedPlacement = SharedPlacement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let OrientationOf2DPlane = tape[ptr++]; - let LoadedBy = tape[ptr++]; - let HasResults = tape[ptr++]; - let SharedPlacement = tape[ptr++]; - return new IfcStructuralAnalysisModel(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, OrientationOf2DPlane, LoadedBy, HasResults, SharedPlacement); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.PredefinedType); - args.push(this.OrientationOf2DPlane); - args.push(this.LoadedBy); - args.push(this.HasResults); - args.push(this.SharedPlacement); - return args; - } -}; -var IfcStructuralConnection = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedCondition = AppliedCondition; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedCondition = tape[ptr++]; - return new IfcStructuralConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedCondition); - return args; - } -}; -var IfcStructuralConnectionCondition = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcStructuralConnectionCondition(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcStructuralCurveAction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.DestabilizingLoad = DestabilizingLoad; - this.ProjectedOrTrue = ProjectedOrTrue; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let DestabilizingLoad = tape[ptr++]; - let ProjectedOrTrue = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStructuralCurveAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.DestabilizingLoad); - args.push(this.ProjectedOrTrue); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStructuralCurveConnection = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, Axis) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedCondition = AppliedCondition; - this.Axis = Axis; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedCondition = tape[ptr++]; - let Axis = tape[ptr++]; - return new IfcStructuralCurveConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, Axis); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedCondition); - args.push(this.Axis); - return args; - } -}; -var IfcStructuralCurveMember = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.PredefinedType = PredefinedType; - this.Axis = Axis; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Axis = tape[ptr++]; - return new IfcStructuralCurveMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.PredefinedType); - args.push(this.Axis); - return args; - } -}; -var IfcStructuralCurveMemberVarying = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.PredefinedType = PredefinedType; - this.Axis = Axis; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Axis = tape[ptr++]; - return new IfcStructuralCurveMemberVarying(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.PredefinedType); - args.push(this.Axis); - return args; - } -}; -var IfcStructuralCurveReaction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStructuralCurveReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStructuralItem = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - return new IfcStructuralItem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - return args; - } -}; -var IfcStructuralLinearAction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.DestabilizingLoad = DestabilizingLoad; - this.ProjectedOrTrue = ProjectedOrTrue; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let DestabilizingLoad = tape[ptr++]; - let ProjectedOrTrue = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStructuralLinearAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.DestabilizingLoad); - args.push(this.ProjectedOrTrue); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStructuralLoad = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcStructuralLoad(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcStructuralLoadCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose, SelfWeightCoefficients) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.PredefinedType = PredefinedType; - this.ActionType = ActionType; - this.ActionSource = ActionSource; - this.Coefficient = Coefficient; - this.Purpose = Purpose; - this.SelfWeightCoefficients = SelfWeightCoefficients; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let ActionType = tape[ptr++]; - let ActionSource = tape[ptr++]; - let Coefficient = tape[ptr++]; - let Purpose = tape[ptr++]; - let SelfWeightCoefficients = tape[ptr++]; - return new IfcStructuralLoadCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose, SelfWeightCoefficients); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.PredefinedType); - args.push(this.ActionType); - args.push(this.ActionSource); - args.push(this.Coefficient); - args.push(this.Purpose); - args.push(this.SelfWeightCoefficients); - return args; - } -}; -var IfcStructuralLoadConfiguration = class { - constructor(expressID, type, Name, Values, Locations) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Values = Values; - this.Locations = Locations; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Values = tape[ptr++]; - let Locations = tape[ptr++]; - return new IfcStructuralLoadConfiguration(expressID, type, Name, Values, Locations); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Values); - args.push(this.Locations); - return args; - } -}; -var IfcStructuralLoadGroup = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.PredefinedType = PredefinedType; - this.ActionType = ActionType; - this.ActionSource = ActionSource; - this.Coefficient = Coefficient; - this.Purpose = Purpose; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let ActionType = tape[ptr++]; - let ActionSource = tape[ptr++]; - let Coefficient = tape[ptr++]; - let Purpose = tape[ptr++]; - return new IfcStructuralLoadGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.PredefinedType); - args.push(this.ActionType); - args.push(this.ActionSource); - args.push(this.Coefficient); - args.push(this.Purpose); - return args; - } -}; -var IfcStructuralLoadLinearForce = class { - constructor(expressID, type, Name, LinearForceX, LinearForceY, LinearForceZ, LinearMomentX, LinearMomentY, LinearMomentZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.LinearForceX = LinearForceX; - this.LinearForceY = LinearForceY; - this.LinearForceZ = LinearForceZ; - this.LinearMomentX = LinearMomentX; - this.LinearMomentY = LinearMomentY; - this.LinearMomentZ = LinearMomentZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let LinearForceX = tape[ptr++]; - let LinearForceY = tape[ptr++]; - let LinearForceZ = tape[ptr++]; - let LinearMomentX = tape[ptr++]; - let LinearMomentY = tape[ptr++]; - let LinearMomentZ = tape[ptr++]; - return new IfcStructuralLoadLinearForce(expressID, type, Name, LinearForceX, LinearForceY, LinearForceZ, LinearMomentX, LinearMomentY, LinearMomentZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.LinearForceX); - args.push(this.LinearForceY); - args.push(this.LinearForceZ); - args.push(this.LinearMomentX); - args.push(this.LinearMomentY); - args.push(this.LinearMomentZ); - return args; - } -}; -var IfcStructuralLoadOrResult = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcStructuralLoadOrResult(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcStructuralLoadPlanarForce = class { - constructor(expressID, type, Name, PlanarForceX, PlanarForceY, PlanarForceZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.PlanarForceX = PlanarForceX; - this.PlanarForceY = PlanarForceY; - this.PlanarForceZ = PlanarForceZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let PlanarForceX = tape[ptr++]; - let PlanarForceY = tape[ptr++]; - let PlanarForceZ = tape[ptr++]; - return new IfcStructuralLoadPlanarForce(expressID, type, Name, PlanarForceX, PlanarForceY, PlanarForceZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.PlanarForceX); - args.push(this.PlanarForceY); - args.push(this.PlanarForceZ); - return args; - } -}; -var IfcStructuralLoadSingleDisplacement = class { - constructor(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DisplacementX = DisplacementX; - this.DisplacementY = DisplacementY; - this.DisplacementZ = DisplacementZ; - this.RotationalDisplacementRX = RotationalDisplacementRX; - this.RotationalDisplacementRY = RotationalDisplacementRY; - this.RotationalDisplacementRZ = RotationalDisplacementRZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DisplacementX = tape[ptr++]; - let DisplacementY = tape[ptr++]; - let DisplacementZ = tape[ptr++]; - let RotationalDisplacementRX = tape[ptr++]; - let RotationalDisplacementRY = tape[ptr++]; - let RotationalDisplacementRZ = tape[ptr++]; - return new IfcStructuralLoadSingleDisplacement(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DisplacementX); - args.push(this.DisplacementY); - args.push(this.DisplacementZ); - args.push(this.RotationalDisplacementRX); - args.push(this.RotationalDisplacementRY); - args.push(this.RotationalDisplacementRZ); - return args; - } -}; -var IfcStructuralLoadSingleDisplacementDistortion = class { - constructor(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ, Distortion) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DisplacementX = DisplacementX; - this.DisplacementY = DisplacementY; - this.DisplacementZ = DisplacementZ; - this.RotationalDisplacementRX = RotationalDisplacementRX; - this.RotationalDisplacementRY = RotationalDisplacementRY; - this.RotationalDisplacementRZ = RotationalDisplacementRZ; - this.Distortion = Distortion; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DisplacementX = tape[ptr++]; - let DisplacementY = tape[ptr++]; - let DisplacementZ = tape[ptr++]; - let RotationalDisplacementRX = tape[ptr++]; - let RotationalDisplacementRY = tape[ptr++]; - let RotationalDisplacementRZ = tape[ptr++]; - let Distortion = tape[ptr++]; - return new IfcStructuralLoadSingleDisplacementDistortion(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ, Distortion); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DisplacementX); - args.push(this.DisplacementY); - args.push(this.DisplacementZ); - args.push(this.RotationalDisplacementRX); - args.push(this.RotationalDisplacementRY); - args.push(this.RotationalDisplacementRZ); - args.push(this.Distortion); - return args; - } -}; -var IfcStructuralLoadSingleForce = class { - constructor(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.ForceX = ForceX; - this.ForceY = ForceY; - this.ForceZ = ForceZ; - this.MomentX = MomentX; - this.MomentY = MomentY; - this.MomentZ = MomentZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let ForceX = tape[ptr++]; - let ForceY = tape[ptr++]; - let ForceZ = tape[ptr++]; - let MomentX = tape[ptr++]; - let MomentY = tape[ptr++]; - let MomentZ = tape[ptr++]; - return new IfcStructuralLoadSingleForce(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.ForceX); - args.push(this.ForceY); - args.push(this.ForceZ); - args.push(this.MomentX); - args.push(this.MomentY); - args.push(this.MomentZ); - return args; - } -}; -var IfcStructuralLoadSingleForceWarping = class { - constructor(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ, WarpingMoment) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.ForceX = ForceX; - this.ForceY = ForceY; - this.ForceZ = ForceZ; - this.MomentX = MomentX; - this.MomentY = MomentY; - this.MomentZ = MomentZ; - this.WarpingMoment = WarpingMoment; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let ForceX = tape[ptr++]; - let ForceY = tape[ptr++]; - let ForceZ = tape[ptr++]; - let MomentX = tape[ptr++]; - let MomentY = tape[ptr++]; - let MomentZ = tape[ptr++]; - let WarpingMoment = tape[ptr++]; - return new IfcStructuralLoadSingleForceWarping(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ, WarpingMoment); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.ForceX); - args.push(this.ForceY); - args.push(this.ForceZ); - args.push(this.MomentX); - args.push(this.MomentY); - args.push(this.MomentZ); - args.push(this.WarpingMoment); - return args; - } -}; -var IfcStructuralLoadStatic = class { - constructor(expressID, type, Name) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - return new IfcStructuralLoadStatic(expressID, type, Name); - } - ToTape() { - let args = []; - args.push(this.Name); - return args; - } -}; -var IfcStructuralLoadTemperature = class { - constructor(expressID, type, Name, DeltaTConstant, DeltaTY, DeltaTZ) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DeltaTConstant = DeltaTConstant; - this.DeltaTY = DeltaTY; - this.DeltaTZ = DeltaTZ; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DeltaTConstant = tape[ptr++]; - let DeltaTY = tape[ptr++]; - let DeltaTZ = tape[ptr++]; - return new IfcStructuralLoadTemperature(expressID, type, Name, DeltaTConstant, DeltaTY, DeltaTZ); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DeltaTConstant); - args.push(this.DeltaTY); - args.push(this.DeltaTZ); - return args; - } -}; -var IfcStructuralMember = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - return new IfcStructuralMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - return args; - } -}; -var IfcStructuralPlanarAction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.DestabilizingLoad = DestabilizingLoad; - this.ProjectedOrTrue = ProjectedOrTrue; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let DestabilizingLoad = tape[ptr++]; - let ProjectedOrTrue = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStructuralPlanarAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.DestabilizingLoad); - args.push(this.ProjectedOrTrue); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStructuralPointAction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.DestabilizingLoad = DestabilizingLoad; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let DestabilizingLoad = tape[ptr++]; - return new IfcStructuralPointAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.DestabilizingLoad); - return args; - } -}; -var IfcStructuralPointConnection = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, ConditionCoordinateSystem) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedCondition = AppliedCondition; - this.ConditionCoordinateSystem = ConditionCoordinateSystem; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedCondition = tape[ptr++]; - let ConditionCoordinateSystem = tape[ptr++]; - return new IfcStructuralPointConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, ConditionCoordinateSystem); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedCondition); - args.push(this.ConditionCoordinateSystem); - return args; - } -}; -var IfcStructuralPointReaction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - return new IfcStructuralPointReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - return args; - } -}; -var IfcStructuralReaction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - return new IfcStructuralReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - return args; - } -}; -var IfcStructuralResultGroup = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheoryType, ResultForLoadGroup, IsLinear) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.TheoryType = TheoryType; - this.ResultForLoadGroup = ResultForLoadGroup; - this.IsLinear = IsLinear; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let TheoryType = tape[ptr++]; - let ResultForLoadGroup = tape[ptr++]; - let IsLinear = tape[ptr++]; - return new IfcStructuralResultGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheoryType, ResultForLoadGroup, IsLinear); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.TheoryType); - args.push(this.ResultForLoadGroup); - args.push(this.IsLinear); - return args; - } -}; -var IfcStructuralSurfaceAction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.DestabilizingLoad = DestabilizingLoad; - this.ProjectedOrTrue = ProjectedOrTrue; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let DestabilizingLoad = tape[ptr++]; - let ProjectedOrTrue = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStructuralSurfaceAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.DestabilizingLoad); - args.push(this.ProjectedOrTrue); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStructuralSurfaceConnection = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedCondition = AppliedCondition; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedCondition = tape[ptr++]; - return new IfcStructuralSurfaceConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedCondition); - return args; - } -}; -var IfcStructuralSurfaceMember = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.PredefinedType = PredefinedType; - this.Thickness = Thickness; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Thickness = tape[ptr++]; - return new IfcStructuralSurfaceMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.PredefinedType); - args.push(this.Thickness); - return args; - } -}; -var IfcStructuralSurfaceMemberVarying = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.PredefinedType = PredefinedType; - this.Thickness = Thickness; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let Thickness = tape[ptr++]; - return new IfcStructuralSurfaceMemberVarying(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.PredefinedType); - args.push(this.Thickness); - return args; - } -}; -var IfcStructuralSurfaceReaction = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.AppliedLoad = AppliedLoad; - this.GlobalOrLocal = GlobalOrLocal; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let AppliedLoad = tape[ptr++]; - let GlobalOrLocal = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcStructuralSurfaceReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.AppliedLoad); - args.push(this.GlobalOrLocal); - args.push(this.PredefinedType); - return args; - } -}; -var IfcStyleModel = class { - constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { - this.expressID = expressID; - this.type = type; - this.ContextOfItems = ContextOfItems; - this.RepresentationIdentifier = RepresentationIdentifier; - this.RepresentationType = RepresentationType; - this.Items = Items; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextOfItems = tape[ptr++]; - let RepresentationIdentifier = tape[ptr++]; - let RepresentationType = tape[ptr++]; - let Items = tape[ptr++]; - return new IfcStyleModel(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); - } - ToTape() { - let args = []; - args.push(this.ContextOfItems); - args.push(this.RepresentationIdentifier); - args.push(this.RepresentationType); - args.push(this.Items); - return args; - } -}; -var IfcStyledItem = class { - constructor(expressID, type, Item, Styles, Name) { - this.expressID = expressID; - this.type = type; - this.Item = Item; - this.Styles = Styles; - this.Name = Name; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Item = tape[ptr++]; - let Styles = tape[ptr++]; - let Name = tape[ptr++]; - return new IfcStyledItem(expressID, type, Item, Styles, Name); - } - ToTape() { - let args = []; - args.push(this.Item); - args.push(this.Styles); - args.push(this.Name); - return args; - } -}; -var IfcStyledRepresentation = class { - constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { - this.expressID = expressID; - this.type = type; - this.ContextOfItems = ContextOfItems; - this.RepresentationIdentifier = RepresentationIdentifier; - this.RepresentationType = RepresentationType; - this.Items = Items; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextOfItems = tape[ptr++]; - let RepresentationIdentifier = tape[ptr++]; - let RepresentationType = tape[ptr++]; - let Items = tape[ptr++]; - return new IfcStyledRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); - } - ToTape() { - let args = []; - args.push(this.ContextOfItems); - args.push(this.RepresentationIdentifier); - args.push(this.RepresentationType); - args.push(this.Items); - return args; - } -}; -var IfcSubContractResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Usage = Usage; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Usage = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSubContractResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Usage); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSubContractResourceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - this.BaseCosts = BaseCosts; - this.BaseQuantity = BaseQuantity; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - let BaseCosts = tape[ptr++]; - let BaseQuantity = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSubContractResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - args.push(this.BaseCosts); - args.push(this.BaseQuantity); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSubedge = class { - constructor(expressID, type, EdgeStart, EdgeEnd, ParentEdge) { - this.expressID = expressID; - this.type = type; - this.EdgeStart = EdgeStart; - this.EdgeEnd = EdgeEnd; - this.ParentEdge = ParentEdge; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let EdgeStart = tape[ptr++]; - let EdgeEnd = tape[ptr++]; - let ParentEdge = tape[ptr++]; - return new IfcSubedge(expressID, type, EdgeStart, EdgeEnd, ParentEdge); - } - ToTape() { - let args = []; - args.push(this.EdgeStart); - args.push(this.EdgeEnd); - args.push(this.ParentEdge); - return args; - } -}; -var IfcSurface = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcSurface(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcSurfaceCurve = class { - constructor(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation) { - this.expressID = expressID; - this.type = type; - this.Curve3D = Curve3D; - this.AssociatedGeometry = AssociatedGeometry; - this.MasterRepresentation = MasterRepresentation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Curve3D = tape[ptr++]; - let AssociatedGeometry = tape[ptr++]; - let MasterRepresentation = tape[ptr++]; - return new IfcSurfaceCurve(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation); - } - ToTape() { - let args = []; - args.push(this.Curve3D); - args.push(this.AssociatedGeometry); - args.push(this.MasterRepresentation); - return args; - } -}; -var IfcSurfaceCurveSweptAreaSolid = class { - constructor(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, ReferenceSurface) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - this.Directrix = Directrix; - this.StartParam = StartParam; - this.EndParam = EndParam; - this.ReferenceSurface = ReferenceSurface; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - let Directrix = tape[ptr++]; - let StartParam = tape[ptr++]; - let EndParam = tape[ptr++]; - let ReferenceSurface = tape[ptr++]; - return new IfcSurfaceCurveSweptAreaSolid(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, ReferenceSurface); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - args.push(this.Directrix); - args.push(this.StartParam); - args.push(this.EndParam); - args.push(this.ReferenceSurface); - return args; - } -}; -var IfcSurfaceFeature = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSurfaceFeature(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSurfaceOfLinearExtrusion = class { - constructor(expressID, type, SweptCurve, Position, ExtrudedDirection, Depth) { - this.expressID = expressID; - this.type = type; - this.SweptCurve = SweptCurve; - this.Position = Position; - this.ExtrudedDirection = ExtrudedDirection; - this.Depth = Depth; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptCurve = tape[ptr++]; - let Position = tape[ptr++]; - let ExtrudedDirection = tape[ptr++]; - let Depth = tape[ptr++]; - return new IfcSurfaceOfLinearExtrusion(expressID, type, SweptCurve, Position, ExtrudedDirection, Depth); - } - ToTape() { - let args = []; - args.push(this.SweptCurve); - args.push(this.Position); - args.push(this.ExtrudedDirection); - args.push(this.Depth); - return args; - } -}; -var IfcSurfaceOfRevolution = class { - constructor(expressID, type, SweptCurve, Position, AxisPosition) { - this.expressID = expressID; - this.type = type; - this.SweptCurve = SweptCurve; - this.Position = Position; - this.AxisPosition = AxisPosition; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptCurve = tape[ptr++]; - let Position = tape[ptr++]; - let AxisPosition = tape[ptr++]; - return new IfcSurfaceOfRevolution(expressID, type, SweptCurve, Position, AxisPosition); - } - ToTape() { - let args = []; - args.push(this.SweptCurve); - args.push(this.Position); - args.push(this.AxisPosition); - return args; - } -}; -var IfcSurfaceReinforcementArea = class { - constructor(expressID, type, Name, SurfaceReinforcement1, SurfaceReinforcement2, ShearReinforcement) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.SurfaceReinforcement1 = SurfaceReinforcement1; - this.SurfaceReinforcement2 = SurfaceReinforcement2; - this.ShearReinforcement = ShearReinforcement; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let SurfaceReinforcement1 = tape[ptr++]; - let SurfaceReinforcement2 = tape[ptr++]; - let ShearReinforcement = tape[ptr++]; - return new IfcSurfaceReinforcementArea(expressID, type, Name, SurfaceReinforcement1, SurfaceReinforcement2, ShearReinforcement); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.SurfaceReinforcement1); - args.push(this.SurfaceReinforcement2); - args.push(this.ShearReinforcement); - return args; - } -}; -var IfcSurfaceStyle = class { - constructor(expressID, type, Name, Side, Styles) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Side = Side; - this.Styles = Styles; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Side = tape[ptr++]; - let Styles = tape[ptr++]; - return new IfcSurfaceStyle(expressID, type, Name, Side, Styles); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Side); - args.push(this.Styles); - return args; - } -}; -var IfcSurfaceStyleLighting = class { - constructor(expressID, type, DiffuseTransmissionColour, DiffuseReflectionColour, TransmissionColour, ReflectanceColour) { - this.expressID = expressID; - this.type = type; - this.DiffuseTransmissionColour = DiffuseTransmissionColour; - this.DiffuseReflectionColour = DiffuseReflectionColour; - this.TransmissionColour = TransmissionColour; - this.ReflectanceColour = ReflectanceColour; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let DiffuseTransmissionColour = tape[ptr++]; - let DiffuseReflectionColour = tape[ptr++]; - let TransmissionColour = tape[ptr++]; - let ReflectanceColour = tape[ptr++]; - return new IfcSurfaceStyleLighting(expressID, type, DiffuseTransmissionColour, DiffuseReflectionColour, TransmissionColour, ReflectanceColour); - } - ToTape() { - let args = []; - args.push(this.DiffuseTransmissionColour); - args.push(this.DiffuseReflectionColour); - args.push(this.TransmissionColour); - args.push(this.ReflectanceColour); - return args; - } -}; -var IfcSurfaceStyleRefraction = class { - constructor(expressID, type, RefractionIndex, DispersionFactor) { - this.expressID = expressID; - this.type = type; - this.RefractionIndex = RefractionIndex; - this.DispersionFactor = DispersionFactor; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RefractionIndex = tape[ptr++]; - let DispersionFactor = tape[ptr++]; - return new IfcSurfaceStyleRefraction(expressID, type, RefractionIndex, DispersionFactor); - } - ToTape() { - let args = []; - args.push(this.RefractionIndex); - args.push(this.DispersionFactor); - return args; - } -}; -var IfcSurfaceStyleRendering = class { - constructor(expressID, type, SurfaceColour, Transparency, DiffuseColour, TransmissionColour, DiffuseTransmissionColour, ReflectionColour, SpecularColour, SpecularHighlight, ReflectanceMethod) { - this.expressID = expressID; - this.type = type; - this.SurfaceColour = SurfaceColour; - this.Transparency = Transparency; - this.DiffuseColour = DiffuseColour; - this.TransmissionColour = TransmissionColour; - this.DiffuseTransmissionColour = DiffuseTransmissionColour; - this.ReflectionColour = ReflectionColour; - this.SpecularColour = SpecularColour; - this.SpecularHighlight = SpecularHighlight; - this.ReflectanceMethod = ReflectanceMethod; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SurfaceColour = tape[ptr++]; - let Transparency = tape[ptr++]; - let DiffuseColour = tape[ptr++]; - let TransmissionColour = tape[ptr++]; - let DiffuseTransmissionColour = tape[ptr++]; - let ReflectionColour = tape[ptr++]; - let SpecularColour = tape[ptr++]; - let SpecularHighlight = tape[ptr++]; - let ReflectanceMethod = tape[ptr++]; - return new IfcSurfaceStyleRendering(expressID, type, SurfaceColour, Transparency, DiffuseColour, TransmissionColour, DiffuseTransmissionColour, ReflectionColour, SpecularColour, SpecularHighlight, ReflectanceMethod); - } - ToTape() { - let args = []; - args.push(this.SurfaceColour); - args.push(this.Transparency); - args.push(this.DiffuseColour); - args.push(this.TransmissionColour); - args.push(this.DiffuseTransmissionColour); - args.push(this.ReflectionColour); - args.push(this.SpecularColour); - args.push(this.SpecularHighlight); - args.push(this.ReflectanceMethod); - return args; - } -}; -var IfcSurfaceStyleShading = class { - constructor(expressID, type, SurfaceColour, Transparency) { - this.expressID = expressID; - this.type = type; - this.SurfaceColour = SurfaceColour; - this.Transparency = Transparency; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SurfaceColour = tape[ptr++]; - let Transparency = tape[ptr++]; - return new IfcSurfaceStyleShading(expressID, type, SurfaceColour, Transparency); - } - ToTape() { - let args = []; - args.push(this.SurfaceColour); - args.push(this.Transparency); - return args; - } -}; -var IfcSurfaceStyleWithTextures = class { - constructor(expressID, type, Textures) { - this.expressID = expressID; - this.type = type; - this.Textures = Textures; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Textures = tape[ptr++]; - return new IfcSurfaceStyleWithTextures(expressID, type, Textures); - } - ToTape() { - let args = []; - args.push(this.Textures); - return args; - } -}; -var IfcSurfaceTexture = class { - constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter) { - this.expressID = expressID; - this.type = type; - this.RepeatS = RepeatS; - this.RepeatT = RepeatT; - this.Mode = Mode; - this.TextureTransform = TextureTransform; - this.Parameter = Parameter; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RepeatS = tape[ptr++]; - let RepeatT = tape[ptr++]; - let Mode = tape[ptr++]; - let TextureTransform = tape[ptr++]; - let Parameter = tape[ptr++]; - return new IfcSurfaceTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter); - } - ToTape() { - let args = []; - args.push(this.RepeatS); - args.push(this.RepeatT); - args.push(this.Mode); - args.push(this.TextureTransform); - args.push(this.Parameter); - return args; - } -}; -var IfcSweptAreaSolid = class { - constructor(expressID, type, SweptArea, Position) { - this.expressID = expressID; - this.type = type; - this.SweptArea = SweptArea; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptArea = tape[ptr++]; - let Position = tape[ptr++]; - return new IfcSweptAreaSolid(expressID, type, SweptArea, Position); - } - ToTape() { - let args = []; - args.push(this.SweptArea); - args.push(this.Position); - return args; - } -}; -var IfcSweptDiskSolid = class { - constructor(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam) { - this.expressID = expressID; - this.type = type; - this.Directrix = Directrix; - this.Radius = Radius; - this.InnerRadius = InnerRadius; - this.StartParam = StartParam; - this.EndParam = EndParam; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Directrix = tape[ptr++]; - let Radius = tape[ptr++]; - let InnerRadius = tape[ptr++]; - let StartParam = tape[ptr++]; - let EndParam = tape[ptr++]; - return new IfcSweptDiskSolid(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam); - } - ToTape() { - let args = []; - args.push(this.Directrix); - args.push(this.Radius); - args.push(this.InnerRadius); - args.push(this.StartParam); - args.push(this.EndParam); - return args; - } -}; -var IfcSweptDiskSolidPolygonal = class { - constructor(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam, FilletRadius) { - this.expressID = expressID; - this.type = type; - this.Directrix = Directrix; - this.Radius = Radius; - this.InnerRadius = InnerRadius; - this.StartParam = StartParam; - this.EndParam = EndParam; - this.FilletRadius = FilletRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Directrix = tape[ptr++]; - let Radius = tape[ptr++]; - let InnerRadius = tape[ptr++]; - let StartParam = tape[ptr++]; - let EndParam = tape[ptr++]; - let FilletRadius = tape[ptr++]; - return new IfcSweptDiskSolidPolygonal(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam, FilletRadius); - } - ToTape() { - let args = []; - args.push(this.Directrix); - args.push(this.Radius); - args.push(this.InnerRadius); - args.push(this.StartParam); - args.push(this.EndParam); - args.push(this.FilletRadius); - return args; - } -}; -var IfcSweptSurface = class { - constructor(expressID, type, SweptCurve, Position) { - this.expressID = expressID; - this.type = type; - this.SweptCurve = SweptCurve; - this.Position = Position; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let SweptCurve = tape[ptr++]; - let Position = tape[ptr++]; - return new IfcSweptSurface(expressID, type, SweptCurve, Position); - } - ToTape() { - let args = []; - args.push(this.SweptCurve); - args.push(this.Position); - return args; - } -}; -var IfcSwitchingDevice = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSwitchingDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSwitchingDeviceType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSwitchingDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSystem = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - return new IfcSystem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - return args; - } -}; -var IfcSystemFurnitureElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSystemFurnitureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcSystemFurnitureElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcSystemFurnitureElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, WebEdgeRadius, WebSlope, FlangeSlope) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Depth = Depth; - this.FlangeWidth = FlangeWidth; - this.WebThickness = WebThickness; - this.FlangeThickness = FlangeThickness; - this.FilletRadius = FilletRadius; - this.FlangeEdgeRadius = FlangeEdgeRadius; - this.WebEdgeRadius = WebEdgeRadius; - this.WebSlope = WebSlope; - this.FlangeSlope = FlangeSlope; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Depth = tape[ptr++]; - let FlangeWidth = tape[ptr++]; - let WebThickness = tape[ptr++]; - let FlangeThickness = tape[ptr++]; - let FilletRadius = tape[ptr++]; - let FlangeEdgeRadius = tape[ptr++]; - let WebEdgeRadius = tape[ptr++]; - let WebSlope = tape[ptr++]; - let FlangeSlope = tape[ptr++]; - return new IfcTShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, WebEdgeRadius, WebSlope, FlangeSlope); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Depth); - args.push(this.FlangeWidth); - args.push(this.WebThickness); - args.push(this.FlangeThickness); - args.push(this.FilletRadius); - args.push(this.FlangeEdgeRadius); - args.push(this.WebEdgeRadius); - args.push(this.WebSlope); - args.push(this.FlangeSlope); - return args; - } -}; -var IfcTable = class { - constructor(expressID, type, Name, Rows, Columns) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Rows = Rows; - this.Columns = Columns; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Rows = tape[ptr++]; - let Columns = tape[ptr++]; - return new IfcTable(expressID, type, Name, Rows, Columns); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Rows); - args.push(this.Columns); - return args; - } -}; -var IfcTableColumn = class { - constructor(expressID, type, Identifier, Name, Description, Unit, ReferencePath) { - this.expressID = expressID; - this.type = type; - this.Identifier = Identifier; - this.Name = Name; - this.Description = Description; - this.Unit = Unit; - this.ReferencePath = ReferencePath; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Identifier = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let Unit = tape[ptr++]; - let ReferencePath = tape[ptr++]; - return new IfcTableColumn(expressID, type, Identifier, Name, Description, Unit, ReferencePath); - } - ToTape() { - let args = []; - args.push(this.Identifier); - args.push(this.Name); - args.push(this.Description); - args.push(this.Unit); - args.push(this.ReferencePath); - return args; - } -}; -var IfcTableRow = class { - constructor(expressID, type, RowCells, IsHeading) { - this.expressID = expressID; - this.type = type; - this.RowCells = RowCells; - this.IsHeading = IsHeading; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let RowCells = tape[ptr++]; - let IsHeading = tape[ptr++]; - return new IfcTableRow(expressID, type, RowCells, IsHeading); - } - ToTape() { - let args = []; - args.push(this.RowCells); - args.push(this.IsHeading); - return args; - } -}; -var IfcTank = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTank(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTankType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTankType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTask = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Status, WorkMethod, IsMilestone, Priority, TaskTime, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.Status = Status; - this.WorkMethod = WorkMethod; - this.IsMilestone = IsMilestone; - this.Priority = Priority; - this.TaskTime = TaskTime; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let Status = tape[ptr++]; - let WorkMethod = tape[ptr++]; - let IsMilestone = tape[ptr++]; - let Priority = tape[ptr++]; - let TaskTime = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTask(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Status, WorkMethod, IsMilestone, Priority, TaskTime, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.Status); - args.push(this.WorkMethod); - args.push(this.IsMilestone); - args.push(this.Priority); - args.push(this.TaskTime); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTaskTime = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.DurationType = DurationType; - this.ScheduleDuration = ScheduleDuration; - this.ScheduleStart = ScheduleStart; - this.ScheduleFinish = ScheduleFinish; - this.EarlyStart = EarlyStart; - this.EarlyFinish = EarlyFinish; - this.LateStart = LateStart; - this.LateFinish = LateFinish; - this.FreeFloat = FreeFloat; - this.TotalFloat = TotalFloat; - this.IsCritical = IsCritical; - this.StatusTime = StatusTime; - this.ActualDuration = ActualDuration; - this.ActualStart = ActualStart; - this.ActualFinish = ActualFinish; - this.RemainingTime = RemainingTime; - this.Completion = Completion; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let DurationType = tape[ptr++]; - let ScheduleDuration = tape[ptr++]; - let ScheduleStart = tape[ptr++]; - let ScheduleFinish = tape[ptr++]; - let EarlyStart = tape[ptr++]; - let EarlyFinish = tape[ptr++]; - let LateStart = tape[ptr++]; - let LateFinish = tape[ptr++]; - let FreeFloat = tape[ptr++]; - let TotalFloat = tape[ptr++]; - let IsCritical = tape[ptr++]; - let StatusTime = tape[ptr++]; - let ActualDuration = tape[ptr++]; - let ActualStart = tape[ptr++]; - let ActualFinish = tape[ptr++]; - let RemainingTime = tape[ptr++]; - let Completion = tape[ptr++]; - return new IfcTaskTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.DurationType); - args.push(this.ScheduleDuration); - args.push(this.ScheduleStart); - args.push(this.ScheduleFinish); - args.push(this.EarlyStart); - args.push(this.EarlyFinish); - args.push(this.LateStart); - args.push(this.LateFinish); - args.push(this.FreeFloat); - args.push(this.TotalFloat); - args.push(this.IsCritical); - args.push(this.StatusTime); - args.push(this.ActualDuration); - args.push(this.ActualStart); - args.push(this.ActualFinish); - args.push(this.RemainingTime); - args.push(this.Completion); - return args; - } -}; -var IfcTaskTimeRecurring = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion, Recurrence) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.DurationType = DurationType; - this.ScheduleDuration = ScheduleDuration; - this.ScheduleStart = ScheduleStart; - this.ScheduleFinish = ScheduleFinish; - this.EarlyStart = EarlyStart; - this.EarlyFinish = EarlyFinish; - this.LateStart = LateStart; - this.LateFinish = LateFinish; - this.FreeFloat = FreeFloat; - this.TotalFloat = TotalFloat; - this.IsCritical = IsCritical; - this.StatusTime = StatusTime; - this.ActualDuration = ActualDuration; - this.ActualStart = ActualStart; - this.ActualFinish = ActualFinish; - this.RemainingTime = RemainingTime; - this.Completion = Completion; - this.Recurrence = Recurrence; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let DurationType = tape[ptr++]; - let ScheduleDuration = tape[ptr++]; - let ScheduleStart = tape[ptr++]; - let ScheduleFinish = tape[ptr++]; - let EarlyStart = tape[ptr++]; - let EarlyFinish = tape[ptr++]; - let LateStart = tape[ptr++]; - let LateFinish = tape[ptr++]; - let FreeFloat = tape[ptr++]; - let TotalFloat = tape[ptr++]; - let IsCritical = tape[ptr++]; - let StatusTime = tape[ptr++]; - let ActualDuration = tape[ptr++]; - let ActualStart = tape[ptr++]; - let ActualFinish = tape[ptr++]; - let RemainingTime = tape[ptr++]; - let Completion = tape[ptr++]; - let Recurrence = tape[ptr++]; - return new IfcTaskTimeRecurring(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion, Recurrence); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.DurationType); - args.push(this.ScheduleDuration); - args.push(this.ScheduleStart); - args.push(this.ScheduleFinish); - args.push(this.EarlyStart); - args.push(this.EarlyFinish); - args.push(this.LateStart); - args.push(this.LateFinish); - args.push(this.FreeFloat); - args.push(this.TotalFloat); - args.push(this.IsCritical); - args.push(this.StatusTime); - args.push(this.ActualDuration); - args.push(this.ActualStart); - args.push(this.ActualFinish); - args.push(this.RemainingTime); - args.push(this.Completion); - args.push(this.Recurrence); - return args; - } -}; -var IfcTaskType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, WorkMethod) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ProcessType = ProcessType; - this.PredefinedType = PredefinedType; - this.WorkMethod = WorkMethod; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ProcessType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let WorkMethod = tape[ptr++]; - return new IfcTaskType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, WorkMethod); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ProcessType); - args.push(this.PredefinedType); - args.push(this.WorkMethod); - return args; - } -}; -var IfcTelecomAddress = class { - constructor(expressID, type, Purpose, Description, UserDefinedPurpose, TelephoneNumbers, FacsimileNumbers, PagerNumber, ElectronicMailAddresses, WWWHomePageURL, MessagingIDs) { - this.expressID = expressID; - this.type = type; - this.Purpose = Purpose; - this.Description = Description; - this.UserDefinedPurpose = UserDefinedPurpose; - this.TelephoneNumbers = TelephoneNumbers; - this.FacsimileNumbers = FacsimileNumbers; - this.PagerNumber = PagerNumber; - this.ElectronicMailAddresses = ElectronicMailAddresses; - this.WWWHomePageURL = WWWHomePageURL; - this.MessagingIDs = MessagingIDs; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Purpose = tape[ptr++]; - let Description = tape[ptr++]; - let UserDefinedPurpose = tape[ptr++]; - let TelephoneNumbers = tape[ptr++]; - let FacsimileNumbers = tape[ptr++]; - let PagerNumber = tape[ptr++]; - let ElectronicMailAddresses = tape[ptr++]; - let WWWHomePageURL = tape[ptr++]; - let MessagingIDs = tape[ptr++]; - return new IfcTelecomAddress(expressID, type, Purpose, Description, UserDefinedPurpose, TelephoneNumbers, FacsimileNumbers, PagerNumber, ElectronicMailAddresses, WWWHomePageURL, MessagingIDs); - } - ToTape() { - let args = []; - args.push(this.Purpose); - args.push(this.Description); - args.push(this.UserDefinedPurpose); - args.push(this.TelephoneNumbers); - args.push(this.FacsimileNumbers); - args.push(this.PagerNumber); - args.push(this.ElectronicMailAddresses); - args.push(this.WWWHomePageURL); - args.push(this.MessagingIDs); - return args; - } -}; -var IfcTendon = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType, NominalDiameter, CrossSectionArea, TensionForce, PreStress, FrictionCoefficient, AnchorageSlip, MinCurvatureRadius) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.SteelGrade = SteelGrade; - this.PredefinedType = PredefinedType; - this.NominalDiameter = NominalDiameter; - this.CrossSectionArea = CrossSectionArea; - this.TensionForce = TensionForce; - this.PreStress = PreStress; - this.FrictionCoefficient = FrictionCoefficient; - this.AnchorageSlip = AnchorageSlip; - this.MinCurvatureRadius = MinCurvatureRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let SteelGrade = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let NominalDiameter = tape[ptr++]; - let CrossSectionArea = tape[ptr++]; - let TensionForce = tape[ptr++]; - let PreStress = tape[ptr++]; - let FrictionCoefficient = tape[ptr++]; - let AnchorageSlip = tape[ptr++]; - let MinCurvatureRadius = tape[ptr++]; - return new IfcTendon(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType, NominalDiameter, CrossSectionArea, TensionForce, PreStress, FrictionCoefficient, AnchorageSlip, MinCurvatureRadius); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.SteelGrade); - args.push(this.PredefinedType); - args.push(this.NominalDiameter); - args.push(this.CrossSectionArea); - args.push(this.TensionForce); - args.push(this.PreStress); - args.push(this.FrictionCoefficient); - args.push(this.AnchorageSlip); - args.push(this.MinCurvatureRadius); - return args; - } -}; -var IfcTendonAnchor = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.SteelGrade = SteelGrade; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let SteelGrade = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTendonAnchor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.SteelGrade); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTendonAnchorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTendonAnchorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTendonConduit = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.SteelGrade = SteelGrade; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let SteelGrade = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTendonConduit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.SteelGrade); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTendonConduitType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTendonConduitType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTendonType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, SheathDiameter) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.NominalDiameter = NominalDiameter; - this.CrossSectionArea = CrossSectionArea; - this.SheathDiameter = SheathDiameter; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let NominalDiameter = tape[ptr++]; - let CrossSectionArea = tape[ptr++]; - let SheathDiameter = tape[ptr++]; - return new IfcTendonType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, SheathDiameter); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.NominalDiameter); - args.push(this.CrossSectionArea); - args.push(this.SheathDiameter); - return args; - } -}; -var IfcTessellatedFaceSet = class { - constructor(expressID, type, Coordinates) { - this.expressID = expressID; - this.type = type; - this.Coordinates = Coordinates; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Coordinates = tape[ptr++]; - return new IfcTessellatedFaceSet(expressID, type, Coordinates); - } - ToTape() { - let args = []; - args.push(this.Coordinates); - return args; - } -}; -var IfcTessellatedItem = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcTessellatedItem(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcTextLiteral = class { - constructor(expressID, type, Literal, Placement, Path) { - this.expressID = expressID; - this.type = type; - this.Literal = Literal; - this.Placement = Placement; - this.Path = Path; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Literal = tape[ptr++]; - let Placement = tape[ptr++]; - let Path = tape[ptr++]; - return new IfcTextLiteral(expressID, type, Literal, Placement, Path); - } - ToTape() { - let args = []; - args.push(this.Literal); - args.push(this.Placement); - args.push(this.Path); - return args; - } -}; -var IfcTextLiteralWithExtent = class { - constructor(expressID, type, Literal, Placement, Path, Extent, BoxAlignment) { - this.expressID = expressID; - this.type = type; - this.Literal = Literal; - this.Placement = Placement; - this.Path = Path; - this.Extent = Extent; - this.BoxAlignment = BoxAlignment; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Literal = tape[ptr++]; - let Placement = tape[ptr++]; - let Path = tape[ptr++]; - let Extent = tape[ptr++]; - let BoxAlignment = tape[ptr++]; - return new IfcTextLiteralWithExtent(expressID, type, Literal, Placement, Path, Extent, BoxAlignment); - } - ToTape() { - let args = []; - args.push(this.Literal); - args.push(this.Placement); - args.push(this.Path); - args.push(this.Extent); - args.push(this.BoxAlignment); - return args; - } -}; -var IfcTextStyle = class { - constructor(expressID, type, Name, TextCharacterAppearance, TextStyle, TextFontStyle, ModelOrDraughting) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.TextCharacterAppearance = TextCharacterAppearance; - this.TextStyle = TextStyle; - this.TextFontStyle = TextFontStyle; - this.ModelOrDraughting = ModelOrDraughting; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let TextCharacterAppearance = tape[ptr++]; - let TextStyle = tape[ptr++]; - let TextFontStyle = tape[ptr++]; - let ModelOrDraughting = tape[ptr++]; - return new IfcTextStyle(expressID, type, Name, TextCharacterAppearance, TextStyle, TextFontStyle, ModelOrDraughting); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.TextCharacterAppearance); - args.push(this.TextStyle); - args.push(this.TextFontStyle); - args.push(this.ModelOrDraughting); - return args; - } -}; -var IfcTextStyleFontModel = class { - constructor(expressID, type, Name, FontFamily, FontStyle, FontVariant, FontWeight, FontSize) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.FontFamily = FontFamily; - this.FontStyle = FontStyle; - this.FontVariant = FontVariant; - this.FontWeight = FontWeight; - this.FontSize = FontSize; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let FontFamily = tape[ptr++]; - let FontStyle = tape[ptr++]; - let FontVariant = tape[ptr++]; - let FontWeight = tape[ptr++]; - let FontSize = tape[ptr++]; - return new IfcTextStyleFontModel(expressID, type, Name, FontFamily, FontStyle, FontVariant, FontWeight, FontSize); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.FontFamily); - args.push(this.FontStyle); - args.push(this.FontVariant); - args.push(this.FontWeight); - args.push(this.FontSize); - return args; - } -}; -var IfcTextStyleForDefinedFont = class { - constructor(expressID, type, Colour, BackgroundColour) { - this.expressID = expressID; - this.type = type; - this.Colour = Colour; - this.BackgroundColour = BackgroundColour; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Colour = tape[ptr++]; - let BackgroundColour = tape[ptr++]; - return new IfcTextStyleForDefinedFont(expressID, type, Colour, BackgroundColour); - } - ToTape() { - let args = []; - args.push(this.Colour); - args.push(this.BackgroundColour); - return args; - } -}; -var IfcTextStyleTextModel = class { - constructor(expressID, type, TextIndent, TextAlign, TextDecoration, LetterSpacing, WordSpacing, TextTransform, LineHeight) { - this.expressID = expressID; - this.type = type; - this.TextIndent = TextIndent; - this.TextAlign = TextAlign; - this.TextDecoration = TextDecoration; - this.LetterSpacing = LetterSpacing; - this.WordSpacing = WordSpacing; - this.TextTransform = TextTransform; - this.LineHeight = LineHeight; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TextIndent = tape[ptr++]; - let TextAlign = tape[ptr++]; - let TextDecoration = tape[ptr++]; - let LetterSpacing = tape[ptr++]; - let WordSpacing = tape[ptr++]; - let TextTransform = tape[ptr++]; - let LineHeight = tape[ptr++]; - return new IfcTextStyleTextModel(expressID, type, TextIndent, TextAlign, TextDecoration, LetterSpacing, WordSpacing, TextTransform, LineHeight); - } - ToTape() { - let args = []; - args.push(this.TextIndent); - args.push(this.TextAlign); - args.push(this.TextDecoration); - args.push(this.LetterSpacing); - args.push(this.WordSpacing); - args.push(this.TextTransform); - args.push(this.LineHeight); - return args; - } -}; -var IfcTextureCoordinate = class { - constructor(expressID, type, Maps) { - this.expressID = expressID; - this.type = type; - this.Maps = Maps; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Maps = tape[ptr++]; - return new IfcTextureCoordinate(expressID, type, Maps); - } - ToTape() { - let args = []; - args.push(this.Maps); - return args; - } -}; -var IfcTextureCoordinateGenerator = class { - constructor(expressID, type, Maps, Mode, Parameter) { - this.expressID = expressID; - this.type = type; - this.Maps = Maps; - this.Mode = Mode; - this.Parameter = Parameter; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Maps = tape[ptr++]; - let Mode = tape[ptr++]; - let Parameter = tape[ptr++]; - return new IfcTextureCoordinateGenerator(expressID, type, Maps, Mode, Parameter); - } - ToTape() { - let args = []; - args.push(this.Maps); - args.push(this.Mode); - args.push(this.Parameter); - return args; - } -}; -var IfcTextureMap = class { - constructor(expressID, type, Maps, Vertices, MappedTo) { - this.expressID = expressID; - this.type = type; - this.Maps = Maps; - this.Vertices = Vertices; - this.MappedTo = MappedTo; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Maps = tape[ptr++]; - let Vertices = tape[ptr++]; - let MappedTo = tape[ptr++]; - return new IfcTextureMap(expressID, type, Maps, Vertices, MappedTo); - } - ToTape() { - let args = []; - args.push(this.Maps); - args.push(this.Vertices); - args.push(this.MappedTo); - return args; - } -}; -var IfcTextureVertex = class { - constructor(expressID, type, Coordinates) { - this.expressID = expressID; - this.type = type; - this.Coordinates = Coordinates; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Coordinates = tape[ptr++]; - return new IfcTextureVertex(expressID, type, Coordinates); - } - ToTape() { - let args = []; - args.push(this.Coordinates); - return args; - } -}; -var IfcTextureVertexList = class { - constructor(expressID, type, TexCoordsList) { - this.expressID = expressID; - this.type = type; - this.TexCoordsList = TexCoordsList; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let TexCoordsList = tape[ptr++]; - return new IfcTextureVertexList(expressID, type, TexCoordsList); - } - ToTape() { - let args = []; - args.push(this.TexCoordsList); - return args; - } -}; -var IfcTimePeriod = class { - constructor(expressID, type, StartTime, EndTime) { - this.expressID = expressID; - this.type = type; - this.StartTime = StartTime; - this.EndTime = EndTime; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let StartTime = tape[ptr++]; - let EndTime = tape[ptr++]; - return new IfcTimePeriod(expressID, type, StartTime, EndTime); - } - ToTape() { - let args = []; - args.push(this.StartTime); - args.push(this.EndTime); - return args; - } -}; -var IfcTimeSeries = class { - constructor(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.Description = Description; - this.StartTime = StartTime; - this.EndTime = EndTime; - this.TimeSeriesDataType = TimeSeriesDataType; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.Unit = Unit; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let StartTime = tape[ptr++]; - let EndTime = tape[ptr++]; - let TimeSeriesDataType = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let Unit = tape[ptr++]; - return new IfcTimeSeries(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.Description); - args.push(this.StartTime); - args.push(this.EndTime); - args.push(this.TimeSeriesDataType); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.Unit); - return args; - } -}; -var IfcTimeSeriesValue = class { - constructor(expressID, type, ListValues) { - this.expressID = expressID; - this.type = type; - this.ListValues = ListValues; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ListValues = tape[ptr++]; - return new IfcTimeSeriesValue(expressID, type, ListValues); - } - ToTape() { - let args = []; - args.push(this.ListValues); - return args; - } -}; -var IfcTopologicalRepresentationItem = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcTopologicalRepresentationItem(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcTopologyRepresentation = class { - constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { - this.expressID = expressID; - this.type = type; - this.ContextOfItems = ContextOfItems; - this.RepresentationIdentifier = RepresentationIdentifier; - this.RepresentationType = RepresentationType; - this.Items = Items; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ContextOfItems = tape[ptr++]; - let RepresentationIdentifier = tape[ptr++]; - let RepresentationType = tape[ptr++]; - let Items = tape[ptr++]; - return new IfcTopologyRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); - } - ToTape() { - let args = []; - args.push(this.ContextOfItems); - args.push(this.RepresentationIdentifier); - args.push(this.RepresentationType); - args.push(this.Items); - return args; - } -}; -var IfcToroidalSurface = class { - constructor(expressID, type, Position, MajorRadius, MinorRadius) { - this.expressID = expressID; - this.type = type; - this.Position = Position; - this.MajorRadius = MajorRadius; - this.MinorRadius = MinorRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Position = tape[ptr++]; - let MajorRadius = tape[ptr++]; - let MinorRadius = tape[ptr++]; - return new IfcToroidalSurface(expressID, type, Position, MajorRadius, MinorRadius); - } - ToTape() { - let args = []; - args.push(this.Position); - args.push(this.MajorRadius); - args.push(this.MinorRadius); - return args; - } -}; -var IfcTransformer = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTransformer(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTransformerType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTransformerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTransitionCurveSegment2D = class { - constructor(expressID, type, StartPoint, StartDirection, SegmentLength, StartRadius, EndRadius, IsStartRadiusCCW, IsEndRadiusCCW, TransitionCurveType) { - this.expressID = expressID; - this.type = type; - this.StartPoint = StartPoint; - this.StartDirection = StartDirection; - this.SegmentLength = SegmentLength; - this.StartRadius = StartRadius; - this.EndRadius = EndRadius; - this.IsStartRadiusCCW = IsStartRadiusCCW; - this.IsEndRadiusCCW = IsEndRadiusCCW; - this.TransitionCurveType = TransitionCurveType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let StartPoint = tape[ptr++]; - let StartDirection = tape[ptr++]; - let SegmentLength = tape[ptr++]; - let StartRadius = tape[ptr++]; - let EndRadius = tape[ptr++]; - let IsStartRadiusCCW = tape[ptr++]; - let IsEndRadiusCCW = tape[ptr++]; - let TransitionCurveType = tape[ptr++]; - return new IfcTransitionCurveSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength, StartRadius, EndRadius, IsStartRadiusCCW, IsEndRadiusCCW, TransitionCurveType); - } - ToTape() { - let args = []; - args.push(this.StartPoint); - args.push(this.StartDirection); - args.push(this.SegmentLength); - args.push(this.StartRadius); - args.push(this.EndRadius); - args.push(this.IsStartRadiusCCW); - args.push(this.IsEndRadiusCCW); - args.push(this.TransitionCurveType); - return args; - } -}; -var IfcTransportElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTransportElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTransportElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTransportElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTrapeziumProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, BottomXDim, TopXDim, YDim, TopXOffset) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.BottomXDim = BottomXDim; - this.TopXDim = TopXDim; - this.YDim = YDim; - this.TopXOffset = TopXOffset; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let BottomXDim = tape[ptr++]; - let TopXDim = tape[ptr++]; - let YDim = tape[ptr++]; - let TopXOffset = tape[ptr++]; - return new IfcTrapeziumProfileDef(expressID, type, ProfileType, ProfileName, Position, BottomXDim, TopXDim, YDim, TopXOffset); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.BottomXDim); - args.push(this.TopXDim); - args.push(this.YDim); - args.push(this.TopXOffset); - return args; - } -}; -var IfcTriangulatedFaceSet = class { - constructor(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex) { - this.expressID = expressID; - this.type = type; - this.Coordinates = Coordinates; - this.Normals = Normals; - this.Closed = Closed; - this.CoordIndex = CoordIndex; - this.PnIndex = PnIndex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Coordinates = tape[ptr++]; - let Normals = tape[ptr++]; - let Closed = tape[ptr++]; - let CoordIndex = tape[ptr++]; - let PnIndex = tape[ptr++]; - return new IfcTriangulatedFaceSet(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex); - } - ToTape() { - let args = []; - args.push(this.Coordinates); - args.push(this.Normals); - args.push(this.Closed); - args.push(this.CoordIndex); - args.push(this.PnIndex); - return args; - } -}; -var IfcTriangulatedIrregularNetwork = class { - constructor(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex, Flags) { - this.expressID = expressID; - this.type = type; - this.Coordinates = Coordinates; - this.Normals = Normals; - this.Closed = Closed; - this.CoordIndex = CoordIndex; - this.PnIndex = PnIndex; - this.Flags = Flags; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Coordinates = tape[ptr++]; - let Normals = tape[ptr++]; - let Closed = tape[ptr++]; - let CoordIndex = tape[ptr++]; - let PnIndex = tape[ptr++]; - let Flags = tape[ptr++]; - return new IfcTriangulatedIrregularNetwork(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex, Flags); - } - ToTape() { - let args = []; - args.push(this.Coordinates); - args.push(this.Normals); - args.push(this.Closed); - args.push(this.CoordIndex); - args.push(this.PnIndex); - args.push(this.Flags); - return args; - } -}; -var IfcTrimmedCurve = class { - constructor(expressID, type, BasisCurve, Trim1, Trim2, SenseAgreement, MasterRepresentation) { - this.expressID = expressID; - this.type = type; - this.BasisCurve = BasisCurve; - this.Trim1 = Trim1; - this.Trim2 = Trim2; - this.SenseAgreement = SenseAgreement; - this.MasterRepresentation = MasterRepresentation; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let BasisCurve = tape[ptr++]; - let Trim1 = tape[ptr++]; - let Trim2 = tape[ptr++]; - let SenseAgreement = tape[ptr++]; - let MasterRepresentation = tape[ptr++]; - return new IfcTrimmedCurve(expressID, type, BasisCurve, Trim1, Trim2, SenseAgreement, MasterRepresentation); - } - ToTape() { - let args = []; - args.push(this.BasisCurve); - args.push(this.Trim1); - args.push(this.Trim2); - args.push(this.SenseAgreement); - args.push(this.MasterRepresentation); - return args; - } -}; -var IfcTubeBundle = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTubeBundle(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTubeBundleType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcTubeBundleType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcTypeObject = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - return new IfcTypeObject(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - return args; - } -}; -var IfcTypeProcess = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ProcessType = ProcessType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ProcessType = tape[ptr++]; - return new IfcTypeProcess(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ProcessType); - return args; - } -}; -var IfcTypeProduct = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcTypeProduct(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - return args; - } -}; -var IfcTypeResource = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.Identification = Identification; - this.LongDescription = LongDescription; - this.ResourceType = ResourceType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let Identification = tape[ptr++]; - let LongDescription = tape[ptr++]; - let ResourceType = tape[ptr++]; - return new IfcTypeResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.Identification); - args.push(this.LongDescription); - args.push(this.ResourceType); - return args; - } -}; -var IfcUShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius, FlangeSlope) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Depth = Depth; - this.FlangeWidth = FlangeWidth; - this.WebThickness = WebThickness; - this.FlangeThickness = FlangeThickness; - this.FilletRadius = FilletRadius; - this.EdgeRadius = EdgeRadius; - this.FlangeSlope = FlangeSlope; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Depth = tape[ptr++]; - let FlangeWidth = tape[ptr++]; - let WebThickness = tape[ptr++]; - let FlangeThickness = tape[ptr++]; - let FilletRadius = tape[ptr++]; - let EdgeRadius = tape[ptr++]; - let FlangeSlope = tape[ptr++]; - return new IfcUShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius, FlangeSlope); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Depth); - args.push(this.FlangeWidth); - args.push(this.WebThickness); - args.push(this.FlangeThickness); - args.push(this.FilletRadius); - args.push(this.EdgeRadius); - args.push(this.FlangeSlope); - return args; - } -}; -var IfcUnitAssignment = class { - constructor(expressID, type, Units) { - this.expressID = expressID; - this.type = type; - this.Units = Units; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Units = tape[ptr++]; - return new IfcUnitAssignment(expressID, type, Units); - } - ToTape() { - let args = []; - args.push(this.Units); - return args; - } -}; -var IfcUnitaryControlElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcUnitaryControlElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcUnitaryControlElementType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcUnitaryControlElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcUnitaryEquipment = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcUnitaryEquipment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcUnitaryEquipmentType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcUnitaryEquipmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcValve = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcValve(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcValveType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcValveType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcVector = class { - constructor(expressID, type, Orientation, Magnitude) { - this.expressID = expressID; - this.type = type; - this.Orientation = Orientation; - this.Magnitude = Magnitude; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Orientation = tape[ptr++]; - let Magnitude = tape[ptr++]; - return new IfcVector(expressID, type, Orientation, Magnitude); - } - ToTape() { - let args = []; - args.push(this.Orientation); - args.push(this.Magnitude); - return args; - } -}; -var IfcVertex = class { - constructor(expressID, type) { - this.expressID = expressID; - this.type = type; - } - static FromTape(expressID, type, tape) { - return new IfcVertex(expressID, type); - } - ToTape() { - let args = []; - return args; - } -}; -var IfcVertexLoop = class { - constructor(expressID, type, LoopVertex) { - this.expressID = expressID; - this.type = type; - this.LoopVertex = LoopVertex; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let LoopVertex = tape[ptr++]; - return new IfcVertexLoop(expressID, type, LoopVertex); - } - ToTape() { - let args = []; - args.push(this.LoopVertex); - return args; - } -}; -var IfcVertexPoint = class { - constructor(expressID, type, VertexGeometry) { - this.expressID = expressID; - this.type = type; - this.VertexGeometry = VertexGeometry; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let VertexGeometry = tape[ptr++]; - return new IfcVertexPoint(expressID, type, VertexGeometry); - } - ToTape() { - let args = []; - args.push(this.VertexGeometry); - return args; - } -}; -var IfcVibrationDamper = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcVibrationDamper(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcVibrationDamperType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcVibrationDamperType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcVibrationIsolator = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcVibrationIsolator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcVibrationIsolatorType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcVibrationIsolatorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcVirtualElement = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - return new IfcVirtualElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - return args; - } -}; -var IfcVirtualGridIntersection = class { - constructor(expressID, type, IntersectingAxes, OffsetDistances) { - this.expressID = expressID; - this.type = type; - this.IntersectingAxes = IntersectingAxes; - this.OffsetDistances = OffsetDistances; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let IntersectingAxes = tape[ptr++]; - let OffsetDistances = tape[ptr++]; - return new IfcVirtualGridIntersection(expressID, type, IntersectingAxes, OffsetDistances); - } - ToTape() { - let args = []; - args.push(this.IntersectingAxes); - args.push(this.OffsetDistances); - return args; - } -}; -var IfcVoidingFeature = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcVoidingFeature(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWall = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWall(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWallElementedCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWallElementedCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWallStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWallStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWallType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWallType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWasteTerminal = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWasteTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWasteTerminalType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWasteTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWindow = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.OverallHeight = OverallHeight; - this.OverallWidth = OverallWidth; - this.PredefinedType = PredefinedType; - this.PartitioningType = PartitioningType; - this.UserDefinedPartitioningType = UserDefinedPartitioningType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let OverallHeight = tape[ptr++]; - let OverallWidth = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let PartitioningType = tape[ptr++]; - let UserDefinedPartitioningType = tape[ptr++]; - return new IfcWindow(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.OverallHeight); - args.push(this.OverallWidth); - args.push(this.PredefinedType); - args.push(this.PartitioningType); - args.push(this.UserDefinedPartitioningType); - return args; - } -}; -var IfcWindowLiningProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, TransomThickness, MullionThickness, FirstTransomOffset, SecondTransomOffset, FirstMullionOffset, SecondMullionOffset, ShapeAspectStyle, LiningOffset, LiningToPanelOffsetX, LiningToPanelOffsetY) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.LiningDepth = LiningDepth; - this.LiningThickness = LiningThickness; - this.TransomThickness = TransomThickness; - this.MullionThickness = MullionThickness; - this.FirstTransomOffset = FirstTransomOffset; - this.SecondTransomOffset = SecondTransomOffset; - this.FirstMullionOffset = FirstMullionOffset; - this.SecondMullionOffset = SecondMullionOffset; - this.ShapeAspectStyle = ShapeAspectStyle; - this.LiningOffset = LiningOffset; - this.LiningToPanelOffsetX = LiningToPanelOffsetX; - this.LiningToPanelOffsetY = LiningToPanelOffsetY; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let LiningDepth = tape[ptr++]; - let LiningThickness = tape[ptr++]; - let TransomThickness = tape[ptr++]; - let MullionThickness = tape[ptr++]; - let FirstTransomOffset = tape[ptr++]; - let SecondTransomOffset = tape[ptr++]; - let FirstMullionOffset = tape[ptr++]; - let SecondMullionOffset = tape[ptr++]; - let ShapeAspectStyle = tape[ptr++]; - let LiningOffset = tape[ptr++]; - let LiningToPanelOffsetX = tape[ptr++]; - let LiningToPanelOffsetY = tape[ptr++]; - return new IfcWindowLiningProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, TransomThickness, MullionThickness, FirstTransomOffset, SecondTransomOffset, FirstMullionOffset, SecondMullionOffset, ShapeAspectStyle, LiningOffset, LiningToPanelOffsetX, LiningToPanelOffsetY); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.LiningDepth); - args.push(this.LiningThickness); - args.push(this.TransomThickness); - args.push(this.MullionThickness); - args.push(this.FirstTransomOffset); - args.push(this.SecondTransomOffset); - args.push(this.FirstMullionOffset); - args.push(this.SecondMullionOffset); - args.push(this.ShapeAspectStyle); - args.push(this.LiningOffset); - args.push(this.LiningToPanelOffsetX); - args.push(this.LiningToPanelOffsetY); - return args; - } -}; -var IfcWindowPanelProperties = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.OperationType = OperationType; - this.PanelPosition = PanelPosition; - this.FrameDepth = FrameDepth; - this.FrameThickness = FrameThickness; - this.ShapeAspectStyle = ShapeAspectStyle; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let OperationType = tape[ptr++]; - let PanelPosition = tape[ptr++]; - let FrameDepth = tape[ptr++]; - let FrameThickness = tape[ptr++]; - let ShapeAspectStyle = tape[ptr++]; - return new IfcWindowPanelProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.OperationType); - args.push(this.PanelPosition); - args.push(this.FrameDepth); - args.push(this.FrameThickness); - args.push(this.ShapeAspectStyle); - return args; - } -}; -var IfcWindowStandardCase = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.ObjectPlacement = ObjectPlacement; - this.Representation = Representation; - this.Tag = Tag; - this.OverallHeight = OverallHeight; - this.OverallWidth = OverallWidth; - this.PredefinedType = PredefinedType; - this.PartitioningType = PartitioningType; - this.UserDefinedPartitioningType = UserDefinedPartitioningType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let ObjectPlacement = tape[ptr++]; - let Representation = tape[ptr++]; - let Tag = tape[ptr++]; - let OverallHeight = tape[ptr++]; - let OverallWidth = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let PartitioningType = tape[ptr++]; - let UserDefinedPartitioningType = tape[ptr++]; - return new IfcWindowStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.ObjectPlacement); - args.push(this.Representation); - args.push(this.Tag); - args.push(this.OverallHeight); - args.push(this.OverallWidth); - args.push(this.PredefinedType); - args.push(this.PartitioningType); - args.push(this.UserDefinedPartitioningType); - return args; - } -}; -var IfcWindowStyle = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ConstructionType, OperationType, ParameterTakesPrecedence, Sizeable) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ConstructionType = ConstructionType; - this.OperationType = OperationType; - this.ParameterTakesPrecedence = ParameterTakesPrecedence; - this.Sizeable = Sizeable; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ConstructionType = tape[ptr++]; - let OperationType = tape[ptr++]; - let ParameterTakesPrecedence = tape[ptr++]; - let Sizeable = tape[ptr++]; - return new IfcWindowStyle(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ConstructionType, OperationType, ParameterTakesPrecedence, Sizeable); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ConstructionType); - args.push(this.OperationType); - args.push(this.ParameterTakesPrecedence); - args.push(this.Sizeable); - return args; - } -}; -var IfcWindowType = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, PartitioningType, ParameterTakesPrecedence, UserDefinedPartitioningType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ApplicableOccurrence = ApplicableOccurrence; - this.HasPropertySets = HasPropertySets; - this.RepresentationMaps = RepresentationMaps; - this.Tag = Tag; - this.ElementType = ElementType; - this.PredefinedType = PredefinedType; - this.PartitioningType = PartitioningType; - this.ParameterTakesPrecedence = ParameterTakesPrecedence; - this.UserDefinedPartitioningType = UserDefinedPartitioningType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ApplicableOccurrence = tape[ptr++]; - let HasPropertySets = tape[ptr++]; - let RepresentationMaps = tape[ptr++]; - let Tag = tape[ptr++]; - let ElementType = tape[ptr++]; - let PredefinedType = tape[ptr++]; - let PartitioningType = tape[ptr++]; - let ParameterTakesPrecedence = tape[ptr++]; - let UserDefinedPartitioningType = tape[ptr++]; - return new IfcWindowType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, PartitioningType, ParameterTakesPrecedence, UserDefinedPartitioningType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ApplicableOccurrence); - args.push(this.HasPropertySets); - args.push(this.RepresentationMaps); - args.push(this.Tag); - args.push(this.ElementType); - args.push(this.PredefinedType); - args.push(this.PartitioningType); - args.push(this.ParameterTakesPrecedence); - args.push(this.UserDefinedPartitioningType); - return args; - } -}; -var IfcWorkCalendar = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, WorkingTimes, ExceptionTimes, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.WorkingTimes = WorkingTimes; - this.ExceptionTimes = ExceptionTimes; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let WorkingTimes = tape[ptr++]; - let ExceptionTimes = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWorkCalendar(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, WorkingTimes, ExceptionTimes, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.WorkingTimes); - args.push(this.ExceptionTimes); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWorkControl = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.CreationDate = CreationDate; - this.Creators = Creators; - this.Purpose = Purpose; - this.Duration = Duration; - this.TotalFloat = TotalFloat; - this.StartTime = StartTime; - this.FinishTime = FinishTime; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let CreationDate = tape[ptr++]; - let Creators = tape[ptr++]; - let Purpose = tape[ptr++]; - let Duration = tape[ptr++]; - let TotalFloat = tape[ptr++]; - let StartTime = tape[ptr++]; - let FinishTime = tape[ptr++]; - return new IfcWorkControl(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.CreationDate); - args.push(this.Creators); - args.push(this.Purpose); - args.push(this.Duration); - args.push(this.TotalFloat); - args.push(this.StartTime); - args.push(this.FinishTime); - return args; - } -}; -var IfcWorkPlan = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.CreationDate = CreationDate; - this.Creators = Creators; - this.Purpose = Purpose; - this.Duration = Duration; - this.TotalFloat = TotalFloat; - this.StartTime = StartTime; - this.FinishTime = FinishTime; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let CreationDate = tape[ptr++]; - let Creators = tape[ptr++]; - let Purpose = tape[ptr++]; - let Duration = tape[ptr++]; - let TotalFloat = tape[ptr++]; - let StartTime = tape[ptr++]; - let FinishTime = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWorkPlan(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.CreationDate); - args.push(this.Creators); - args.push(this.Purpose); - args.push(this.Duration); - args.push(this.TotalFloat); - args.push(this.StartTime); - args.push(this.FinishTime); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWorkSchedule = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.Identification = Identification; - this.CreationDate = CreationDate; - this.Creators = Creators; - this.Purpose = Purpose; - this.Duration = Duration; - this.TotalFloat = TotalFloat; - this.StartTime = StartTime; - this.FinishTime = FinishTime; - this.PredefinedType = PredefinedType; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let Identification = tape[ptr++]; - let CreationDate = tape[ptr++]; - let Creators = tape[ptr++]; - let Purpose = tape[ptr++]; - let Duration = tape[ptr++]; - let TotalFloat = tape[ptr++]; - let StartTime = tape[ptr++]; - let FinishTime = tape[ptr++]; - let PredefinedType = tape[ptr++]; - return new IfcWorkSchedule(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.Identification); - args.push(this.CreationDate); - args.push(this.Creators); - args.push(this.Purpose); - args.push(this.Duration); - args.push(this.TotalFloat); - args.push(this.StartTime); - args.push(this.FinishTime); - args.push(this.PredefinedType); - return args; - } -}; -var IfcWorkTime = class { - constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, RecurrencePattern, Start, Finish) { - this.expressID = expressID; - this.type = type; - this.Name = Name; - this.DataOrigin = DataOrigin; - this.UserDefinedDataOrigin = UserDefinedDataOrigin; - this.RecurrencePattern = RecurrencePattern; - this.Start = Start; - this.Finish = Finish; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let Name = tape[ptr++]; - let DataOrigin = tape[ptr++]; - let UserDefinedDataOrigin = tape[ptr++]; - let RecurrencePattern = tape[ptr++]; - let Start = tape[ptr++]; - let Finish = tape[ptr++]; - return new IfcWorkTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, RecurrencePattern, Start, Finish); - } - ToTape() { - let args = []; - args.push(this.Name); - args.push(this.DataOrigin); - args.push(this.UserDefinedDataOrigin); - args.push(this.RecurrencePattern); - args.push(this.Start); - args.push(this.Finish); - return args; - } -}; -var IfcZShapeProfileDef = class { - constructor(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius) { - this.expressID = expressID; - this.type = type; - this.ProfileType = ProfileType; - this.ProfileName = ProfileName; - this.Position = Position; - this.Depth = Depth; - this.FlangeWidth = FlangeWidth; - this.WebThickness = WebThickness; - this.FlangeThickness = FlangeThickness; - this.FilletRadius = FilletRadius; - this.EdgeRadius = EdgeRadius; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let ProfileType = tape[ptr++]; - let ProfileName = tape[ptr++]; - let Position = tape[ptr++]; - let Depth = tape[ptr++]; - let FlangeWidth = tape[ptr++]; - let WebThickness = tape[ptr++]; - let FlangeThickness = tape[ptr++]; - let FilletRadius = tape[ptr++]; - let EdgeRadius = tape[ptr++]; - return new IfcZShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius); - } - ToTape() { - let args = []; - args.push(this.ProfileType); - args.push(this.ProfileName); - args.push(this.Position); - args.push(this.Depth); - args.push(this.FlangeWidth); - args.push(this.WebThickness); - args.push(this.FlangeThickness); - args.push(this.FilletRadius); - args.push(this.EdgeRadius); - return args; - } -}; -var IfcZone = class { - constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName) { - this.expressID = expressID; - this.type = type; - this.GlobalId = GlobalId; - this.OwnerHistory = OwnerHistory; - this.Name = Name; - this.Description = Description; - this.ObjectType = ObjectType; - this.LongName = LongName; - } - static FromTape(expressID, type, tape) { - let ptr = 0; - let GlobalId = tape[ptr++]; - let OwnerHistory = tape[ptr++]; - let Name = tape[ptr++]; - let Description = tape[ptr++]; - let ObjectType = tape[ptr++]; - let LongName = tape[ptr++]; - return new IfcZone(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName); - } - ToTape() { - let args = []; - args.push(this.GlobalId); - args.push(this.OwnerHistory); - args.push(this.Name); - args.push(this.Description); - args.push(this.ObjectType); - args.push(this.LongName); - return args; - } -}; - -// dist/helpers/ifc-elements.ts -var IfcElements2 = { - 103090709: "IFCPROJECT", - 4097777520: "IFCSITE", - 4031249490: "IFCBUILDING", - 3124254112: "IFCBUILDINGSTOREY", - 3856911033: "IFCSPACE", - 1674181508: "IFCANNOTATION", - 25142252: "IFCCONTROLLER", - 32344328: "IFCBOILER", - 76236018: "IFCLAMP", - 90941305: "IFCPUMP", - 177149247: "IFCAIRTERMINALBOX", - 182646315: "IFCFLOWINSTRUMENT", - 263784265: "IFCFURNISHINGELEMENT", - 264262732: "IFCELECTRICGENERATOR", - 277319702: "IFCAUDIOVISUALAPPLIANCE", - 310824031: "IFCPIPEFITTING", - 331165859: "IFCSTAIR", - 342316401: "IFCDUCTFITTING", - 377706215: "IFCMECHANICALFASTENER", - 395920057: "IFCDOOR", - 402227799: "IFCELECTRICMOTOR", - 413509423: "IFCSYSTEMFURNITUREELEMENT", - 484807127: "IFCEVAPORATOR", - 486154966: "IFCWINDOWSTANDARDCASE", - 629592764: "IFCLIGHTFIXTURE", - 630975310: "IFCUNITARYCONTROLELEMENT", - 635142910: "IFCCABLECARRIERFITTING", - 639361253: "IFCCOIL", - 647756555: "IFCFASTENER", - 707683696: "IFCFLOWSTORAGEDEVICE", - 738039164: "IFCPROTECTIVEDEVICE", - 753842376: "IFCBEAM", - 812556717: "IFCTANK", - 819412036: "IFCFILTER", - 843113511: "IFCCOLUMN", - 862014818: "IFCELECTRICDISTRIBUTIONBOARD", - 900683007: "IFCFOOTING", - 905975707: "IFCCOLUMNSTANDARDCASE", - 926996030: "IFCVOIDINGFEATURE", - 979691226: "IFCREINFORCINGBAR", - 987401354: "IFCFLOWSEGMENT", - 1003880860: "IFCELECTRICTIMECONTROL", - 1051757585: "IFCCABLEFITTING", - 1052013943: "IFCDISTRIBUTIONCHAMBERELEMENT", - 1062813311: "IFCDISTRIBUTIONCONTROLELEMENT", - 1073191201: "IFCMEMBER", - 1095909175: "IFCBUILDINGELEMENTPROXY", - 1156407060: "IFCPLATESTANDARDCASE", - 1162798199: "IFCSWITCHINGDEVICE", - 1329646415: "IFCSHADINGDEVICE", - 1335981549: "IFCDISCRETEACCESSORY", - 1360408905: "IFCDUCTSILENCER", - 1404847402: "IFCSTACKTERMINAL", - 1426591983: "IFCFIRESUPPRESSIONTERMINAL", - 1437502449: "IFCMEDICALDEVICE", - 1509553395: "IFCFURNITURE", - 1529196076: "IFCSLAB", - 1620046519: "IFCTRANSPORTELEMENT", - 1634111441: "IFCAIRTERMINAL", - 1658829314: "IFCENERGYCONVERSIONDEVICE", - 1677625105: "IFCCIVILELEMENT", - 1687234759: "IFCPILE", - 1904799276: "IFCELECTRICAPPLIANCE", - 1911478936: "IFCMEMBERSTANDARDCASE", - 1945004755: "IFCDISTRIBUTIONELEMENT", - 1973544240: "IFCCOVERING", - 1999602285: "IFCSPACEHEATER", - 2016517767: "IFCROOF", - 2056796094: "IFCAIRTOAIRHEATRECOVERY", - 2058353004: "IFCFLOWCONTROLLER", - 2068733104: "IFCHUMIDIFIER", - 2176052936: "IFCJUNCTIONBOX", - 2188021234: "IFCFLOWMETER", - 2223149337: "IFCFLOWTERMINAL", - 2262370178: "IFCRAILING", - 2272882330: "IFCCONDENSER", - 2295281155: "IFCPROTECTIVEDEVICETRIPPINGUNIT", - 2320036040: "IFCREINFORCINGMESH", - 2347447852: "IFCTENDONANCHOR", - 2391383451: "IFCVIBRATIONISOLATOR", - 2391406946: "IFCWALL", - 2474470126: "IFCMOTORCONNECTION", - 2769231204: "IFCVIRTUALELEMENT", - 2814081492: "IFCENGINE", - 2906023776: "IFCBEAMSTANDARDCASE", - 2938176219: "IFCBURNER", - 2979338954: "IFCBUILDINGELEMENTPART", - 3024970846: "IFCRAMP", - 3026737570: "IFCTUBEBUNDLE", - 3027962421: "IFCSLABSTANDARDCASE", - 3040386961: "IFCDISTRIBUTIONFLOWELEMENT", - 3053780830: "IFCSANITARYTERMINAL", - 3079942009: "IFCOPENINGSTANDARDCASE", - 3087945054: "IFCALARM", - 3101698114: "IFCSURFACEFEATURE", - 3127900445: "IFCSLABELEMENTEDCASE", - 3132237377: "IFCFLOWMOVINGDEVICE", - 3171933400: "IFCPLATE", - 3221913625: "IFCCOMMUNICATIONSAPPLIANCE", - 3242481149: "IFCDOORSTANDARDCASE", - 3283111854: "IFCRAMPFLIGHT", - 3296154744: "IFCCHIMNEY", - 3304561284: "IFCWINDOW", - 3310460725: "IFCELECTRICFLOWSTORAGEDEVICE", - 3319311131: "IFCHEATEXCHANGER", - 3415622556: "IFCFAN", - 3420628829: "IFCSOLARDEVICE", - 3493046030: "IFCGEOGRAPHICELEMENT", - 3495092785: "IFCCURTAINWALL", - 3508470533: "IFCFLOWTREATMENTDEVICE", - 3512223829: "IFCWALLSTANDARDCASE", - 3518393246: "IFCDUCTSEGMENT", - 3571504051: "IFCCOMPRESSOR", - 3588315303: "IFCOPENINGELEMENT", - 3612865200: "IFCPIPESEGMENT", - 3640358203: "IFCCOOLINGTOWER", - 3651124850: "IFCPROJECTIONELEMENT", - 3694346114: "IFCOUTLET", - 3747195512: "IFCEVAPORATIVECOOLER", - 3758799889: "IFCCABLECARRIERSEGMENT", - 3824725483: "IFCTENDON", - 3825984169: "IFCTRANSFORMER", - 3902619387: "IFCCHILLER", - 4074379575: "IFCDAMPER", - 4086658281: "IFCSENSOR", - 4123344466: "IFCELEMENTASSEMBLY", - 4136498852: "IFCCOOLEDBEAM", - 4156078855: "IFCWALLELEMENTEDCASE", - 4175244083: "IFCINTERCEPTOR", - 4207607924: "IFCVALVE", - 4217484030: "IFCCABLESEGMENT", - 4237592921: "IFCWASTETERMINAL", - 4252922144: "IFCSTAIRFLIGHT", - 4278956645: "IFCFLOWFITTING", - 4288193352: "IFCACTUATOR", - 4292641817: "IFCUNITARYEQUIPMENT", - 3009204131: "IFCGRID" -}; - -// dist/helpers/properties.ts -var PropsNames = { - aggregates: { - name: IFCRELAGGREGATES, - relating: "RelatingObject", - related: "RelatedObjects", - key: "children" - }, - spatial: { - name: IFCRELCONTAINEDINSPATIALSTRUCTURE, - relating: "RelatingStructure", - related: "RelatedElements", - key: "children" - }, - psets: { - name: IFCRELDEFINESBYPROPERTIES, - relating: "RelatingPropertyDefinition", - related: "RelatedObjects", - key: "hasPsets" - }, - materials: { - name: IFCRELASSOCIATESMATERIAL, - relating: "RelatingMaterial", - related: "RelatedObjects", - key: "hasMaterial" - }, - type: { - name: IFCRELDEFINESBYTYPE, - relating: "RelatingType", - related: "RelatedObjects", - key: "hasType" - } -}; -var Properties = class { - constructor(api) { - this.api = api; - } - getItemProperties(modelID, id, recursive = false) { - return __async(this, null, function* () { - return this.api.GetLine(modelID, id, recursive); - }); - } - getPropertySets(modelID, elementID, recursive = false) { - return __async(this, null, function* () { - return yield this.getProperty(modelID, elementID, recursive, PropsNames.psets); - }); - } - getTypeProperties(modelID, elementID, recursive = false) { - return __async(this, null, function* () { - return yield this.getProperty(modelID, elementID, recursive, PropsNames.type); - }); - } - getMaterialsProperties(modelID, elementID, recursive = false) { - return __async(this, null, function* () { - return yield this.getProperty(modelID, elementID, recursive, PropsNames.materials); - }); - } - getSpatialStructure(modelID, includeProperties) { - return __async(this, null, function* () { - yield this.getAllTypesOfModel(modelID); - const chunks = yield this.getSpatialTreeChunks(modelID); - const allLines = yield this.api.GetLineIDsWithType(modelID, IFCPROJECT); - const projectID = allLines.get(0); - const project = Properties.newIfcProject(projectID); - yield this.getSpatialNode(modelID, project, chunks, includeProperties); - this.cleanupTypes(); - return project; - }); - } - getAllItemsOfType(modelID, type, verbose) { - return __async(this, null, function* () { - let items = []; - const lines = yield this.api.GetLineIDsWithType(modelID, type); - for (let i = 0; i < lines.size(); i++) - items.push(lines.get(i)); - if (!verbose) - return items; - const result = []; - for (let i = 0; i < items.length; i++) { - result.push(yield this.api.GetLine(modelID, items[i])); - } - return result; - }); - } - getProperty(modelID, elementID, recursive = false, propName) { - return __async(this, null, function* () { - const propSetIds = yield this.getAllRelatedItemsOfType(modelID, elementID, propName); - const result = []; - for (let i = 0; i < propSetIds.length; i++) { - result.push(yield this.api.GetLine(modelID, propSetIds[i], recursive)); - } - return result; - }); - } - getChunks(modelID, chunks, propNames) { - return __async(this, null, function* () { - const relation = yield this.api.GetLineIDsWithType(modelID, propNames.name); - for (let i = 0; i < relation.size(); i++) { - const rel = yield this.api.GetLine(modelID, relation.get(i), false); - this.saveChunk(chunks, propNames, rel); - } - }); - } - static isRelated(id, rel, propNames) { - const relatedItems = rel[propNames.related]; - if (Array.isArray(relatedItems)) { - const values = relatedItems.map((item) => item.value); - return values.includes(id); - } - return relatedItems.value === id; - } - static newIfcProject(id) { - return { - expressID: id, - type: "IFCPROJECT", - children: [] - }; - } - getSpatialNode(modelID, node, treeChunks, includeProperties) { - return __async(this, null, function* () { - yield this.getChildren(modelID, node, treeChunks, PropsNames.aggregates, includeProperties); - yield this.getChildren(modelID, node, treeChunks, PropsNames.spatial, includeProperties); - }); - } - getChildren(modelID, node, treeChunks, propNames, includeProperties) { - return __async(this, null, function* () { - const children = treeChunks[node.expressID]; - if (children == void 0) - return; - const prop = propNames.key; - const nodes = []; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - let node2 = this.newNode(child); - if (includeProperties) { - const properties = yield this.getItemProperties(modelID, node2.expressID); - node2 = __spreadValues(__spreadValues({}, properties), node2); - } - yield this.getSpatialNode(modelID, node2, treeChunks, includeProperties); - nodes.push(node2); - } - node[prop] = nodes; - }); - } - newNode(id) { - const typeName = this.getNodeType(id); - return { - expressID: id, - type: typeName, - children: [] - }; - } - getNodeType(id) { - const typeID = this.types[id]; - return IfcElements2[typeID]; - } - getSpatialTreeChunks(modelID) { - return __async(this, null, function* () { - const treeChunks = {}; - yield this.getChunks(modelID, treeChunks, PropsNames.aggregates); - yield this.getChunks(modelID, treeChunks, PropsNames.spatial); - return treeChunks; - }); - } - saveChunk(chunks, propNames, rel) { - const relating = rel[propNames.relating].value; - const related = rel[propNames.related].map((r) => r.value); - if (chunks[relating] == void 0) { - chunks[relating] = related; - } else { - chunks[relating] = chunks[relating].concat(related); - } - } - getRelated(rel, propNames, IDs) { - const element = rel[propNames.relating]; - if (!Array.isArray(element)) - IDs.push(element.value); - else - element.forEach((ele) => IDs.push(ele.value)); - } - getAllRelatedItemsOfType(modelID, id, propNames) { - return __async(this, null, function* () { - const lines = yield this.api.GetLineIDsWithType(modelID, propNames.name); - const IDs = []; - for (let i = 0; i < lines.size(); i++) { - const rel = yield this.api.GetLine(modelID, lines.get(i)); - const isRelated = Properties.isRelated(id, rel, propNames); - if (isRelated) - this.getRelated(rel, propNames, IDs); - } - return IDs; - }); - } - cleanupTypes() { - this.types = {}; - } - getAllTypesOfModel(modelID) { - return __async(this, null, function* () { - const result = {}; - const elements = Object.keys(IfcElements2).map((e) => parseInt(e)); - for (let i = 0; i < elements.length; i++) { - const element = elements[i]; - const lines = yield this.api.GetLineIDsWithType(modelID, element); - const size = lines.size(); - for (let i2 = 0; i2 < size; i2++) - result[lines.get(i2)] = element; - } - this.types = result; - }); - } -}; - -// dist/web-ifc-api.ts -var WebIFCWasm; -if (typeof self !== "undefined" && self.crossOriginIsolated) { - WebIFCWasm = require_web_ifc_mt(); -} else { - WebIFCWasm = require_web_ifc(); -} -var IfcAPI2 = class { - constructor() { - this.wasmModule = void 0; - this.fs = void 0; - this.wasmPath = ""; - this.ifcGuidMap = new Map(); - this.properties = new Properties(this); - } - Init(customLocateFileHandler) { - return __async(this, null, function* () { - if (WebIFCWasm) { - let locateFileHandler = (path, prefix) => { - if (path.endsWith(".wasm")) { - return prefix + this.wasmPath + path; - } - return prefix + path; - }; - this.wasmModule = yield WebIFCWasm({ noInitialRun: true, locateFile: customLocateFileHandler || locateFileHandler }); - this.fs = this.wasmModule.FS; - } else { - console.error(`Could not find wasm module at './web-ifc' from web-ifc-api.ts`); - } - }); - } - OpenModel(data, settings) { - let s = __spreadValues({ - COORDINATE_TO_ORIGIN: false, - USE_FAST_BOOLS: false, - CIRCLE_SEGMENTS_LOW: 5, - CIRCLE_SEGMENTS_MEDIUM: 8, - CIRCLE_SEGMENTS_HIGH: 12, - BOOL_ABORT_THRESHOLD: 1e4 - }, settings); - let offsetInSrc = 0; - let result = this.wasmModule.OpenModel(s, (destPtr, destSize) => { - let srcSize = Math.min(data.byteLength - offsetInSrc, destSize); - let dest = this.wasmModule.HEAPU8.subarray(destPtr, destPtr + destSize); - let src = data.subarray(offsetInSrc, offsetInSrc + srcSize); - dest.set(src); - offsetInSrc += srcSize; - return srcSize; - }); - return result; - } - CreateModel(settings) { - let s = __spreadValues({ - COORDINATE_TO_ORIGIN: false, - USE_FAST_BOOLS: false, - CIRCLE_SEGMENTS_LOW: 5, - CIRCLE_SEGMENTS_MEDIUM: 8, - CIRCLE_SEGMENTS_HIGH: 12, - BOOL_ABORT_THRESHOLD: 1e4 - }, settings); - let result = this.wasmModule.CreateModel(s); - return result; - } - ExportFileAsIFC(modelID) { - this.wasmModule.ExportFileAsIFC(modelID); - let result = this.fs.readFile("/export.ifc"); - this.wasmModule["FS_unlink"]("/export.ifc"); - return result; - } - GetGeometry(modelID, geometryExpressID) { - return this.wasmModule.GetGeometry(modelID, geometryExpressID); - } - GetLine(modelID, expressID, flatten = false) { - let rawLineData = this.GetRawLineData(modelID, expressID); - let lineData = FromRawLineData[rawLineData.type](rawLineData); - if (flatten) { - this.FlattenLine(modelID, lineData); - } - return lineData; - } - GetAndClearErrors(modelID) { - return this.wasmModule.GetAndClearErrors(modelID); - } - WriteLine(modelID, lineObject) { - Object.keys(lineObject).forEach((propertyName) => { - let property = lineObject[propertyName]; - if (property && property.expressID !== void 0) { - this.WriteLine(modelID, property); - lineObject[propertyName] = { - type: 5, - value: property.expressID - }; - } else if (Array.isArray(property) && property.length > 0) { - for (let i = 0; i < property.length; i++) { - if (property[i].expressID !== void 0) { - this.WriteLine(modelID, property[i]); - lineObject[propertyName][i] = { - type: 5, - value: property[i].expressID - }; - } - } - } - }); - let rawLineData = { - ID: lineObject.expressID, - type: lineObject.type, - arguments: lineObject.ToTape() - }; - this.WriteRawLineData(modelID, rawLineData); - } - FlattenLine(modelID, line) { - Object.keys(line).forEach((propertyName) => { - let property = line[propertyName]; - if (property && property.type === 5) { - line[propertyName] = this.GetLine(modelID, property.value, true); - } else if (Array.isArray(property) && property.length > 0 && property[0].type === 5) { - for (let i = 0; i < property.length; i++) { - line[propertyName][i] = this.GetLine(modelID, property[i].value, true); - } - } - }); - } - GetRawLineData(modelID, expressID) { - return this.wasmModule.GetLine(modelID, expressID); - } - WriteRawLineData(modelID, data) { - return this.wasmModule.WriteLine(modelID, data.ID, data.type, data.arguments); - } - GetLineIDsWithType(modelID, type) { - return this.wasmModule.GetLineIDsWithType(modelID, type); - } - GetAllLines(modelID) { - return this.wasmModule.GetAllLines(modelID); - } - SetGeometryTransformation(modelID, transformationMatrix) { - if (transformationMatrix.length != 16) { - console.log(`Bad transformation matrix size: ${transformationMatrix.length}`); - return; - } - this.wasmModule.SetGeometryTransformation(modelID, transformationMatrix); - } - GetCoordinationMatrix(modelID) { - return this.wasmModule.GetCoordinationMatrix(modelID); - } - GetVertexArray(ptr, size) { - return this.getSubArray(this.wasmModule.HEAPF32, ptr, size); - } - GetIndexArray(ptr, size) { - return this.getSubArray(this.wasmModule.HEAPU32, ptr, size); - } - getSubArray(heap, startPtr, sizeBytes) { - return heap.subarray(startPtr / 4, startPtr / 4 + sizeBytes).slice(0); - } - CloseModel(modelID) { - this.ifcGuidMap.delete(modelID); - this.wasmModule.CloseModel(modelID); - } - StreamAllMeshes(modelID, meshCallback) { - this.wasmModule.StreamAllMeshes(modelID, meshCallback); - } - StreamAllMeshesWithTypes(modelID, types, meshCallback) { - this.wasmModule.StreamAllMeshesWithTypes(modelID, types, meshCallback); - } - IsModelOpen(modelID) { - return this.wasmModule.IsModelOpen(modelID); - } - LoadAllGeometry(modelID) { - return this.wasmModule.LoadAllGeometry(modelID); - } - GetFlatMesh(modelID, expressID) { - return this.wasmModule.GetFlatMesh(modelID, expressID); - } - CreateIfcGuidToExpressIdMapping(modelID) { - const map = new Map(); - for (let x = 0; x < IfcElements.length; x++) { - const type = IfcElements[x]; - const lines = this.GetLineIDsWithType(modelID, type); - const size = lines.size(); - for (let y = 0; y < size; y++) { - const expressID = lines.get(y); - const info = this.GetLine(modelID, expressID); - const globalID = info.GlobalId.value; - map.set(expressID, globalID); - map.set(globalID, expressID); - } - } - this.ifcGuidMap.set(modelID, map); - } - SetWasmPath(path) { - this.wasmPath = path; - } -}; - -/** - * Default data access strategy for {@link WebIFCLoaderPlugin}. - */ -class WebIFCDefaultDataSource { - - constructor() { - } - - /** - * Gets the contents of the given IFC file in an arraybuffer. - * - * @param {String|Number} src Path or ID of an IFC file. - * @param {Function} ok Callback fired on success, argument is the IFC file in an arraybuffer. - * @param {Function} error Callback fired on error. - */ - getIFC(src, ok, error) { - var defaultCallback = () => { - }; - ok = ok || defaultCallback; - error = error || defaultCallback; - const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; - const dataUriRegexResult = src.match(dataUriRegex); - if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest - const isBase64 = !!dataUriRegexResult[2]; - var data = dataUriRegexResult[3]; - data = window.decodeURIComponent(data); - if (isBase64) { - data = window.atob(data); - } - try { - const buffer = new ArrayBuffer(data.length); - const view = new Uint8Array(buffer); - for (var i = 0; i < data.length; i++) { - view[i] = data.charCodeAt(i); - } - ok(buffer); - } catch (errMsg) { - error(errMsg); - } - } else { - const request = new XMLHttpRequest(); - request.open('GET', src, true); - request.responseType = 'arraybuffer'; - request.onreadystatechange = function () { - if (request.readyState === 4) { - if (request.status === 200) { - ok(request.response); - } else { - error('getXKT error : ' + request.response); - } - } - }; - request.send(null); - } - } -} - -/** - * @desc Localization service for a {@link Viewer}. - * - * * A LocaleService is a container of string translations ("messages") for various locales. - * * A {@link Viewer} has its own default LocaleService at {@link Viewer#localeService}. - * * We can replace that with our own LocaleService, or a custom subclass, via the Viewer's constructor. - * * Viewer plugins that need localized translations will attempt to them for the currently active locale from the LocaleService. - * * Whenever we switch the LocaleService to a different locale, plugins will automatically refresh their translations for that locale. - * - * ## Usage - * - * In the example below, we'll create a {@link Viewer} that uses an {@link XKTLoaderPlugin} to load a BIM model, and a - * {@link NavCubePlugin}, which shows a camera navigation cube in the corner of the canvas. - * - * We'll also configure our Viewer with our own LocaleService instance, configured with English, Māori and French - * translations for our NavCubePlugin. - * - * We could instead have just used the Viewer's default LocaleService, but this example demonstrates how we might - * configure the Viewer our own custom LocaleService subclass. - * - * The translations fetched by our NavCubePlugin will be: - * - * * "NavCube.front" - * * "NavCube.back" - * * "NavCube.top" - * * "NavCube.bottom" - * * "NavCube.left" - * * "NavCube.right" - * - *
    - * These are paths that resolve to our translations for the currently active locale, and are hard-coded within - * the NavCubePlugin. - * - * For example, if the LocaleService's locale is set to "fr", then the path "NavCube.back" will drill down - * into ````messages->fr->NavCube->front```` and fetch "Arrière". - * - * If we didn't provide that particular translation in our LocaleService, or any translations for that locale, - * then the NavCubePlugin will just fall back on its own default hard-coded translation, which in this case is "BACK". - * - * [[Run example](https://xeokit.github.io/xeokit-sdk/examples/#localization_NavCubePlugin)] - * - * ````javascript - * import {Viewer, LocaleService, NavCubePlugin, XKTLoaderPlugin} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * - * canvasId: "myCanvas", - * - * localeService: new LocaleService({ - * messages: { - * "en": { // English - * "NavCube": { - * "front": "Front", - * "back": "Back", - * "top": "Top", - * "bottom": "Bottom", - * "left": "Left", - * "right": "Right" - * } - * }, - * "mi": { // Māori - * "NavCube": { - * "front": "Mua", - * "back": "Tuarā", - * "top": "Runga", - * "bottom": "Raro", - * "left": "Mauī", - * "right": "Tika" - * } - * }, - * "fr": { // Francais - * "NavCube": { - * "front": "Avant", - * "back": "Arrière", - * "top": "Supérieur", - * "bottom": "Inférieur", - * "left": "Gauche", - * "right": "Droit" - * } - * } - * }, - * locale: "en" - * }) - * }); - * - * viewer.camera.eye = [-3.93, 2.85, 27.01]; - * viewer.camera.look = [4.40, 3.72, 8.89]; - * viewer.camera.up = [-0.01, 0.99, 0.03]; - * - * const navCubePlugin = new NavCubePlugin(viewer, { - * canvasID: "myNavCubeCanvas" - * }); - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/Duplex.ifc.xkt", - * edges: true - * }); - * ```` - * - * We can dynamically switch our Viewer to a different locale at any time, which will update the text on the - * faces of our NavCube: - * - * ````javascript - * viewer.localeService.locale = "mi"; // Switch to Māori - * ```` - * - * We can load new translations at any time: - * - * ````javascript - * viewer.localeService.loadMessages({ - * "jp": { // Japanese - * "NavCube": { - * "front": "前部", - * "back": "裏", - * "top": "上", - * "bottom": "底", - * "left": "左", - * "right": "右" - * } - * } - * }); - * ```` - * - * And we can clear the translations if needed: - * - * ````javascript - * viewer.localeService.clearMessages(); - * ```` - * - * We can get an "updated" event from the LocaleService whenever we switch locales or load messages, which is useful - * for triggering UI elements to refresh themselves with updated translations. Internally, our {@link NavCubePlugin} - * subscribes to this event, fetching new strings for itself via {@link LocaleService#translate} each time the - * event is fired. - * - * ````javascript - * viewer.localeService.on("updated", () => { - * console.log( viewer.localeService.translate("NavCube.left") ); - * }); - * ```` - * @since 2.0 - */ -class LocaleService { - - /** - * Constructs a LocaleService. - * - * @param {*} [params={}] - * @param {JSON} [params.messages] - * @param {String} [params.locale] - */ - constructor(params = {}) { - - this._eventSubIDMap = null; - this._eventSubEvents = null; - this._eventSubs = null; - this._events = null; - - this._locale = "en"; - this._messages = {}; - this._locales = []; - this._locale = "en"; - - this.messages = params.messages; - this.locale = params.locale; - } - - /** - * Replaces the current set of locale translations. - * - * * Fires an "updated" event when done. - * * Automatically refreshes any plugins that depend on the translations. - * * Does not change the current locale. - * - * ## Usage - * - * ````javascript - * viewer.localeService.setMessages({ - * messages: { - * "en": { // English - * "NavCube": { - * "front": "Front", - * "back": "Back", - * "top": "Top", - * "bottom": "Bottom", - * "left": "Left", - * "right": "Right" - * } - * }, - * "mi": { // Māori - * "NavCube": { - * "front": "Mua", - * "back": "Tuarā", - * "top": "Runga", - * "bottom": "Raro", - * "left": "Mauī", - * "right": "Tika" - * } - * } - * } - * }); - * ```` - * - * @param {*} messages The new translations. - */ - set messages(messages) { - this._messages = messages || {}; - this._locales = Object.keys(this._messages); - this.fire("updated", this); - } - - /** - * Loads a new set of locale translations, adding them to the existing translations. - * - * * Fires an "updated" event when done. - * * Automatically refreshes any plugins that depend on the translations. - * * Does not change the current locale. - * - * ## Usage - * - * ````javascript - * viewer.localeService.loadMessages({ - * "jp": { // Japanese - * "NavCube": { - * "front": "前部", - * "back": "裏", - * "top": "上", - * "bottom": "底", - * "left": "左", - * "right": "右" - * } - * } - * }); - * ```` - * - * @param {*} messages The new translations. - */ - loadMessages(messages = {}) { - for (let locale in messages) { - this._messages[locale] = messages[locale]; - } - this.messages = this._messages; - } - - /** - * Clears all locale translations. - * - * * Fires an "updated" event when done. - * * Does not change the current locale. - * * Automatically refreshes any plugins that depend on the translations, which will cause those - * plugins to fall back on their internal hard-coded text values, since this method removes all - * our translations. - */ - clearMessages() { - this.messages = {}; - } - - /** - * Gets the list of available locales. - * - * These are derived from the currently configured set of translations. - * - * @returns {String[]} The list of available locales. - */ - get locales() { - return this._locales; - } - - /** - * Sets the current locale. - * - * * Fires an "updated" event when done. - * * The given locale does not need to be in the list of available locales returned by {@link LocaleService#locales}, since - * this method assumes that you may want to load the locales at a later point. - * * Automatically refreshes any plugins that depend on the translations. - * * We can then get translations for the locale, if translations have been loaded for it, via {@link LocaleService#translate} and {@link LocaleService#translatePlurals}. - * - * @param {String} locale The new current locale. - */ - set locale(locale) { - locale = locale || "de"; - if (this._locale === locale) { - return; - } - this._locale = locale; - this.fire("updated", locale); - } - - /** - * Gets the current locale. - * - * @returns {String} The current locale. - */ - get locale() { - return this._locale; - } - - /** - * Translates the given string according to the current locale. - * - * Returns null if no translation can be found. - * - * @param {String} msg String to translate. - * @param {*} [args] Extra parameters. - * @returns {String|null} Translated string if found, else null. - */ - translate(msg, args) { - const localeMessages = this._messages[this._locale]; - if (!localeMessages) { - return null; - } - const localeMessage = resolvePath(msg, localeMessages); - if (localeMessage) { - if (args) { - return vsprintf(localeMessage, args); - } - return localeMessage; - } - return null; - } - - /** - * Translates the given phrase according to the current locale. - * - * Returns null if no translation can be found. - * - * @param {String} msg Phrase to translate. - * @param {Number} count The plural number. - * @param {*} [args] Extra parameters. - * @returns {String|null} Translated string if found, else null. - */ - translatePlurals(msg, count, args) { - const localeMessages = this._messages[this._locale]; - if (!localeMessages) { - return null; - } - let localeMessage = resolvePath(msg, localeMessages); - count = parseInt("" + count, 10); - if (count === 0) { - localeMessage = localeMessage.zero; - } else { - localeMessage = (count > 1) ? localeMessage.other : localeMessage.one; - } - if (!localeMessage) { - return null; - } - localeMessage = vsprintf(localeMessage, [count]); - if (args) { - localeMessage = vsprintf(localeMessage, args); - } - return localeMessage; - } - - /** - * Fires an event on this LocaleService. - * - * Notifies existing subscribers to the event, optionally retains the event to give to - * any subsequent notifications on the event as they are made. - * - * @param {String} event The event type name. - * @param {Object} value The event parameters. - * @param {Boolean} [forget=false] When true, does not retain for subsequent subscribers. - */ - fire(event, value, forget) { - if (!this._events) { - this._events = {}; - } - if (!this._eventSubs) { - this._eventSubs = {}; - } - if (forget !== true) { - this._events[event] = value || true; // Save notification - } - const subs = this._eventSubs[event]; - if (subs) { - for (const subId in subs) { - if (subs.hasOwnProperty(subId)) { - const sub = subs[subId]; - sub.callback(value); - } - } - } - } - - /** - * Subscribes to an event on this LocaleService. - * - * @param {String} event The event - * @param {Function} callback Callback fired on the event - * @return {String} Handle to the subscription, which may be used to unsubscribe with {@link #off}. - */ - on(event, callback) { - if (!this._events) { - this._events = {}; - } - if (!this._eventSubIDMap) { - this._eventSubIDMap = new Map$1(); // Subscription subId pool - } - if (!this._eventSubEvents) { - this._eventSubEvents = {}; - } - if (!this._eventSubs) { - this._eventSubs = {}; - } - let subs = this._eventSubs[event]; - if (!subs) { - subs = {}; - this._eventSubs[event] = subs; - } - const subId = this._eventSubIDMap.addItem(); // Create unique subId - subs[subId] = { - callback: callback - }; - this._eventSubEvents[subId] = event; - const value = this._events[event]; - if (value !== undefined) { - callback(value); - } - return subId; - } - - /** - * Cancels an event subscription that was previously made with {@link LocaleService#on}. - * - * @param {String} subId Subscription ID - */ - off(subId) { - if (subId === undefined || subId === null) { - return; - } - if (!this._eventSubEvents) { - return; - } - const event = this._eventSubEvents[subId]; - if (event) { - delete this._eventSubEvents[subId]; - const subs = this._eventSubs[event]; - if (subs) { - delete subs[subId]; - } - this._eventSubIDMap.removeItem(subId); // Release subId - } - } -} - -function resolvePath(key, json) { - if (json[key]) { - return json[key]; - } - const parts = key.split("."); - let obj = json; - for (let i = 0, len = parts.length; obj && (i < len); i++) { - const part = parts[i]; - obj = obj[part]; - } - return obj; -} - -function vsprintf(msg, args = []) { - return msg.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) { - if (m === "{{") { - return "{"; - } - if (m === "}}") { - return "}"; - } - return args[n]; - }); -} - -/** - * @desc Abstract base class for curve classes. - */ -class Curve extends Component { - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this Curve as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Curve}, generated automatically when omitted. - * @param {Object} [cfg] Configs for this Curve. - * @param {Number} [cfg.t=0] Current position on this Curve, in range between ````0..1````. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this.t = cfg.t; - } - - /** - * Sets the progress along this Curve. - * - * Automatically clamps to range ````[0..1]````. - * - * Default value is ````0````. - * - * @param {Number} value The progress value. - */ - set t(value) { - value = value || 0; - this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); - } - - /** - * Gets the progress along this Curve. - * - * @returns {Number} The progress value. - */ - get t() { - return this._t; - } - - /** - * Gets the tangent on this Curve at position {@link Curve#t}. - * - * @returns {Number[]} The tangent. - */ - get tangent() { - return this.getTangent(this._t); - } - - /** - * Gets the length of this Curve. - * - * @returns {Number} The Curve length. - */ - get length() { - var lengths = this._getLengths(); - return lengths[lengths.length - 1]; - } - - /** - * Returns a normalized tangent vector on this Curve at the given position. - * - * @param {Number} t Position to get tangent at. - * @returns {Number[]} Normalized tangent vector - */ - getTangent(t) { - var delta = 0.0001; - if (t === undefined) { - t = this._t; - } - var t1 = t - delta; - var t2 = t + delta; - if (t1 < 0) { - t1 = 0; - } - if (t2 > 1) { - t2 = 1; - } - var pt1 = this.getPoint(t1); - var pt2 = this.getPoint(t2); - var vec = math.subVec3(pt2, pt1, []); - return math.normalizeVec3(vec, []); - } - - getPointAt(u) { - var t = this.getUToTMapping(u); - return this.getPoint(t); - } - - /** - * Samples points on this Curve, at the given number of equally-spaced divisions. - * - * @param {Number} divisions The number of divisions. - * @returns {{Array of Array}} Array of sampled 3D points. - */ - getPoints(divisions) { - if (!divisions) { - divisions = 5; - } - var d, pts = []; - for (d = 0; d <= divisions; d++) { - pts.push(this.getPoint(d / divisions)); - } - return pts; - } - - _getLengths(divisions) { - if (!divisions) { - divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions) : 200; - } - if (this.cacheArcLengths && (this.cacheArcLengths.length === divisions + 1) && !this.needsUpdate) { - return this.cacheArcLengths; - - } - this.needsUpdate = false; - var cache = []; - var current; - var last = this.getPoint(0); - var p; - var sum = 0; - cache.push(0); - for (p = 1; p <= divisions; p++) { - current = this.getPoint(p / divisions); - sum += math.lenVec3(math.subVec3(current, last, [])); - cache.push(sum); - last = current; - } - this.cacheArcLengths = cache; - return cache; // { sums: cache, sum:sum }, Sum is in the last element. - } - - _updateArcLengths() { - this.needsUpdate = true; - this._getLengths(); - } - - // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance - - getUToTMapping(u, distance) { - var arcLengths = this._getLengths(); - var i = 0; - var il = arcLengths.length; - var t; - var targetArcLength; // The targeted u distance value to get - if (distance) { - targetArcLength = distance; - } else { - targetArcLength = u * arcLengths[il - 1]; - } - //var time = Date.now(); - var low = 0, high = il - 1, comparison; - while (low <= high) { - i = Math.floor(low + (high - low) / 2); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats - comparison = arcLengths[i] - targetArcLength; - if (comparison < 0) { - low = i + 1; - } else if (comparison > 0) { - high = i - 1; - } else { - high = i; - break; - // DONE - } - } - i = high; - if (arcLengths[i] === targetArcLength) { - t = i / (il - 1); - return t; - } - var lengthBefore = arcLengths[i]; - var lengthAfter = arcLengths[i + 1]; - var segmentLength = lengthAfter - lengthBefore; - var segmentFraction = (targetArcLength - lengthBefore) / segmentLength; - t = (i + segmentFraction) / (il - 1); - return t; - } -} - -/** - * @desc A {@link Curve} along which a 3D position can be animated. - * - * * As shown in the diagram below, a SplineCurve is defined by three or more control points. - * * You can sample a {@link SplineCurve#point} and a {@link Curve#tangent} vector on a SplineCurve for any given value of {@link SplineCurve#t} in the range ````[0..1]````. - * * When you set {@link SplineCurve#t} on a SplineCurve, its {@link SplineCurve#point} and {@link Curve#tangent} will update accordingly. - * * To build a complex path, you can combine an unlimited combination of SplineCurves, {@link CubicBezierCurve} and {@link QuadraticBezierCurve} into a {@link Path}. - *
    - *
    - * - * * Spline Curve from Wikipedia* - */ -class SplineCurve extends Curve { - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this SplineCurve as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Array} [cfg.points=[]] Control points on this SplineCurve. - * @param {Number} [cfg.t=0] Current position on this SplineCurve, in range between 0..1. - * @param {Number} [cfg.t=0] Current position on this CubicBezierCurve, in range between 0..1. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this.points = cfg.points; - this.t = cfg.t; - } - - /** - * Sets the control points on this SplineCurve. - * - * Default value is ````[]````. - * - * @param {Number[]} value New control points. - */ - set points(value) { - this._points = value || []; - } - - /** - * Gets the control points on this SplineCurve. - * - * Default value is ````[]````. - * - * @returns {Number[]} The control points. - */ - get points() { - return this._points; - } - - /** - * Sets the progress along this SplineCurve. - * - * Automatically clamps to range ````[0..1]````. - * - * Default value is ````0````. - * - * @param {Number} value The new progress. - */ - set t(value) { - value = value || 0; - this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); - } - - /** - * Gets the progress along this SplineCurve. - * - * Automatically clamps to range ````[0..1]````. - * - * Default value is ````0````. - * - * @returns {Number} The new progress. - */ - get t() { - return this._t; - } - - /** - * Gets the point on this SplineCurve at position {@link SplineCurve#t}. - * - * @returns {Number[]} The point at {@link SplineCurve#t}. - */ - get point() { - return this.getPoint(this._t); - } - - /** - * Returns point on this SplineCurve at the given position. - * - * @param {Number} t Position to get point at. - * @returns {Number[]} Point at the given position. - */ - getPoint(t) { - - var points = this.points; - - if (points.length < 3) { - this.error("Can't sample point from SplineCurve - not enough points on curve - returning [0,0,0]."); - return; - } - - var point = (points.length - 1) * t; - - var intPoint = Math.floor(point); - var weight = point - intPoint; - - var point0 = points[intPoint === 0 ? intPoint : intPoint - 1]; - var point1 = points[intPoint]; - var point2 = points[intPoint > points.length - 2 ? points.length - 1 : intPoint + 1]; - var point3 = points[intPoint > points.length - 3 ? points.length - 1 : intPoint + 2]; - - var vector = math.vec3(); - - vector[0] = math.catmullRomInterpolate(point0[0], point1[0], point2[0], point3[0], weight); - vector[1] = math.catmullRomInterpolate(point0[1], point1[1], point2[1], point3[1], weight); - vector[2] = math.catmullRomInterpolate(point0[2], point1[2], point2[2], point3[2], weight); - - return vector; - } - - getJSON() { - return { - points: points, - t: this._t - }; - } -} - -const tempVec3a$4 = math.vec3(); - -/** - * @desc Defines a sequence of frames along which a {@link CameraPathAnimation} can animate a {@link Camera}. - * - * See {@link CameraPathAnimation} for usage. - */ -class CameraPath extends Component { - - /** - * Returns "CameraPath". - * - * @private - * - * @returns {string} "CameraPath" - */ - get type() { - return "CameraPath" - } - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this CameraPath as well. - * @param [cfg] {*} Configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {{t:Number, eye:Object, look:Object, up: Object}[]} [cfg.frames] Initial sequence of frames. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - this._frames = []; - - this._eyeCurve = new SplineCurve(this); - this._lookCurve = new SplineCurve(this); - this._upCurve = new SplineCurve(this); - - if (cfg.frames) { - this.addFrames(cfg.frames); - this.smoothFrameTimes(1); - } - } - - /** - * Gets the camera frames in this CameraPath. - * - * @returns {{t:Number, eye:Object, look:Object, up: Object}[]} The frames on this CameraPath. - */ - get frames() { - return this._frames; - } - - /** - * Gets the {@link SplineCurve} along which {@link Camera#eye} travels. - * @returns {SplineCurve} The SplineCurve for {@link Camera#eye}. - */ - get eyeCurve() { - return this._eyeCurve; - } - - /** - * Gets the {@link SplineCurve} along which {@link Camera#look} travels. - * @returns {SplineCurve} The SplineCurve for {@link Camera#look}. - */ - get lookCurve() { - return this._lookCurve; - } - - /** - * Gets the {@link SplineCurve} along which {@link Camera#up} travels. - * @returns {SplineCurve} The SplineCurve for {@link Camera#up}. - */ - get upCurve() { - return this._upCurve; - } - - /** - * Adds a frame to this CameraPath, given as the current position of the {@link Camera}. - * - * @param {Number} t Time instant for the new frame. - */ - saveFrame(t) { - const camera = this.scene.camera; - this.addFrame(t, camera.eye, camera.look, camera.up); - } - - /** - * Adds a frame to this CameraPath, specified as values for eye, look and up vectors at a given time instant. - * - * @param {Number} t Time instant for the new frame. - * @param {Number[]} eye A three-element vector specifying the eye position for the new frame. - * @param {Number[]} look A three-element vector specifying the look position for the new frame. - * @param {Number[]} up A three-element vector specifying the up vector for the new frame. - */ - addFrame(t, eye, look, up) { - const frame = { - t: t, - eye: eye.slice(0), - look: look.slice(0), - up: up.slice(0) - }; - this._frames.push(frame); - this._eyeCurve.points.push(frame.eye); - this._lookCurve.points.push(frame.look); - this._upCurve.points.push(frame.up); - } - - /** - * Adds multiple frames to this CameraPath, each frame specified as a set of values for eye, look and up vectors at a given time instant. - * - * @param {{t:Number, eye:Object, look:Object, up: Object}[]} frames Frames to add to this CameraPath. - */ - addFrames(frames) { - let frame; - for (let i = 0, len = frames.length; i < len; i++) { - frame = frames[i]; - this.addFrame(frame.t || 0, frame.eye, frame.look, frame.up); - } - } - - /** - * Sets the position of the {@link Camera} to a position interpolated within this CameraPath at the given time instant. - * - * @param {Number} t Time instant. - */ - loadFrame(t) { - - const camera = this.scene.camera; - - t = t / (this._frames[this._frames.length - 1].t - this._frames[0].t); - t = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t); - - camera.eye = this._eyeCurve.getPoint(t, tempVec3a$4); - camera.look = this._lookCurve.getPoint(t, tempVec3a$4); - camera.up = this._upCurve.getPoint(t, tempVec3a$4); - } - - /** - * Gets eye, look and up vectors on this CameraPath at a given instant. - * - * @param {Number} t Time instant. - * @param {Number[]} eye The eye position to update. - * @param {Number[]} look The look position to update. - * @param {Number[]} up The up vector to update. - */ - sampleFrame(t, eye, look, up) { - t = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t); - this._eyeCurve.getPoint(t, eye); - this._lookCurve.getPoint(t, look); - this._upCurve.getPoint(t, up); - } - - /** - * Given a total duration (in seconds) for this CameraPath, recomputes the time instant at each frame so that, - * when animated by {@link CameraPathAnimation}, the {@link Camera} will move along the path at a constant rate. - * - * @param {Number} duration The total duration for this CameraPath. - */ - smoothFrameTimes(duration) { - const numFrames = this._frames.length; - if (numFrames === 0) { - return; - } - const vec = math.vec3(); - var totalLen = 0; - this._frames[0].t = 0; - const lens = []; - for (let i = 1, len = this._frames.length; i < len; i++) { - var lenVec = math.lenVec3(math.subVec3(this._frames[i].eye, this._frames[i - 1].eye, vec)); - lens[i] = lenVec; - totalLen += lenVec; - } - for (let i = 1, len = this._frames.length; i < len; i++) { - const interFrameRate = (lens[i] / totalLen) * duration; - this._frames[i].t = this._frames[i-1].t + interFrameRate; - } - } - - /** - * Removes all frames from this CameraPath. - */ - clearFrames() { - this._frames = []; - this._eyeCurve.points = []; - this._lookCurve.points = []; - this._upCurve.points = []; - } -} - -const tempVec3$2 = math.vec3(); -const newLook = math.vec3(); -const newEye = math.vec3(); -const newUp = math.vec3(); -const newLookEyeVec = math.vec3(); - -/** - * @desc Jumps or flies the {@link Scene}'s {@link Camera} to a given target. - * - * * Located at {@link Viewer#cameraFlight} - * * Can fly or jump to its target. - * * While flying, can be stopped, or redirected to a different target. - * * Can also smoothly transition between ortho and perspective projections. - * - * - * A CameraFlightAnimation's target can be: - * - * * specific ````eye````, ````look```` and ````up```` positions, - * * an axis-aligned World-space bounding box (AABB), or - * * an instance or ID of any {@link Component} subtype that provides a World-space AABB. - * - * A target can also contain a ````projection```` type to transition into. For example, if your {@link Camera#projection} is - * currently ````"perspective"```` and you supply {@link CameraFlightAnimation#flyTo} with a ````projection```` property - * equal to "ortho", then CameraFlightAnimation will smoothly transition the Camera into an orthographic projection. - * - * Configure {@link CameraFlightAnimation#fit} and {@link CameraFlightAnimation#fitFOV} to make it stop at the point - * where the target occupies a certain amount of the field-of-view. - * - * ## Flying to an Entity - * - * Flying to an {@link Entity}: - * - * ````Javascript - * var entity = new Mesh(viewer.scene); - * - * // Fly to the Entity's World-space AABB - * viewer.cameraFlight.flyTo(entity); - * ```` - * ## Flying to a Position - * - * Flying the CameraFlightAnimation from the previous example to specified eye, look and up positions: - * - * ````Javascript - * viewer.cameraFlight.flyTo({ - * eye: [-5,-5,-5], - * look: [0,0,0] - * up: [0,1,0], - * duration: 1 // Default, seconds - * },() => { - * // Done - * }); - * ```` - * - * ## Flying to an AABB - * - * Flying the CameraFlightAnimation from the previous two examples explicitly to the {@link Boundary3D"}}Boundary3D's{{/crossLink}} - * axis-aligned bounding box: - * - * ````Javascript - * viewer.cameraFlight.flyTo(entity.aabb); - * ```` - * - * ## Transitioning Between Projections - * - * CameraFlightAnimation also allows us to smoothly transition between Camera projections. We can do that by itself, or - * in addition to flying the Camera to a target. - * - * Let's transition the Camera to orthographic projection: - * - * [[Run example](http://xeokit.github.io/xeokit-sdk/examples/#camera_CameraFlightAnimation_projection)] - * - * ````Javascript - * viewer.cameraFlight.flyTo({ projection: "ortho", () => { - * // Done - * }); - * ```` - * - * Now let's transition the Camera back to perspective projection: - * - * ````Javascript - * viewer.cameraFlight.flyTo({ projection: "perspective"}, () => { - * // Done - * }); - * ```` - * - * Fly Camera to a position, while transitioning to orthographic projection: - * - * ````Javascript - * viewer.cameraFlight.flyTo({ - * eye: [-100,20,2], - * look: [0,0,-40], - * up: [0,1,0], - * projection: "ortho", () => { - * // Done - * }); - * ```` - */ -class CameraFlightAnimation extends Component { - - /** - * @private - */ - get type() { - return "CameraFlightAnimation"; - } - - /** - @constructor - @private - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - this._look1 = math.vec3(); - this._eye1 = math.vec3(); - this._up1 = math.vec3(); - this._look2 = math.vec3(); - this._eye2 = math.vec3(); - this._up2 = math.vec3(); - this._orthoScale1 = 1; - this._orthoScale2 = 1; - this._flying = false; - this._flyEyeLookUp = false; - this._flyingEye = false; - this._flyingLook = false; - this._callback = null; - this._callbackScope = null; - this._time1 = null; - this._time2 = null; - this.easing = cfg.easing !== false; - - this.duration = cfg.duration; - this.fit = cfg.fit; - this.fitFOV = cfg.fitFOV; - this.trail = cfg.trail; - } - - /** - * Flies the {@link Camera} to a target. - * - * * When the target is a boundary, the {@link Camera} will fly towards the target and stop when the target fills most of the canvas. - * * When the target is an explicit {@link Camera} position, given as ````eye````, ````look```` and ````up````, then CameraFlightAnimation will interpolate the {@link Camera} to that target and stop there. - * - * @param {Object|Component} [params=Scene] Either a parameters object or a {@link Component} subtype that has - * an AABB. Defaults to the {@link Scene}, which causes the {@link Camera} to fit the Scene in view. - * @param {Number} [params.arc=0] Factor in range ````[0..1]```` indicating how much the {@link Camera#eye} position - * will swing away from its {@link Camera#look} position as it flies to the target. - * @param {Number|String|Component} [params.component] ID or instance of a component to fly to. Defaults to the entire {@link Scene}. - * @param {Number[]} [params.aabb] World-space axis-aligned bounding box (AABB) target to fly to. - * @param {Number[]} [params.eye] Position to fly the eye position to. - * @param {Number[]} [params.look] Position to fly the look position to. - * @param {Number[]} [params.up] Position to fly the up vector to. - * @param {String} [params.projection] Projection type to transition into as we fly. Can be any of the values of {@link Camera.projection}. - * @param {Boolean} [params.fit=true] Whether to fit the target to the view volume. Overrides {@link CameraFlightAnimation#fit}. - * @param {Number} [params.fitFOV] How much of field-of-view, in degrees, that a target {@link Entity} or its AABB should - * fill the canvas on arrival. Overrides {@link CameraFlightAnimation#fitFOV}. - * @param {Number} [params.duration] Flight duration in seconds. Overrides {@link CameraFlightAnimation#duration}. - * @param {Number} [params.orthoScale] Animate the Camera's orthographic scale to this target value. See {@link Ortho#scale}. - * @param {Function} [callback] Callback fired on arrival. - * @param {Object} [scope] Optional scope for callback. - */ - flyTo(params, callback, scope) { - - params = params || this.scene; - - if (this._flying) { - this.stop(); - } - - this._flying = false; - this._flyingEye = false; - this._flyingLook = false; - this._flyingEyeLookUp = false; - - this._callback = callback; - this._callbackScope = scope; - - const camera = this.scene.camera; - const flyToProjection = (!!params.projection) && (params.projection !== camera.projection); - - this._eye1[0] = camera.eye[0]; - this._eye1[1] = camera.eye[1]; - this._eye1[2] = camera.eye[2]; - - this._look1[0] = camera.look[0]; - this._look1[1] = camera.look[1]; - this._look1[2] = camera.look[2]; - - this._up1[0] = camera.up[0]; - this._up1[1] = camera.up[1]; - this._up1[2] = camera.up[2]; - - this._orthoScale1 = camera.ortho.scale; - this._orthoScale2 = params.orthoScale || this._orthoScale1; - - let aabb; - let eye; - let look; - let up; - let componentId; - - if (params.aabb) { - aabb = params.aabb; - - } else if (params.length === 6) { - aabb = params; - - } else if ((params.eye && params.look) || params.up) { - eye = params.eye; - look = params.look; - up = params.up; - - } else if (params.eye) { - eye = params.eye; - - } else if (params.look) { - look = params.look; - - } else { // Argument must be an instance or ID of a Component (subtype) - - let component = params; - - if (utils.isNumeric(component) || utils.isString(component)) { - - componentId = component; - component = this.scene.components[componentId]; - - if (!component) { - this.error("Component not found: " + utils.inQuotes(componentId)); - if (callback) { - if (scope) { - callback.call(scope); - } else { - callback(); - } - } - return; - } - } - if (!flyToProjection) { - aabb = component.aabb || this.scene.aabb; - } - } - - const poi = params.poi; - - if (aabb) { - - if (aabb[3] < aabb[0] || aabb[4] < aabb[1] || aabb[5] < aabb[2]) { // Don't fly to an inverted boundary - return; - } - - if (aabb[3] === aabb[0] && aabb[4] === aabb[1] && aabb[5] === aabb[2]) { // Don't fly to an empty boundary - return; - } - - aabb = aabb.slice(); - const aabbCenter = math.getAABB3Center(aabb); - - this._look2 = poi || aabbCenter; - - const eyeLookVec = math.subVec3(this._eye1, this._look1, tempVec3$2); - const eyeLookVecNorm = math.normalizeVec3(eyeLookVec); - const diag = poi ? math.getAABB3DiagPoint(aabb, poi) : math.getAABB3Diag(aabb); - const fitFOV = params.fitFOV || this._fitFOV; - const sca = Math.abs(diag / Math.tan(fitFOV * math.DEGTORAD)); - - this._orthoScale2 = diag * 1.1; - - this._eye2[0] = this._look2[0] + (eyeLookVecNorm[0] * sca); - this._eye2[1] = this._look2[1] + (eyeLookVecNorm[1] * sca); - this._eye2[2] = this._look2[2] + (eyeLookVecNorm[2] * sca); - - this._up2[0] = this._up1[0]; - this._up2[1] = this._up1[1]; - this._up2[2] = this._up1[2]; - - this._flyingEyeLookUp = true; - - } else if (eye || look || up) { - - this._flyingEyeLookUp = !!eye && !!look && !!up; - this._flyingEye = !!eye && !look; - this._flyingLook = !!look && !eye; - - if (eye) { - this._eye2[0] = eye[0]; - this._eye2[1] = eye[1]; - this._eye2[2] = eye[2]; - } - - if (look) { - this._look2[0] = look[0]; - this._look2[1] = look[1]; - this._look2[2] = look[2]; - } - - if (up) { - this._up2[0] = up[0]; - this._up2[1] = up[1]; - this._up2[2] = up[2]; - } - } - - if (flyToProjection) { - - if (params.projection === "ortho" && camera.projection !== "ortho") { - this._projection2 = "ortho"; - this._projMatrix1 = camera.projMatrix.slice(); - this._projMatrix2 = camera.ortho.matrix.slice(); - camera.projection = "customProjection"; - } - - if (params.projection === "perspective" && camera.projection !== "perspective") { - this._projection2 = "perspective"; - this._projMatrix1 = camera.projMatrix.slice(); - this._projMatrix2 = camera.perspective.matrix.slice(); - camera.projection = "customProjection"; - } - } else { - this._projection2 = null; - } - - this.fire("started", params, true); - - this._time1 = Date.now(); - this._time2 = this._time1 + (params.duration ? params.duration * 1000 : this._duration); - - this._flying = true; // False as soon as we stop - - core.scheduleTask(this._update, this); - } - - /** - * Jumps the {@link Scene}'s {@link Camera} to the given target. - * - * * When the target is a boundary, this CameraFlightAnimation will position the {@link Camera} at where the target fills most of the canvas. - * * When the target is an explicit {@link Camera} position, given as ````eye````, ````look```` and ````up```` vectors, then this CameraFlightAnimation will jump the {@link Camera} to that target. - * - * @param {*|Component} params Either a parameters object or a {@link Component} subtype that has a World-space AABB. - * @param {Number} [params.arc=0] Factor in range [0..1] indicating how much the {@link Camera#eye} will swing away from its {@link Camera#look} as it flies to the target. - * @param {Number|String|Component} [params.component] ID or instance of a component to fly to. - * @param {Number[]} [params.aabb] World-space axis-aligned bounding box (AABB) target to fly to. - * @param {Number[]} [params.eye] Position to fly the eye position to. - * @param {Number[]} [params.look] Position to fly the look position to. - * @param {Number[]} [params.up] Position to fly the up vector to. - * @param {String} [params.projection] Projection type to transition into. Can be any of the values of {@link Camera.projection}. - * @param {Number} [params.fitFOV] How much of field-of-view, in degrees, that a target {@link Entity} or its AABB should fill the canvas on arrival. Overrides {@link CameraFlightAnimation#fitFOV}. - * @param {Boolean} [params.fit] Whether to fit the target to the view volume. Overrides {@link CameraFlightAnimation#fit}. - */ - jumpTo(params) { - this._jumpTo(params); - } - - _jumpTo(params) { - - if (this._flying) { - this.stop(); - } - - const camera = this.scene.camera; - - var aabb; - var componentId; - var newEye; - var newLook; - var newUp; - - if (params.aabb) { // Boundary3D - aabb = params.aabb; - - } else if (params.length === 6) { // AABB - aabb = params; - - } else if (params.eye || params.look || params.up) { // Camera pose - newEye = params.eye; - newLook = params.look; - newUp = params.up; - - } else { // Argument must be an instance or ID of a Component (subtype) - - let component = params; - - if (utils.isNumeric(component) || utils.isString(component)) { - componentId = component; - component = this.scene.components[componentId]; - if (!component) { - this.error("Component not found: " + utils.inQuotes(componentId)); - return; - } - } - aabb = component.aabb || this.scene.aabb; - } - - const poi = params.poi; - - if (aabb) { - - if (aabb[3] <= aabb[0] || aabb[4] <= aabb[1] || aabb[5] <= aabb[2]) { // Don't fly to an empty boundary - return; - } - - var diag = poi ? math.getAABB3DiagPoint(aabb, poi) : math.getAABB3Diag(aabb); - - newLook = poi || math.getAABB3Center(aabb, newLook); - - if (this._trail) { - math.subVec3(camera.look, newLook, newLookEyeVec); - } else { - math.subVec3(camera.eye, camera.look, newLookEyeVec); - } - - math.normalizeVec3(newLookEyeVec); - let dist; - const fit = (params.fit !== undefined) ? params.fit : this._fit; - - if (fit) { - dist = Math.abs((diag) / Math.tan((params.fitFOV || this._fitFOV) * math.DEGTORAD)); - - } else { - dist = math.lenVec3(math.subVec3(camera.eye, camera.look, tempVec3$2)); - } - - math.mulVec3Scalar(newLookEyeVec, dist); - - camera.eye = math.addVec3(newLook, newLookEyeVec, tempVec3$2); - camera.look = newLook; - - this.scene.camera.ortho.scale = diag * 1.1; - - } else if (newEye || newLook || newUp) { - - if (newEye) { - camera.eye = newEye; - } - if (newLook) { - camera.look = newLook; - } - if (newUp) { - camera.up = newUp; - } - } - - if (params.projection) { - camera.projection = params.projection; - } - } - - _update() { - if (!this._flying) { - return; - } - const time = Date.now(); - let t = (time - this._time1) / (this._time2 - this._time1); - const stopping = (t >= 1); - - if (t > 1) { - t = 1; - } - - const tFlight = this.easing ? CameraFlightAnimation._ease(t, 0, 1, 1) : t; - const camera = this.scene.camera; - - if (this._flyingEye || this._flyingLook) { - - if (this._flyingEye) { - math.subVec3(camera.eye, camera.look, newLookEyeVec); - camera.eye = math.lerpVec3(tFlight, 0, 1, this._eye1, this._eye2, newEye); - camera.look = math.subVec3(newEye, newLookEyeVec, newLook); - } else if (this._flyingLook) { - camera.look = math.lerpVec3(tFlight, 0, 1, this._look1, this._look2, newLook); - camera.up = math.lerpVec3(tFlight, 0, 1, this._up1, this._up2, newUp); - } - - } else if (this._flyingEyeLookUp) { - - camera.eye = math.lerpVec3(tFlight, 0, 1, this._eye1, this._eye2, newEye); - camera.look = math.lerpVec3(tFlight, 0, 1, this._look1, this._look2, newLook); - camera.up = math.lerpVec3(tFlight, 0, 1, this._up1, this._up2, newUp); - } - - if (this._projection2) { - const tProj = (this._projection2 === "ortho") ? CameraFlightAnimation._easeOutExpo(t, 0, 1, 1) : CameraFlightAnimation._easeInCubic(t, 0, 1, 1); - camera.customProjection.matrix = math.lerpMat4(tProj, 0, 1, this._projMatrix1, this._projMatrix2); - - } else { - camera.ortho.scale = this._orthoScale1 + (t * (this._orthoScale2 - this._orthoScale1)); - } - - if (stopping) { - camera.ortho.scale = this._orthoScale2; - this.stop(); - return; - } - core.scheduleTask(this._update, this); // Keep flying - } - - static _ease(t, b, c, d) { // Quadratic easing out - decelerating to zero velocity http://gizma.com/easing - t /= d; - return -c * t * (t - 2) + b; - } - - static _easeInCubic(t, b, c, d) { - t /= d; - return c * t * t * t + b; - } - - static _easeOutExpo(t, b, c, d) { - return c * (-Math.pow(2, -10 * t / d) + 1) + b; - } - - /** - * Stops an earlier flyTo, fires arrival callback. - */ - stop() { - if (!this._flying) { - return; - } - this._flying = false; - this._time1 = null; - this._time2 = null; - if (this._projection2) { - this.scene.camera.projection = this._projection2; - } - const callback = this._callback; - if (callback) { - this._callback = null; - if (this._callbackScope) { - callback.call(this._callbackScope); - } else { - callback(); - } - } - this.fire("stopped", true, true); - } - - /** - * Cancels an earlier flyTo without calling the arrival callback. - */ - cancel() { - if (!this._flying) { - return; - } - this._flying = false; - this._time1 = null; - this._time2 = null; - if (this._callback) { - this._callback = null; - } - this.fire("canceled", true, true); - } - - /** - * Sets the flight duration, in seconds, when calling {@link CameraFlightAnimation#flyTo}. - * - * Stops any flight currently in progress. - * - * default value is ````0.5````. - * - * @param {Number} value New duration value. - */ - set duration(value) { - this._duration = value ? (value * 1000.0) : 500; - this.stop(); - } - - /** - * Gets the flight duration, in seconds, when calling {@link CameraFlightAnimation#flyTo}. - * - * default value is ````0.5````. - * - * @returns {Number} New duration value. - */ - get duration() { - return this._duration / 1000.0; - } - - /** - * Sets if, when CameraFlightAnimation is flying to a boundary, it will always adjust the distance between the - * {@link Camera#eye} and {@link Camera#look} so as to ensure that the target boundary is always filling the view volume. - * - * When false, the eye will remain at its current distance from the look position. - * - * Default value is ````true````. - * - * @param {Boolean} value Set ````true```` to activate this behaviour. - */ - set fit(value) { - this._fit = value !== false; - } - - /** - * Gets if, when CameraFlightAnimation is flying to a boundary, it will always adjust the distance between the - * {@link Camera#eye} and {@link Camera#look} so as to ensure that the target boundary is always filling the view volume. - * - * When false, the eye will remain at its current distance from the look position. - * - * Default value is ````true````. - * - * @returns {Boolean} value Set ````true```` to activate this behaviour. - */ - get fit() { - return this._fit; - } - - /** - * Sets how much of the perspective field-of-view, in degrees, that a target {@link Entity#aabb} should - * fill the canvas when calling {@link CameraFlightAnimation#flyTo} or {@link CameraFlightAnimation#jumpTo}. - * - * Default value is ````45````. - * - * @param {Number} value New FOV value. - */ - set fitFOV(value) { - this._fitFOV = value || 45; - } - - /** - * Gets how much of the perspective field-of-view, in degrees, that a target {@link Entity#aabb} should - * fill the canvas when calling {@link CameraFlightAnimation#flyTo} or {@link CameraFlightAnimation#jumpTo}. - * - * Default value is ````45````. - * - * @returns {Number} Current FOV value. - */ - get fitFOV() { - return this._fitFOV; - } - - /** - * Sets if this CameraFlightAnimation to point the {@link Camera} - * in the direction that it is travelling when flying to a target after calling {@link CameraFlightAnimation#flyTo}. - * - * Default value is ````true````. - * - * @param {Boolean} value Set ````true```` to activate trailing behaviour. - */ - set trail(value) { - this._trail = !!value; - } - - /** - * Gets if this CameraFlightAnimation points the {@link Camera} - * in the direction that it is travelling when flying to a target after calling {@link CameraFlightAnimation#flyTo}. - * - * Default value is ````true````. - * - * @returns {Boolean} True if trailing behaviour is active. - */ - get trail() { - return this._trail; - } - - /** - * @private - */ - destroy() { - this.stop(); - super.destroy(); - } -} - -/** - * @desc Animates the {@link Scene}'s's {@link Camera} along a {@link CameraPath}. - * - * ## Usage - * - * In the example below, we'll load a model using a {@link GLTFLoaderPlugin}, then animate a {@link Camera} - * through the frames in a {@link CameraPath}. - * - * * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#camera_CameraPathAnimation)] - * - * ````Javascript - * import {Viewer, GLTFLoaderPlugin, CameraPath, CameraPathAnimation} from "xeokit-sdk.es.js"; - * - * // Create a Viewer and arrange camera - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [124.86756896972656, -93.50288391113281, 173.2632598876953]; - * viewer.camera.look = [102.14186096191406, -90.24193572998047, 173.4224395751953]; - * viewer.camera.up = [0.23516440391540527, 0.9719591736793518, -0.0016466031083837152]; - * - * // Load model - * - * const gltfLoader = new GLTFLoaderPlugin(viewer); - * - * const model = gltfLoader.load({ - * id: "myModel", - * src: "./models/gltf/modern_office/scene.gltf", - * edges: true, - * edgeThreshold: 20, - * xrayed: false - * }); - * - * // Create a CameraPath - * - * var cameraPath = new CameraPath(viewer.scene, { - * frames: [ - * { - * t: 0, - * eye: [124.86, -93.50, 173.26], - * look: [102.14, -90.24, 173.42], - * up: [0.23, 0.97, -0.00] - * }, - * { - * t: 1, - * eye: [79.75, -85.98, 226.57], - * look: [99.24, -84.11, 238.56], - * up: [-0.14, 0.98, -0.09] - * }, - * // Rest of the frames omitted for brevity - * ] - * }); - * - * // Create a CameraPathAnimation to play our CameraPath - * - * var cameraPathAnimation = new CameraPathAnimation(viewer.scene, { - * cameraPath: cameraPath, - * playingRate: 0.2 // Playing 0.2 time units per second - * }); - * - * // Once model loaded, start playing after a couple of seconds delay - * - * model.on("loaded", function () { - * setTimeout(function () { - * cameraPathAnimation.play(0); // Play from the beginning of the CameraPath - * }, 2000); - * }); - * ```` - */ -class CameraPathAnimation extends Component { - - /** - * Returns "CameraPathAnimation". - * - * @private - * @returns {string} "CameraPathAnimation" - */ - get type() { - return "CameraPathAnimation" - } - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this CameraPathAnimation as well. - * @param {*} [cfg] Configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {CameraPath} [cfg.eyeCurve] A {@link CameraPath} that defines the path of a {@link Camera}. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - this._cameraFlightAnimation = new CameraFlightAnimation(this); - this._t = 0; - this.state = CameraPathAnimation.SCRUBBING; - this._playingFromT = 0; - this._playingToT = 0; - this._playingRate = cfg.playingRate || 1.0; - this._playingDir = 1.0; - this._lastTime = null; - - this.cameraPath = cfg.cameraPath; - - this._tick = this.scene.on("tick", this._updateT, this); - } - - _updateT() { - const cameraPath = this._cameraPath; - if (!cameraPath) { - return; - } - let numFrames; - let t; - const time = performance.now(); - const elapsedSecs = (this._lastTime) ? (time - this._lastTime) * 0.001 : 0; - this._lastTime = time; - if (elapsedSecs === 0) { - return; - } - switch (this.state) { - case CameraPathAnimation.SCRUBBING: - return; - case CameraPathAnimation.PLAYING: - this._t += this._playingRate * elapsedSecs; - numFrames = this._cameraPath.frames.length; - if (numFrames === 0 || (this._playingDir < 0 && this._t <= 0) || (this._playingDir > 0 && this._t >= this._cameraPath.frames[numFrames - 1].t)) { - this.state = CameraPathAnimation.SCRUBBING; - this._t = this._cameraPath.frames[numFrames - 1].t; - this.fire("stopped"); - return; - } - cameraPath.loadFrame(this._t); - break; - case CameraPathAnimation.PLAYING_TO: - t = this._t + (this._playingRate * elapsedSecs * this._playingDir); - if ((this._playingDir < 0 && t <= this._playingToT) || (this._playingDir > 0 && t >= this._playingToT)) { - t = this._playingToT; - this.state = CameraPathAnimation.SCRUBBING; - this.fire("stopped"); - } - this._t = t; - cameraPath.loadFrame(this._t); - break; - } - } - - /* - * @private - */ - _ease(t, b, c, d) { - t /= d; - return -c * t * (t - 2) + b; - } - - /** - * Sets the {@link CameraPath} animated by this CameraPathAnimation. - * - @param {CameraPath} value The new CameraPath. - */ - set cameraPath(value) { - this._cameraPath = value; - } - - /** - * Gets the {@link CameraPath} animated by this CameraPathAnimation. - * - @returns {CameraPath} The CameraPath. - */ - get cameraPath() { - return this._cameraPath; - } - - /** - * Sets the rate at which the CameraPathAnimation animates the {@link Camera} along the {@link CameraPath}. - * - * @param {Number} value The amount of progress per second. - */ - set rate(value) { - this._playingRate = value; - } - - /** - * Gets the rate at which the CameraPathAnimation animates the {@link Camera} along the {@link CameraPath}. - * - * @returns {*|number} The current playing rate. - */ - get rate() { - return this._playingRate; - } - - /** - * Begins animating the {@link Camera} along CameraPathAnimation's {@link CameraPath} from the beginning. - */ - play() { - if (!this._cameraPath) { - return; - } - this._lastTime = null; - this.state = CameraPathAnimation.PLAYING; - } - - /** - * Begins animating the {@link Camera} along CameraPathAnimation's {@link CameraPath} from the given time. - * - * @param {Number} t Time instant. - */ - playToT(t) { - const cameraPath = this._cameraPath; - if (!cameraPath) { - return; - } - this._playingFromT = this._t; - this._playingToT = t; - this._playingDir = (this._playingToT - this._playingFromT) < 0 ? -1 : 1; - this._lastTime = null; - this.state = CameraPathAnimation.PLAYING_TO; - } - - /** - * Animates the {@link Camera} along CameraPathAnimation's {@link CameraPath} to the given frame. - * - * @param {Number} frameIdx Index of the frame to play to. - */ - playToFrame(frameIdx) { - const cameraPath = this._cameraPath; - if (!cameraPath) { - return; - } - const frame = cameraPath.frames[frameIdx]; - if (!frame) { - this.error("playToFrame - frame index out of range: " + frameIdx); - return; - } - this.playToT(frame.t); - } - - /** - * Flies the {@link Camera} directly to the given frame on the CameraPathAnimation's {@link CameraPath}. - * - * @param {Number} frameIdx Index of the frame to play to. - * @param {Function} [ok] Callback to fire when playing is complete. - */ - flyToFrame(frameIdx, ok) { - const cameraPath = this._cameraPath; - if (!cameraPath) { - return; - } - const frame = cameraPath.frames[frameIdx]; - if (!frame) { - this.error("flyToFrame - frame index out of range: " + frameIdx); - return; - } - this.state = CameraPathAnimation.SCRUBBING; - this._cameraFlightAnimation.flyTo(frame, ok); - } - - /** - * Scrubs the {@link Camera} to the given time on the CameraPathAnimation's {@link CameraPath}. - * - * @param {Number} t Time instant. - */ - scrubToT(t) { - const cameraPath = this._cameraPath; - if (!cameraPath) { - return; - } - const camera = this.scene.camera; - if (!camera) { - return; - } - this._t = t; - cameraPath.loadFrame(this._t); - this.state = CameraPathAnimation.SCRUBBING; - } - - /** - * Scrubs the {@link Camera} to the given frame on the CameraPathAnimation's {@link CameraPath}. - * - * @param {Number} frameIdx Index of the frame to scrub to. - */ - scrubToFrame(frameIdx) { - const cameraPath = this._cameraPath; - if (!cameraPath) { - return; - } - const camera = this.scene.camera; - if (!camera) { - return; - } - const frame = cameraPath.frames[frameIdx]; - if (!frame) { - this.error("playToFrame - frame index out of range: " + frameIdx); - return; - } - cameraPath.loadFrame(this._t); - this.state = CameraPathAnimation.SCRUBBING; - } - - /** - * Stops playing this CameraPathAnimation. - */ - stop() { - this.state = CameraPathAnimation.SCRUBBING; - this.fire("stopped"); - } - - destroy() { - super.destroy(); - this.scene.off(this._tick); - } -} - -CameraPathAnimation.STOPPED = 0; -CameraPathAnimation.SCRUBBING = 1; -CameraPathAnimation.PLAYING = 2; -CameraPathAnimation.PLAYING_TO = 3; - -/** - * @private - */ -var K3D = {}; - -K3D.load = function(path, resp) -{ - var request = new XMLHttpRequest(); - request.open("GET", path, true); - request.responseType = "arraybuffer"; - request.onload = function(e){resp(e.target.response);}; - request.send(); -}; - -K3D.save = function(buff, path) -{ - var dataURI = "data:application/octet-stream;base64," + btoa(K3D.parse._buffToStr(buff)); - window.location.href = dataURI; -}; - -K3D.clone = function(o) -{ - return JSON.parse(JSON.stringify(o)); -}; - - - -K3D.bin = {}; - -K3D.bin.f = new Float32Array(1); -K3D.bin.fb = new Uint8Array(K3D.bin.f.buffer); - -K3D.bin.rf = function(buff, off) { var f = K3D.bin.f, fb = K3D.bin.fb; for(var i=0; i<4; i++) fb[i] = buff[off+i]; return f[0]; }; -K3D.bin.rsl = function(buff, off) { return buff[off] | buff[off+1]<<8; }; -K3D.bin.ril = function(buff, off) { return buff[off] | buff[off+1]<<8 | buff[off+2]<<16 | buff[off+3]<<24; }; -K3D.bin.rASCII0 = function(buff, off) { var s = ""; while(buff[off]!=0) s += String.fromCharCode(buff[off++]); return s; }; - - -K3D.bin.wf = function(buff, off, v) { var f=new Float32Array(buff.buffer, off, 1); f[0]=v; }; -K3D.bin.wsl = function(buff, off, v) { buff[off]=v; buff[off+1]=v>>8; }; -K3D.bin.wil = function(buff, off, v) { buff[off]=v; buff[off+1]=v>>8; buff[off+2]=v>>16; buff[off+3]>>24; }; -K3D.parse = {}; - -K3D.parse._buffToStr = function(buff) -{ - var a = new Uint8Array(buff); - var s = ""; - for(var i=0; imaxx) maxx = vx; - if(vymaxy) maxy = vy; - if(vzmaxz) maxz = vz; - } - return {min:{x:minx, y:miny, z:minz}, max:{x:maxx, y:maxy, z:maxz}}; -}; - -/** - * @desc Loads {@link Geometry} from 3DS. - * - * ## Usage - * - * In the example below we'll create a {@link Mesh} with {@link PhongMaterial}, {@link Texture} and a {@link ReadableGeometry} loaded from 3DS. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_loaders_3DS)] - * - * ````javascript - * import {Viewer, Mesh, load3DSGeometry, ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [40.04, 23.46, 79.06]; - * viewer.scene.camera.look = [-6.48, 13.92, -0.56]; - * viewer.scene.camera.up = [-0.04, 0.98, -0.08]; - * - * load3DSGeometry(viewer.scene, { - * src: "models/3ds/lexus.3ds", - * compressGeometry: false - * - * }).then(function (geometryCfg) { - * - * // Success - * - * new Mesh(viewer.scene, { - * - * geometry: new ReadableGeometry(viewer.scene, geometryCfg), - * - * material: new PhongMaterial(viewer.scene, { - * - * emissive: [1, 1, 1], - * emissiveMap: new Texture({ // .3DS has no normals so relies on emissive illumination - * src: "models/3ds/lexus.jpg" - * }) - * }), - * - * rotation: [-90, 0, 0] // +Z is up for this particular 3DS - * }); - * }, function () { - * // Error - * }); - * ```` - * - * @function load3DSGeometry - * @param {Scene} scene Scene we're loading the geometry for. - * @param {*} cfg Configs, also added to the result object. - * @param {String} [cfg.src] Path to 3DS file. - * @returns {Object} Configuration to pass into a {@link Geometry} constructor, containing geometry arrays loaded from the OBJ file. - */ -function load3DSGeometry(scene, cfg = {}) { - - return new Promise(function (resolve, reject) { - - if (!cfg.src) { - console.error("load3DSGeometry: Parameter expected: src"); - reject(); - } - - var spinner = scene.canvas.spinner; - spinner.processes++; - - utils.loadArraybuffer(cfg.src, function (data) { - - if (!data.byteLength) { - console.error("load3DSGeometry: no data loaded"); - spinner.processes--; - reject(); - } - - var m = K3D.parse.from3DS(data); // done ! - - var mesh = m.edit.objects[0].mesh; - var positions = mesh.vertices; - var uv = mesh.uvt; - var indices = mesh.indices; - - spinner.processes--; - - resolve(utils.apply(cfg, { - primitive: "triangles", - positions: positions, - normals: null, - uv: uv, - indices: indices - })); - }, - - function (msg) { - console.error("load3DSGeometry: " + msg); - spinner.processes--; - reject(); - }); - }); -} - -/** - * @desc Loads {@link Geometry} from OBJ. - * - * ## Usage - * - * In the example below we'll create a {@link Mesh} with {@link MetallicMaterial} and {@link ReadableGeometry} loaded from OBJ. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_loaders_OBJ)] - * - * ````javascript - * import {Viewer, Mesh, loadOBJGeometry, ReadableGeometry, - * MetallicMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0.57, 1.37, 1.14]; - * viewer.scene.camera.look = [0.04, 0.58, 0.00]; - * viewer.scene.camera.up = [-0.22, 0.84, -0.48]; - * - * loadOBJGeometry(viewer.scene, { - * - * src: "models/obj/fireHydrant/FireHydrantMesh.obj", - * compressGeometry: false - * - * }).then(function (geometryCfg) { - * - * // Success - * - * new Mesh(viewer.scene, { - * - * geometry: new ReadableGeometry(viewer.scene, geometryCfg), - * - * material: new MetallicMaterial(viewer.scene, { - * - * baseColor: [1, 1, 1], - * metallic: 1.0, - * roughness: 1.0, - * - * baseColorMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Base_Color.png", - * encoding: "sRGB" - * }), - * normalMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Normal_OpenGL.png" - * }), - * roughnessMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Roughness.png" - * }), - * metallicMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Metallic.png" - * }), - * occlusionMap: new Texture(viewer.scene, { - * src: "models/obj/fireHydrant/fire_hydrant_Mixed_AO.png" - * }), - * - * specularF0: 0.7 - * }) - * }); - * }, function () { - * // Error - * }); - * ```` - * - * @function loadOBJGeometry - * @param {Scene} scene Scene we're loading the geometry for. - * @param {*} [cfg] Configs, also added to the result object. - * @param {String} [cfg.src] Path to OBJ file. - * @returns {Object} Configuration to pass into a {@link Geometry} constructor, containing geometry arrays loaded from the OBJ file. - */ -function loadOBJGeometry(scene, cfg = {}) { - - return new Promise(function (resolve, reject) { - - if (!cfg.src) { - console.error("loadOBJGeometry: Parameter expected: src"); - reject(); - } - - var spinner = scene.canvas.spinner; - spinner.processes++; - - utils.loadArraybuffer(cfg.src, function (data) { - - if (!data.byteLength) { - console.error("loadOBJGeometry: no data loaded"); - spinner.processes--; - reject(); - } - - var m = K3D.parse.fromOBJ(data); // done ! - - // unwrap simply duplicates some values, so they can be indexed with indices [0,1,2,3 ... ] - // In some rendering engines, you can have only one index value for vertices, UVs, normals ..., - // so "unwrapping" is a simple solution. - - var positions = K3D.edit.unwrap(m.i_verts, m.c_verts, 3); - var normals = K3D.edit.unwrap(m.i_norms, m.c_norms, 3); - var uv = K3D.edit.unwrap(m.i_uvt, m.c_uvt, 2); - var indices = new Int32Array(m.i_verts.length); - - for (var i = 0; i < m.i_verts.length; i++) { - indices[i] = i; - } - - spinner.processes--; - - resolve(utils.apply(cfg, { - primitive: "triangles", - positions: positions, - normals: normals.length > 0 ? normals : null, - autoNormals: normals.length === 0, - uv: uv, - indices: indices - })); - }, - - function (msg) { - console.error("loadOBJGeometry: " + msg); - spinner.processes--; - reject(); - }); - }); -} - -/** - * @desc Creates a box-shaped lines {@link Geometry}. - * - * ## Usage - * - * In the example below we'll create a {@link Mesh} with a box-shaped {@link ReadableGeometry} that has lines primitives. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildBoxLinesGeometry)] - * - * ````javascript - * import {Viewer, Mesh, buildBoxLinesGeometry, ReadableGeometry, PhongMaterial} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0, 0, 5]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildBoxLinesGeometry({ - * center: [0,0,0], - * xSize: 1, // Half-size on each axis - * ySize: 1, - * zSize: 1 - * }), - * material: new PhongMaterial(viewer.scene, { - * emissive: [0,1,0] - * }) - * }); - * ```` - * - * @function buildBoxLinesGeometry - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number[]} [cfg.center] 3D point indicating the center position. - * @param {Number} [cfg.xSize=1.0] Half-size on the X-axis. - * @param {Number} [cfg.ySize=1.0] Half-size on the Y-axis. - * @param {Number} [cfg.zSize=1.0] Half-size on the Z-axis. - * @returns {Object} Configuration for a {@link Geometry} subtype. - */ -function buildBoxLinesGeometry(cfg = {}) { - - let xSize = cfg.xSize || 1; - if (xSize < 0) { - console.error("negative xSize not allowed - will invert"); - xSize *= -1; - } - - let ySize = cfg.ySize || 1; - if (ySize < 0) { - console.error("negative ySize not allowed - will invert"); - ySize *= -1; - } - - let zSize = cfg.zSize || 1; - if (zSize < 0) { - console.error("negative zSize not allowed - will invert"); - zSize *= -1; - } - - const center = cfg.center; - const centerX = center ? center[0] : 0; - const centerY = center ? center[1] : 0; - const centerZ = center ? center[2] : 0; - - const xmin = -xSize + centerX; - const ymin = -ySize + centerY; - const zmin = -zSize + centerZ; - const xmax = xSize + centerX; - const ymax = ySize + centerY; - const zmax = zSize + centerZ; - - return utils.apply(cfg, { - primitive: "lines", - positions: [ - xmin, ymin, zmin, - xmin, ymin, zmax, - xmin, ymax, zmin, - xmin, ymax, zmax, - xmax, ymin, zmin, - xmax, ymin, zmax, - xmax, ymax, zmin, - xmax, ymax, zmax - ], - indices: [ - 0, 1, - 1, 3, - 3, 2, - 2, 0, - 4, 5, - 5, 7, - 7, 6, - 6, 4, - 0, 4, - 1, 5, - 2, 6, - 3, 7 - ] - }); -} - -/** - * @desc Creates a grid-shaped {@link Geometry}. - * - * ## Usage - * - * Creating a {@link Mesh} with a GridGeometry and a {@link PhongMaterial}: - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildGridGeometry)] - * - * ````javascript - * import {Viewer, Mesh, buildGridGeometry, VBOGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [0, 0, 5]; - * viewer.camera.look = [0, 0, 0]; - * viewer.camera.up = [0, 1, 0]; - * - * new Mesh(viewer.scene, { - * geometry: new VBOGeometry(viewer.scene, buildGridGeometry({ - * size: 1000, - * divisions: 500 - * })), - * material: new PhongMaterial(viewer.scene, { - * color: [0.0, 0.0, 0.0], - * emissive: [0.4, 0.4, 0.4] - * }), - * position: [0, -1.6, 0] - * }); - * ```` - * - * @function buildGridGeometry - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for the {@link Geometry}, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number} [cfg.size=1] Dimension on the X and Z-axis. - * @param {Number} [cfg.divisions=1] Number of divisions on X and Z axis.. - * @returns {Object} Configuration for a {@link Geometry} subtype. - */ -function buildGridGeometry(cfg = {}) { - - let size = cfg.size || 1; - if (size < 0) { - console.error("negative size not allowed - will invert"); - size *= -1; - } - - let divisions = cfg.divisions || 1; - if (divisions < 0) { - console.error("negative divisions not allowed - will invert"); - divisions *= -1; - } - if (divisions < 1) { - divisions = 1; - } - - size = size || 10; - divisions = divisions || 10; - - const step = size / divisions; - const halfSize = size / 2; - - const positions = []; - const indices = []; - let l = 0; - - for (let i = 0, k = -halfSize; i <= divisions; i++, k += step) { - - positions.push(-halfSize); - positions.push(0); - positions.push(k); - - positions.push(halfSize); - positions.push(0); - positions.push(k); - - positions.push(k); - positions.push(0); - positions.push(-halfSize); - - positions.push(k); - positions.push(0); - positions.push(halfSize); - - indices.push(l++); - indices.push(l++); - indices.push(l++); - indices.push(l++); - } - - return utils.apply(cfg, { - primitive: "lines", - positions: positions, - indices: indices - }); -} - -/** - * @desc Creates a plane-shaped {@link Geometry}. - * - * ## Usage - * - * Creating a {@link Mesh} with a PlaneGeometry and a {@link PhongMaterial} with diffuse {@link Texture}: - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#geometry_builders_buildPlaneGeometry)] - * - * ````javascript - * import {Viewer, Mesh, buildPlaneGeometry, ReadableGeometry, PhongMaterial, Texture} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [0, 0, 5]; - * viewer.camera.look = [0, 0, 0]; - * viewer.camera.up = [0, 1, 0]; - - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildPlaneGeometry({ - * center: [0,0,0], - * xSize: 2, - * zSize: 2, - * xSegments: 10, - * zSegments: 10 - * }), - * material: new PhongMaterial(viewer.scene, { - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }) - * }) - * }); - * ```` - * - * @function buildPlaneGeometry - * @param {*} [cfg] Configs - * @param {Number[]} [cfg.center] 3D point indicating the center position. - * @param {String} [cfg.id] Optional ID for the {@link Geometry}, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number} [cfg.xSize=1] Dimension on the X-axis. - * @param {Number} [cfg.zSize=1] Dimension on the Z-axis. - * @param {Number} [cfg.xSegments=1] Number of segments on the X-axis. - * @param {Number} [cfg.zSegments=1] Number of segments on the Z-axis. - * @returns {Object} Configuration for a {@link Geometry} subtype. - */ -function buildPlaneGeometry(cfg = {}) { - - let xSize = cfg.xSize || 1; - if (xSize < 0) { - console.error("negative xSize not allowed - will invert"); - xSize *= -1; - } - - let zSize = cfg.zSize || 1; - if (zSize < 0) { - console.error("negative zSize not allowed - will invert"); - zSize *= -1; - } - - let xSegments = cfg.xSegments || 1; - if (xSegments < 0) { - console.error("negative xSegments not allowed - will invert"); - xSegments *= -1; - } - if (xSegments < 1) { - xSegments = 1; - } - - let zSegments = cfg.xSegments || 1; - if (zSegments < 0) { - console.error("negative zSegments not allowed - will invert"); - zSegments *= -1; - } - if (zSegments < 1) { - zSegments = 1; - } - - const center = cfg.center; - const centerX = center ? center[0] : 0; - const centerY = center ? center[1] : 0; - const centerZ = center ? center[2] : 0; - - const halfWidth = xSize / 2; - const halfHeight = zSize / 2; - - const planeX = Math.floor(xSegments) || 1; - const planeZ = Math.floor(zSegments) || 1; - - const planeX1 = planeX + 1; - const planeZ1 = planeZ + 1; - - const segmentWidth = xSize / planeX; - const segmentHeight = zSize / planeZ; - - const positions = new Float32Array(planeX1 * planeZ1 * 3); - const normals = new Float32Array(planeX1 * planeZ1 * 3); - const uvs = new Float32Array(planeX1 * planeZ1 * 2); - - let offset = 0; - let offset2 = 0; - - let iz; - let ix; - let x; - let a; - let b; - let c; - let d; - - for (iz = 0; iz < planeZ1; iz++) { - - const z = iz * segmentHeight - halfHeight; - - for (ix = 0; ix < planeX1; ix++) { - - x = ix * segmentWidth - halfWidth; - - positions[offset] = x + centerX; - positions[offset + 1] = centerY; - positions[offset + 2] = -z + centerZ; - - normals[offset + 2] = -1; - - uvs[offset2] = (ix) / planeX; - uvs[offset2 + 1] = ((planeZ - iz) / planeZ); - - offset += 3; - offset2 += 2; - } - } - - offset = 0; - - const indices = new ((positions.length / 3) > 65535 ? Uint32Array : Uint16Array)(planeX * planeZ * 6); - - for (iz = 0; iz < planeZ; iz++) { - - for (ix = 0; ix < planeX; ix++) { - - a = ix + planeX1 * iz; - b = ix + planeX1 * (iz + 1); - c = (ix + 1) + planeX1 * (iz + 1); - d = (ix + 1) + planeX1 * iz; - - indices[offset] = d; - indices[offset + 1] = b; - indices[offset + 2] = a; - - indices[offset + 3] = d; - indices[offset + 4] = c; - indices[offset + 5] = b; - - offset += 6; - } - } - - return utils.apply(cfg, { - positions: positions, - normals: normals, - uv: uvs, - indices: indices - }); -} - -const tempVec3$1 = math.vec3(); -const tempVec3b$4 = math.vec3(); -math.vec3(); -const zeroVec = math.vec3([0, -1, 0]); -const tempQuat = math.vec4([0, 0, 0, 1]); - -/** - * @desc A plane-shaped 3D object containing a bitmap image. - * - * Use ````ImagePlane```` to embed bitmap images in your scenes. - * - * As shown in the examples below, ````ImagePlane```` is useful for creating ground planes from satellite maps and embedding 2D plan - * view images in cross-section slicing planes. - * - * # Example 1: Create a ground plane from a satellite image - * - * In our first example, we'll load the Schependomlaan model, then use - * an ````ImagePlane```` to create a ground plane, which will contain - * a satellite image sourced from Google Maps. - * - * - * - * [](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_groundPlane) - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_groundPlane)] - * - * ````javascript - * import {Viewer, ImagePlane, XKTLoaderPlugin} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [-8.31, 42.21, 54.30]; - * viewer.camera.look = [-0.86, 15.40, 14.90]; - * viewer.camera.up = [0.10, 0.83, -0.54]; - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * xktLoader.load({ // Load IFC model - * id: "myModel", - * src: "./models/xkt/Schependomlaan.xkt", - * edges: true, - * - * rotation: [0, 22, 0], // Rotate, position and scale the model to align it correctly with the ImagePlane - * position: [-8, 0, 15], - * scale: [1.1, 1.1, 1.1] - * }); - * - * new ImagePlane(viewer.scene, { - * src: "./images/schependomlaanSatMap.png", // Google satellite image; accepted file types are PNG and JPEG - * visible: true, // Show the ImagePlane - * gridVisible: true, // Show the grid - grid is only visible when ImagePlane is also visible - * size: 190, // Size of ImagePlane's longest edge - * position: [0, -1, 0], // World-space position of ImagePlane's center - * rotation: [0, 0, 0], // Euler angles for X, Y and Z - * opacity: 1.0, // Fully opaque - * collidable: false, // ImagePlane does not contribute to Scene boundary - * clippable: true, // ImagePlane can be clipped by SectionPlanes - * pickable: true // Allow the ground plane to be picked - * }); - * ```` - *
    - * - * # Example 2: Embed an image in a cross-section plane - * - * In our second example, we'll load the Schependomlaan model again, then slice it in half with - * a {@link SectionPlanesPlugin}, then use an ````ImagePlane```` to embed a 2D plan view image in the slicing plane. - * - * - * - * [](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_imageInSectionPlane) - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#ImagePlane_imageInSectionPlane)] - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, SectionPlanesPlugin, ImagePlane} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.camera.eye = [-9.11, 20.01, 5.13]; - * viewer.camera.look = [9.07, 0.77, -9.78]; - * viewer.camera.up = [0.47, 0.76, -0.38]; - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const sectionPlanes = new SectionPlanesPlugin(viewer, { - * overviewVisible: false - * }); - * - * model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/schependomlaan/schependomlaan.xkt", - * metaModelSrc: "./metaModels/schependomlaan/metaModel.json", - * edges: true, - * }); - * - * const sectionPlane = sectionPlanes.createSectionPlane({ - * id: "mySectionPlane", - * pos: [10.95, 1.95, -10.35], - * dir: [0.0, -1.0, 0.0] - * }); - * - * const imagePlane = new ImagePlane(viewer.scene, { - * src: "./images/schependomlaanPlanView.png", // Plan view image; accepted file types are PNG and JPEG - * visible: true, - * gridVisible: true, - * size: 23.95, - * position: sectionPlane.pos, - * dir: sectionPlane.dir, - * collidable: false, - * opacity: 0.75, - * clippable: false, // Don't allow ImagePlane to be clipped by the SectionPlane - * pickable: false // Don't allow ImagePlane to be picked - * }); - * ```` - */ -class ImagePlane extends Component { - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this ````ImagePlane```` as well. - * @param {*} [cfg] ````ImagePlane```` configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Boolean} [cfg.visible=true] Indicates whether or not this ````ImagePlane```` is visible. - * @param {Boolean} [cfg.gridVisible=true] Indicates whether or not the grid is visible. Grid is only visible when ````ImagePlane```` is also visible. - * @param {Number[]} [cfg.position=[0,0,0]] World-space position of the ````ImagePlane````. - * @param {Number[]} [cfg.size=1] World-space size of the longest edge of the ````ImagePlane````. Note that - * ````ImagePlane```` sets its aspect ratio to match its image. If we set a value of ````1000````, and the image - * has size ````400x300````, then the ````ImagePlane```` will then have size ````1000 x 750````. - * @param {Number[]} [cfg.rotation=[0,0,0]] Local rotation of the ````ImagePlane````, as Euler angles given in degrees, for each of the X, Y and Z axis. - * @param {Number[]} [cfg.matrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]] Modelling transform matrix for the ````ImagePlane````. Overrides the ````position````, ````size```, ````rotation```` and ````dir```` parameters. - * @param {Boolean} [cfg.collidable=true] Indicates if the ````ImagePlane```` is initially included in boundary calculations. - * @param {Boolean} [cfg.clippable=true] Indicates if the ````ImagePlane```` is initially clippable. - * @param {Boolean} [cfg.pickable=true] Indicates if the ````ImagePlane```` is initially pickable. - * @param {Number} [cfg.opacity=1.0] ````ImagePlane````'s initial opacity factor, multiplies by the rendered fragment alpha. - * @param {String} [cfg.src] URL of image. Accepted file types are PNG and JPEG. - * @param {HTMLImageElement} [cfg.image] An ````HTMLImageElement```` to source the image from. Overrides ````src````. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - this._src = null; - this._image = null; - this._pos = math.vec3(); - this._origin = math.vec3(); - this._rtcPos = math.vec3(); - this._dir = math.vec3(); - this._size = 1.0; - this._imageSize = math.vec2(); - - this._texture = new Texture(this); - - this._plane = new Mesh(this, { - - geometry: new ReadableGeometry(this, buildPlaneGeometry({ - center: [0, 0, 0], - xSize: 1, - zSize: 1, - xSegments: 10, - zSegments: 10 - })), - - material: new PhongMaterial(this, { - diffuse: [0, 0, 0], - ambient: [0, 0, 0], - specular: [0, 0, 0], - diffuseMap: this._texture, - emissiveMap: this._texture, - backfaces: true - }), - clippable: cfg.clippable - }); - - this._grid = new Mesh(this, { - geometry: new ReadableGeometry(this, buildGridGeometry({ - size: 1, - divisions: 10 - })), - material: new PhongMaterial(this, { - diffuse: [0.0, 0.0, 0.0], - ambient: [0.0, 0.0, 0.0], - emissive: [0.2, 0.8, 0.2] - }), - position: [0, 0.001, 0.0], - clippable: cfg.clippable - }); - - this._node = new Node$1(this, { - rotation: [0, 0, 0], - position: [0, 0, 0], - scale: [1, 1, 1], - clippable: false, - children: [ - this._plane, - this._grid - ] - }); - - this._gridVisible = false; - - this.visible = true; - this.gridVisible = cfg.gridVisible; - this.position = cfg.position; - this.rotation = cfg.rotation; - this.dir = cfg.dir; - this.size = cfg.size; - this.collidable = cfg.collidable; - this.clippable = cfg.clippable; - this.pickable = cfg.pickable; - this.opacity = cfg.opacity; - - if (cfg.image) { - this.image = cfg.image; - } else { - this.src = cfg.src; - } - } - - /** - * Sets if this ````ImagePlane```` is visible or not. - * - * Default value is ````true````. - * - * @param {Boolean} visible Set ````true```` to make this ````ImagePlane```` visible. - */ - set visible(visible) { - this._plane.visible = visible; - this._grid.visible = (this._gridVisible && visible); - } - - /** - * Gets if this ````ImagePlane```` is visible or not. - * - * Default value is ````true````. - * - * @returns {Boolean} Returns ````true```` if visible. - */ - get visible() { - return this._plane.visible; - } - - /** - * Sets if this ````ImagePlane````'s grid is visible or not. - * - * Default value is ````false````. - * - * Grid is only visible when ````ImagePlane```` is also visible. - * - * @param {Boolean} visible Set ````true```` to make this ````ImagePlane````'s grid visible. - */ - set gridVisible(visible) { - visible = (visible !== false); - this._gridVisible = visible; - this._grid.visible = (this._gridVisible && this.visible); - } - - /** - * Gets if this ````ImagePlane````'s grid is visible or not. - * - * Default value is ````false````. - * - * @returns {Boolean} Returns ````true```` if visible. - */ - get gridVisible() { - return this._gridVisible; - } - - /** - * Sets an ````HTMLImageElement```` to source the image from. - * - * Sets {@link Texture#src} null. - * - * @type {HTMLImageElement} - */ - set image(image) { - this._image = image; - if (this._image) { - this._imageSize[0] = image.width; - this._imageSize[1] = image.height; - this._updatePlaneSizeFromImage(); - this._src = null; - this._texture.image = this._image; - } - } - - /** - * Gets the ````HTMLImageElement```` the ````ImagePlane````'s image is sourced from, if set. - * - * Returns null if not set. - * - * @type {HTMLImageElement} - */ - get image() { - return this._image; - } - - /** - * Sets an image file path that the ````ImagePlane````'s image is sourced from. - * - * Accepted file types are PNG and JPEG. - * - * Sets {@link Texture#image} null. - * - * @type {String} - */ - set src(src) { - this._src = src; - if (this._src) { - this._image = null; - const image = new Image(); - image.onload = () => { - this._texture.image = image; - this._imageSize[0] = image.width; - this._imageSize[1] = image.height; - this._updatePlaneSizeFromImage(); - }; - image.src = this._src; - } - } - - /** - * Gets the image file path that the ````ImagePlane````'s image is sourced from, if set. - * - * Returns null if not set. - * - * @type {String} - */ - get src() { - return this._src; - } - - /** - * Sets the World-space position of this ````ImagePlane````. - * - * Default value is ````[0, 0, 0]````. - * - * @param {Number[]} value New position. - */ - set position(value) { - this._pos.set(value || [0, 0, 0]); - worldToRTCPos(this._pos, this._origin, this._rtcPos); - this._node.origin = this._origin; - this._node.position = this._rtcPos; - } - - /** - * Gets the World-space position of this ````ImagePlane````. - * - * Default value is ````[0, 0, 0]````. - * - * @returns {Number[]} Current position. - */ - get position() { - return this._pos; - } - - /** - * Sets the direction of this ````ImagePlane```` using Euler angles. - * - * Default value is ````[0, 0, 0]````. - * - * @param {Number[]} value Euler angles for ````X````, ````Y```` and ````Z```` axis rotations. - */ - set rotation(value) { - this._node.rotation = value; - } - - /** - * Gets the direction of this ````ImagePlane```` as Euler angles. - * - * @returns {Number[]} Euler angles for ````X````, ````Y```` and ````Z```` axis rotations. - */ - get rotation() { - return this._node.rotation; - } - - /** - * Sets the World-space size of the longest edge of the ````ImagePlane````. - * - * Note that ````ImagePlane```` sets its aspect ratio to match its image. If we set a value of ````1000````, and - * the image has size ````400x300````, then the ````ImagePlane```` will then have size ````1000 x 750````. - * - * Default value is ````1.0````. - * - * @param {Number} size New World-space size of the ````ImagePlane````. - */ - set size(size) { - this._size = (size === undefined || size === null) ? 1.0 : size; - if (this._image) { - this._updatePlaneSizeFromImage(); - } - } - - /** - * Gets the World-space size of the longest edge of the ````ImagePlane````. - * - * Returns {Number} World-space size of the ````ImagePlane````. - */ - get size() { - return this._size; - } - - /** - * Sets the direction of this ````ImagePlane```` as a direction vector. - * - * Default value is ````[0, 0, -1]````. - * - * @param {Number[]} dir New direction vector. - */ - set dir(dir) { - - this._dir.set(dir || [0, 0, -1]); - - if (dir) { - - const origin = this.scene.center; - const negDir = [-this._dir[0], -this._dir[1], -this._dir[2]]; - - math.subVec3(origin, this.position, tempVec3$1); - - const dist = -math.dotVec3(negDir, tempVec3$1); - - math.normalizeVec3(negDir); - math.mulVec3Scalar(negDir, dist, tempVec3b$4); - math.vec3PairToQuaternion(zeroVec, dir, tempQuat); - - this._node.quaternion = tempQuat; - } - } - - /** - * Gets the direction of this ````ImagePlane```` as a direction vector. - * - * @returns {Number[]} value Current direction. - */ - get dir() { - return this._dir; - } - - /** - * Sets if this ````ImagePlane```` is included in boundary calculations. - * - * Default is ````true````. - * - * @type {Boolean} - */ - set collidable(value) { - this._node.collidable = (value !== false); - } - - /** - * Gets if this ````ImagePlane```` is included in boundary calculations. - * - * Default is ````true````. - * - * @type {Boolean} - */ - get collidable() { - return this._node.collidable; - } - - /** - * Sets if this ````ImagePlane```` is clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * Default is ````true````. - * - * @type {Boolean} - */ - set clippable(value) { - this._node.clippable = (value !== false); - } - - /** - * Gets if this ````ImagePlane```` is clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * Default is ````true````. - * - * @type {Boolean} - */ - get clippable() { - return this._node.clippable; - } - - /** - * Sets if this ````ImagePlane```` is pickable. - * - * Default is ````true````. - * - * @type {Boolean} - */ - set pickable(value) { - this._node.pickable = (value !== false); - } - - /** - * Gets if this ````ImagePlane```` is pickable. - * - * Default is ````true````. - * - * @type {Boolean} - */ - get pickable() { - return this._node.pickable; - } - - /** - * Sets the opacity factor for this ````ImagePlane````. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - set opacity(opacity) { - this._node.opacity = opacity; - } - - /** - * Gets this ````ImagePlane````'s opacity factor. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - get opacity() { - return this._node.opacity; - } - - /** - * @destroy - */ - destroy() { - super.destroy(); - } - - _updatePlaneSizeFromImage() { - const size = this._size; - const width = this._imageSize[0]; - const height = this._imageSize[1]; - const aspect = height / width; - if (width > height) { - this._node.scale = [size, 1.0, size * aspect]; - } else { - this._node.scale = [size * aspect, 1.0, size]; - } - } -} - -/** - * A positional light source that originates from a single point and spreads outward in all directions, with optional attenuation over distance. - * - * * Has a position in {@link PointLight#pos}, but no direction. - * * Defined in either *World* or *View* coordinate space. When in World-space, {@link PointLight#pos} is relative to - * the World coordinate system, and will appear to move as the {@link Camera} moves. When in View-space, - * {@link PointLight#pos} is relative to the View coordinate system, and will behave as if fixed to the viewer's head. - * * Has {@link PointLight#constantAttenuation}, {@link PointLight#linearAttenuation} and {@link PointLight#quadraticAttenuation} - * factors, which indicate how intensity attenuates over distance. - * * {@link AmbientLight}s, {@link PointLight}s and {@link PointLight}s are registered by their {@link Component#id} on {@link Scene#lights}. - * - * ## Usage - * - * In the example below we'll replace the {@link Scene}'s default light sources with three World-space PointLights. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#lights_PointLight_world)] - * - * ````javascript - * import {Viewer, Mesh, buildSphereGeometry, buildPlaneGeometry, - * ReadableGeometry, PhongMaterial, Texture, PointLight} from "xeokit-sdk.es.js"; - * - * // Create a Viewer and arrange the camera - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0, 0, 5]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * // Replace the Scene's default lights with three custom world-space PointLights - * - * viewer.scene.clearLights(); - * - * new PointLight(viewer.scene,{ - * id: "keyLight", - * pos: [-80, 60, 80], - * color: [1.0, 0.3, 0.3], - * intensity: 1.0, - * space: "world" - * }); - * - * new PointLight(viewer.scene,{ - * id: "fillLight", - * pos: [80, 40, 40], - * color: [0.3, 1.0, 0.3], - * intensity: 1.0, - * space: "world" - * }); - * - * new PointLight(viewer.scene,{ - * id: "rimLight", - * pos: [-20, 80, -80], - * color: [0.6, 0.6, 0.6], - * intensity: 1.0, - * space: "world" - * }); - * - * // Create a sphere and ground plane - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ - * radius: 1.3 - * }), - * material: new PhongMaterial(viewer.scene, { - * diffuse: [0.7, 0.7, 0.7], - * specular: [1.0, 1.0, 1.0], - * emissive: [0, 0, 0], - * alpha: 1.0, - * ambient: [1, 1, 0], - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }) - * }) - * }); - * - * new Mesh(viewer.scene, { - * geometry: buildPlaneGeometry(ReadableGeometry, viewer.scene, { - * xSize: 30, - * zSize: 30 - * }), - * material: new PhongMaterial(viewer.scene, { - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }), - * backfaces: true - * }), - * position: [0, -2.1, 0] - * }); - * ```` - */ -class PointLight extends Light { - - /** - @private - */ - get type() { - return "PointLight"; - } - - /** - * @param {Component} owner Owner component. When destroyed, the owner will destroy this PointLight as well. - * @param {*} [cfg] The PointLight configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number[]} [cfg.pos=[ 1.0, 1.0, 1.0 ]] Position, in either World or View space, depending on the value of the **space** parameter. - * @param {Number[]} [cfg.color=[0.7, 0.7, 0.8 ]] Color of this PointLight. - * @param {Number} [cfg.intensity=1.0] Intensity of this PointLight, as a factor in range ````[0..1]````. - * @param {Number} [cfg.constantAttenuation=0] Constant attenuation factor. - * @param {Number} [cfg.linearAttenuation=0] Linear attenuation factor. - * @param {Number} [cfg.quadraticAttenuation=0]Quadratic attenuation factor. - * @param {String} [cfg.space="view"]The coordinate system this PointLight is defined in - "view" or "world". - * @param {Boolean} [cfg.castsShadow=false] Flag which indicates if this PointLight casts a castsShadow. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - const self = this; - - this._shadowRenderBuf = null; - this._shadowViewMatrix = null; - this._shadowProjMatrix = null; - this._shadowViewMatrixDirty = true; - this._shadowProjMatrixDirty = true; - - const camera = this.scene.camera; - const canvas = this.scene.canvas; - - this._onCameraViewMatrix = camera.on("viewMatrix", () => { - this._shadowViewMatrixDirty = true; - }); - - this._onCameraProjMatrix = camera.on("projMatrix", () => { - this._shadowProjMatrixDirty = true; - }); - - this._onCanvasBoundary = canvas.on("boundary", () => { - this._shadowProjMatrixDirty = true; - }); - - this._state = new RenderState({ - - type: "point", - pos: math.vec3([1.0, 1.0, 1.0]), - color: math.vec3([0.7, 0.7, 0.8]), - intensity: 1.0, attenuation: [0.0, 0.0, 0.0], - space: cfg.space || "view", - castsShadow: false, - - getShadowViewMatrix: () => { - if (self._shadowViewMatrixDirty) { - if (!self._shadowViewMatrix) { - self._shadowViewMatrix = math.identityMat4(); - } - const eye = self._state.pos; - const look = camera.look; - const up = camera.up; - math.lookAtMat4v(eye, look, up, self._shadowViewMatrix); - self._shadowViewMatrixDirty = false; - } - return self._shadowViewMatrix; - }, - - getShadowProjMatrix: () => { - if (self._shadowProjMatrixDirty) { // TODO: Set when canvas resizes - if (!self._shadowProjMatrix) { - self._shadowProjMatrix = math.identityMat4(); - } - const canvas = self.scene.canvas.canvas; - math.perspectiveMat4(70 * (Math.PI / 180.0), canvas.clientWidth / canvas.clientHeight, 0.1, 500.0, self._shadowProjMatrix); - self._shadowProjMatrixDirty = false; - } - return self._shadowProjMatrix; - }, - - getShadowRenderBuf: () => { - if (!self._shadowRenderBuf) { - self._shadowRenderBuf = new RenderBuffer(self.scene.canvas.canvas, self.scene.canvas.gl, {size: [1024, 1024]}); // Super old mobile devices have a limit of 1024x1024 textures - } - return self._shadowRenderBuf; - } - }); - - this.pos = cfg.pos; - this.color = cfg.color; - this.intensity = cfg.intensity; - this.constantAttenuation = cfg.constantAttenuation; - this.linearAttenuation = cfg.linearAttenuation; - this.quadraticAttenuation = cfg.quadraticAttenuation; - this.castsShadow = cfg.castsShadow; - - this.scene._lightCreated(this); - } - - /** - * Sets the position of this PointLight. - * - * This will be either World- or View-space, depending on the value of {@link PointLight#space}. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @param {Number[]} pos The position. - */ - set pos(pos) { - this._state.pos.set(pos || [1.0, 1.0, 1.0]); - this._shadowViewMatrixDirty = true; - this.glRedraw(); - } - - /** - * Gets the position of this PointLight. - * - * This will be either World- or View-space, depending on the value of {@link PointLight#space}. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @returns {Number[]} The position. - */ - get pos() { - return this._state.pos; - } - - /** - * Sets the RGB color of this PointLight. - * - * Default value is ````[0.7, 0.7, 0.8]````. - * - * @param {Number[]} color The PointLight's RGB color. - */ - set color(color) { - this._state.color.set(color || [0.7, 0.7, 0.8]); - this.glRedraw(); - } - - /** - * Gets the RGB color of this PointLight. - * - * Default value is ````[0.7, 0.7, 0.8]````. - * - * @returns {Number[]} The PointLight's RGB color. - */ - get color() { - return this._state.color; - } - - /** - * Sets the intensity of this PointLight. - * - * Default intensity is ````1.0```` for maximum intensity. - * - * @param {Number} intensity The PointLight's intensity - */ - set intensity(intensity) { - intensity = intensity !== undefined ? intensity : 1.0; - this._state.intensity = intensity; - this.glRedraw(); - } - - /** - * Gets the intensity of this PointLight. - * - * Default value is ````1.0```` for maximum intensity. - * - * @returns {Number} The PointLight's intensity. - */ - get intensity() { - return this._state.intensity; - } - - /** - * Sets the constant attenuation factor for this PointLight. - * - * Default value is ````0````. - * - * @param {Number} value The constant attenuation factor. - */ - set constantAttenuation(value) { - this._state.attenuation[0] = value || 0.0; - this.glRedraw(); - } - - /** - * Gets the constant attenuation factor for this PointLight. - * - * Default value is ````0````. - * - * @returns {Number} The constant attenuation factor. - */ - get constantAttenuation() { - return this._state.attenuation[0]; - } - - /** - * Sets the linear attenuation factor for this PointLight. - * - * Default value is ````0````. - * - * @param {Number} value The linear attenuation factor. - */ - set linearAttenuation(value) { - this._state.attenuation[1] = value || 0.0; - this.glRedraw(); - } - - /** - * Gets the linear attenuation factor for this PointLight. - * - * Default value is ````0````. - * - * @returns {Number} The linear attenuation factor. - */ - get linearAttenuation() { - return this._state.attenuation[1]; - } - - /** - * Sets the quadratic attenuation factor for this PointLight. - * - * Default value is ````0````. - * - * @param {Number} value The quadratic attenuation factor. - */ - set quadraticAttenuation(value) { - this._state.attenuation[2] = value || 0.0; - this.glRedraw(); - } - - /** - * Gets the quadratic attenuation factor for this PointLight. - * - * Default value is ````0````. - * - * @returns {Number} The quadratic attenuation factor. - */ - get quadraticAttenuation() { - return this._state.attenuation[2]; - } - - /** - * Sets if this PointLight casts a shadow. - * - * Default value is ````false````. - * - * @param {Boolean} castsShadow Set ````true```` to cast shadows. - */ - set castsShadow(castsShadow) { - castsShadow = !!castsShadow; - if (this._state.castsShadow === castsShadow) { - return; - } - this._state.castsShadow = castsShadow; - this._shadowViewMatrixDirty = true; - this.glRedraw(); - } - - /** - * Gets if this PointLight casts a shadow. - * - * Default value is ````false````. - * - * @returns {Boolean} ````true```` if this PointLight casts shadows. - */ - get castsShadow() { - return this._state.castsShadow; - } - - /** - * Destroys this PointLight. - */ - destroy() { - - const camera = this.scene.camera; - const canvas = this.scene.canvas; - camera.off(this._onCameraViewMatrix); - camera.off(this._onCameraProjMatrix); - canvas.off(this._onCanvasBoundary); - - super.destroy(); - - this._state.destroy(); - if (this._shadowRenderBuf) { - this._shadowRenderBuf.destroy(); - } - this.scene._lightDestroyed(this); - this.glRedraw(); - } -} - -function ensureImageSizePowerOfTwo(image) { - if (!isPowerOfTwo(image.width) || !isPowerOfTwo(image.height)) { - const canvas = document.createElement("canvas"); - canvas.width = nextHighestPowerOfTwo(image.width); - canvas.height = nextHighestPowerOfTwo(image.height); - const ctx = canvas.getContext("2d"); - ctx.drawImage(image, - 0, 0, image.width, image.height, - 0, 0, canvas.width, canvas.height); - image = canvas; - } - return image; -} - -function isPowerOfTwo(x) { - return (x & (x - 1)) === 0; -} - -function nextHighestPowerOfTwo(x) { - --x; - for (let i = 1; i < 32; i <<= 1) { - x = x | x >> i; - } - return x + 1; -} - -/** - * @desc A cube texture map. - */ -class CubeTexture extends Component { - - /** - @private - */ - get type() { - return "CubeTexture"; - } - - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for this CubeTexture, unique among all components in the parent scene, generated automatically when omitted. - * @param {String[]} [cfg.src=null] Paths to six image files to load into this CubeTexture. - * @param {Boolean} [cfg.flipY=false] Flips this CubeTexture's source data along its vertical axis when true. - * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - const gl = this.scene.canvas.gl; - - this._state = new RenderState({ - texture: new Texture2D({gl, target: gl.TEXTURE_CUBE_MAP}), - flipY: this._checkFlipY(cfg.minFilter), - encoding: this._checkEncoding(cfg.encoding), - minFilter: LinearMipmapLinearFilter, - magFilter: LinearFilter, - wrapS: ClampToEdgeWrapping, - wrapT: ClampToEdgeWrapping, - mipmaps: true - }); - - this._src = cfg.src; - this._images = []; - - this._loadSrc(cfg.src); - - stats.memory.textures++; - } - - _checkFlipY(value) { - return !!value; - } - - _checkEncoding(value) { - value = value || LinearEncoding; - if (value !== LinearEncoding && value !== sRGBEncoding) { - this.error("Unsupported value for 'encoding' - supported values are LinearEncoding and sRGBEncoding. Defaulting to LinearEncoding."); - value = LinearEncoding; - } - return value; - } - - _webglContextRestored() { - this.scene.canvas.gl; - this._state.texture = null; - // if (this._images.length > 0) { - // this._state.texture = new xeokit.renderer.Texture2D(gl, gl.TEXTURE_CUBE_MAP); - // this._state.texture.setImage(this._images, this._state); - // this._state.texture.setProps(this._state); - // } else - if (this._src) { - this._loadSrc(this._src); - } - } - - _loadSrc(src) { - const self = this; - const gl = this.scene.canvas.gl; - this._images = []; - let loadFailed = false; - let numLoaded = 0; - for (let i = 0; i < src.length; i++) { - const image = new Image(); - image.onload = (function () { - let _image = image; - const index = i; - return function () { - if (loadFailed) { - return; - } - _image = ensureImageSizePowerOfTwo(_image); - self._images[index] = _image; - numLoaded++; - if (numLoaded === 6) { - let texture = self._state.texture; - if (!texture) { - texture = new Texture2D({gl, target: gl.TEXTURE_CUBE_MAP}); - self._state.texture = texture; - } - texture.setImage(self._images, self._state); - self.fire("loaded", self._src, false); - self.glRedraw(); - } - }; - })(); - image.onerror = function () { - loadFailed = true; - }; - image.src = src[i]; - } - } - - /** - * Destroys this CubeTexture - * - */ - destroy() { - super.destroy(); - if (this._state.texture) { - this._state.texture.destroy(); - } - stats.memory.textures--; - this._state.destroy(); - } -} - -/** - * @desc A reflection cube map. - * - * ## Usage - * - * ````javascript - * import {Viewer, Mesh, buildSphereGeometry, - * ReadableGeometry, MetallicMaterial, ReflectionMap} from "xeokit-sdk.es.js"; - * - * // Create a Viewer and arrange the camera - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0, 0, 5]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * new ReflectionMap(viewer.scene, { - * src: [ - * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PX.png", - * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NX.png", - * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PY.png", - * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NY.png", - * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_PZ.png", - * "textures/reflect/Uffizi_Gallery/Uffizi_Gallery_Radiance_NZ.png" - * ] - * }); - * - * // Create a sphere and ground plane - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ - * radius: 2.0 - * }), - * new MetallicMaterial(viewer.scene, { - * baseColor: [1, 1, 1], - * metallic: 1.0, - * roughness: 1.0 - * }) - * }); - * ```` - */ -class ReflectionMap extends CubeTexture { - - /** - @private - */ - get type() { - return "ReflectionMap"; - } - - /** - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for this ReflectionMap, unique among all components in the parent scene, generated automatically when omitted. - * @param {String[]} [cfg.src=null] Paths to six image files to load into this ReflectionMap. - * @param {Boolean} [cfg.flipY=false] Flips this ReflectionMap's source data along its vertical axis when true. - * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this.scene._lightsState.addReflectionMap(this._state); - this.scene._reflectionMapCreated(this); - } - - /** - * Destroys this ReflectionMap. - */ - destroy() { - super.destroy(); - this.scene._reflectionMapDestroyed(this); - } -} - -/** - * @desc A **LightMap** specifies a cube texture light map. - * - * ## Usage - * - * ````javascript - * import {Viewer, Mesh, buildSphereGeometry, - * ReadableGeometry, MetallicMaterial, LightMap} from "xeokit-sdk.es.js"; - * - * // Create a Viewer and arrange the camera - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.scene.camera.eye = [0, 0, 5]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * new LightMap(viewer.scene, { - * src: [ - * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PX.png", - * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NX.png", - * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PY.png", - * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NY.png", - * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_PZ.png", - * "textures/light/Uffizi_Gallery/Uffizi_Gallery_Irradiance_NZ.png" - * ] - * }); - * - * // Create a sphere and ground plane - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildSphereGeometry({ - * radius: 2.0 - * }), - * new MetallicMaterial(viewer.scene, { - * baseColor: [1, 1, 1], - * metallic: 1.0, - * roughness: 1.0 - * }) - * }); - * ```` - */ -class LightMap extends CubeTexture { - - /** - @private - */ - get type() { - return "LightMap"; - } - - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this component as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for this LightMap, unique among all components in the parent scene, generated automatically when omitted. - * @param {String:Object} [cfg.meta] Optional map of user-defined metadata to attach to this LightMap. - * @param {String[]} [cfg.src=null] Paths to six image files to load into this LightMap. - * @param {Boolean} [cfg.flipY=false] Flips this LightMap's source data along its vertical axis when true. - * @param {Number} [cfg.encoding=LinearEncoding] Encoding format. Supported values are {@link LinearEncoding} and {@link sRGBEncoding}. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this.scene._lightMapCreated(this); - } - - destroy() { - super.destroy(); - this.scene._lightMapDestroyed(this); - } -} - -/** - * @desc Configures Fresnel effects for {@link PhongMaterial}s. - * - * Fresnels are attached to {@link PhongMaterial}s, which are attached to {@link Mesh}es. - * - * ## Usage - * - * In the example below we'll create a {@link Mesh} with a {@link PhongMaterial} that applies a Fresnel to its alpha channel to give a glasss-like effect. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#materials_Fresnel)] - * - * ````javascript - * import {Viewer, Mesh, buildTorusGeometry, - * ReadableGeometry, PhongMaterial, Texture, Fresnel} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [0, 0, 5]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * new Mesh(viewer.scene, { - * geometry: new ReadableGeometry(viewer.scene, buildTorusGeometry({ - * center: [0, 0, 0], - * radius: 1.5, - * tube: 0.5, - * radialSegments: 32, - * tubeSegments: 24, - * arc: Math.PI * 2.0 - * }), - * material: new PhongMaterial(viewer.scene, { - * alpha: 0.9, - * alphaMode: "blend", - * ambient: [0.0, 0.0, 0.0], - * shininess: 30, - * diffuseMap: new Texture(viewer.scene, { - * src: "textures/diffuse/uvGrid2.jpg" - * }), - * alphaFresnel: new Fresnel(viewer.scene, { -v edgeBias: 0.2, - * centerBias: 0.8, - * edgeColor: [1.0, 1.0, 1.0], - * centerColor: [0.0, 0.0, 0.0], - * power: 2 - * }) - * }) - * }); - * ```` - */ -class Fresnel extends Component { - - /** - * JavaScript class name for this Component. - * - * @type {String} - */ - get type() { - return "Fresnel"; - } - - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this Fresnel as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent scene, generated automatically when omitted. - * @param {Number[]} [cfg.edgeColor=[ 0.0, 0.0, 0.0 ]] Color used on edges. - * @param {Number[]} [cfg.centerColor=[ 1.0, 1.0, 1.0 ]] Color used on center. - * @param {Number} [cfg.edgeBias=0] Bias at the edge. - * @param {Number} [cfg.centerBias=1] Bias at the center. - * @param {Number} [cfg.power=0] The power. - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - this._state = new RenderState({ - edgeColor: math.vec3([0, 0, 0]), - centerColor: math.vec3([1, 1, 1]), - edgeBias: 0, - centerBias: 1, - power: 1 - }); - - this.edgeColor = cfg.edgeColor; - this.centerColor = cfg.centerColor; - this.edgeBias = cfg.edgeBias; - this.centerBias = cfg.centerBias; - this.power = cfg.power; - } - - /** - * Sets the Fresnel's edge color. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @type {Number[]} - */ - set edgeColor(value) { - this._state.edgeColor.set(value || [0.0, 0.0, 0.0]); - this.glRedraw(); - } - - /** - * Gets the Fresnel's edge color. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @type {Number[]} - */ - get edgeColor() { - return this._state.edgeColor; - } - - /** - * Sets the Fresnel's center color. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @type {Number[]} - */ - set centerColor(value) { - this._state.centerColor.set(value || [1.0, 1.0, 1.0]); - this.glRedraw(); - } - - /** - * Gets the Fresnel's center color. - * - * Default value is ````[1.0, 1.0, 1.0]````. - * - * @type {Number[]} - */ - get centerColor() { - return this._state.centerColor; - } - - /** - * Sets the Fresnel's edge bias. - * - * Default value is ````0````. - * - * @type {Number} - */ - set edgeBias(value) { - this._state.edgeBias = value || 0; - this.glRedraw(); - } - - /** - * Gets the Fresnel's edge bias. - * - * Default value is ````0````. - * - * @type {Number} - */ - get edgeBias() { - return this._state.edgeBias; - } - - /** - * Sets the Fresnel's center bias. - * - * Default value is ````1````. - * - * @type {Number} - */ - set centerBias(value) { - this._state.centerBias = (value !== undefined && value !== null) ? value : 1; - this.glRedraw(); - } - - /** - * Gets the Fresnel's center bias. - * - * Default value is ````1````. - * - * @type {Number} - */ - get centerBias() { - return this._state.centerBias; - } - - /** - * Sets the Fresnel's power. - * - * Default value is ````1````. - * - * @type {Number} - */ - set power(value) { - this._state.power = (value !== undefined && value !== null) ? value : 1; - this.glRedraw(); - } - - /** - * Gets the Fresnel's power. - * - * Default value is ````1````. - * - * @type {Number} - */ - get power() { - return this._state.power; - } - - /** - * Destroys this Fresnel. - */ - destroy() { - super.destroy(); - this._state.destroy(); - } -} - -/** - * A {@link Marker} with a billboarded and textured quad attached to it. - * - * * Extends {@link Marker} - * * Keeps the quad oriented towards the viewpoint - * * Auto-fits the quad to the texture - * * Has a world-space position - * * Can be configured to hide the quad whenever the position is occluded by some other object - * - * ## Usage - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#markers_SpriteMarker)] - * - * ```` javascript - * import {Viewer, SpriteMarker } from "./../dist/xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas", - * transparent: true - * }); - * - * viewer.scene.camera.eye = [0, 0, 25]; - * viewer.scene.camera.look = [0, 0, 0]; - * viewer.scene.camera.up = [0, 1, 0]; - * - * new SpriteMarker(viewer.scene, { - * worldPos: [-10, 0, 0], - * src: "../assets/textures/diffuse/uvGrid2_512x1024.jpg", - * size: 5, - * occludable: false - * }); - * - * new SpriteMarker(viewer.scene, { - * worldPos: [+10, 0, 0], - * src: "../assets/textures/diffuse/uvGrid2_1024x512.jpg", - * size: 4, - * occludable: false - * }); - *```` - */ -class SpriteMarker extends Marker { - - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this SpriteMarker as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID for this SpriteMarker, unique among all components in the parent scene, generated automatically when omitted. - * @param {Entity} [cfg.entity] Entity to associate this Marker with. When the SpriteMarker has an Entity, then {@link Marker#visible} will always be ````false```` if {@link Entity#visible} is false. - * @param {Boolean} [cfg.occludable=false] Indicates whether or not this Marker is hidden (ie. {@link Marker#visible} is ````false```` whenever occluded by {@link Entity}s in the {@link Scene}. - * @param {Number[]} [cfg.worldPos=[0,0,0]] World-space 3D Marker position. - * @param {String} [cfg.src=null] Path to image file to load into this SpriteMarker. See the {@link SpriteMarker#src} property for more info. - * @param {HTMLImageElement} [cfg.image=null] HTML Image object to load into this SpriteMarker. See the {@link SpriteMarker#image} property for more info. - * @param {Boolean} [cfg.flipY=false] Flips this SpriteMarker's texture image along its vertical axis when true. - * @param {String} [cfg.encoding="linear"] Texture encoding format. See the {@link Texture#encoding} property for more info. - */ - constructor(owner, cfg = {}) { - - super(owner, { - entity: cfg.entity, - occludable: cfg.occludable, - worldPos: cfg.worldPos - }); - - this._occluded = false; - this._visible = true; - this._src = null; - this._image = null; - this._pos = math.vec3(); - this._origin = math.vec3(); - this._rtcPos = math.vec3(); - this._dir = math.vec3(); - this._size = 1.0; - this._imageSize = math.vec2(); - - this._texture = new Texture(this, { - src: cfg.src - }); - - this._geometry = new ReadableGeometry(this, { - primitive: "triangles", - positions: [3, 3, 0, -3, 3, 0, -3, -3, 0, 3, -3, 0], - normals: [-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0], - uv: [1, -1, 0, -1, 0, 0, 1, 0], - indices: [0, 1, 2, 0, 2, 3] // Ensure these will be front-faces - }); - - this._mesh = new Mesh(this, { - geometry: this._geometry, - material: new PhongMaterial(this, { - ambient: [0.9, 0.3, 0.9], - shininess: 30, - diffuseMap: this._texture, - backfaces: true - }), - scale: [1, 1, 1], // Note: by design, scale does not work with billboard - position: cfg.worldPos, - rotation: [90, 0, 0], - billboard: "spherical", - occluder: false // Don't occlude SpriteMarkers or Annotations +// dist/web-ifc.js +var require_web_ifc = __commonJS({ + "dist/web-ifc.js"(exports, module) { + var WebIFCWasm2 = function() { + var _scriptDir = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : void 0; + if (typeof __filename !== "undefined") + _scriptDir = _scriptDir || __filename; + return function(WebIFCWasm3) { + WebIFCWasm3 = WebIFCWasm3 || {}; + var Module = typeof WebIFCWasm3 !== "undefined" ? WebIFCWasm3 : {}; + var readyPromiseResolve, readyPromiseReject; + Module["ready"] = new Promise(function(resolve, reject) { + readyPromiseResolve = resolve; + readyPromiseReject = reject; }); - - this.visible = true; - this.collidable = cfg.collidable; - this.clippable = cfg.clippable; - this.pickable = cfg.pickable; - this.opacity = cfg.opacity; - this.size = cfg.size; - - if (cfg.image) { - this.image = cfg.image; - } else { - this.src = cfg.src; - } - } - - _setVisible(visible) { // Called by VisibilityTester and this._entity.on("destroyed"..) - this._occluded = (!visible); - this._mesh.visible = this._visible && (!this._occluded); - super._setVisible(visible); - } - - /** - * Sets if this ````SpriteMarker```` is visible or not. - * - * Default value is ````true````. - * - * @param {Boolean} visible Set ````true```` to make this ````SpriteMarker```` visible. - */ - set visible(visible) { - this._visible = (visible === null || visible === undefined) ? true : visible; - this._mesh.visible = this._visible && (!this._occluded); - } - - /** - * Gets if this ````SpriteMarker```` is visible or not. - * - * Default value is ````true````. - * - * @returns {Boolean} Returns ````true```` if visible. - */ - get visible() { - return this._visible; - } - - /** - * Sets an ````HTMLImageElement```` to source the image from. - * - * Sets {@link Texture#src} null. - * - * @type {HTMLImageElement} - */ - set image(image) { - this._image = image; - if (this._image) { - this._imageSize[0] = this._image.width; - this._imageSize[1] = this._image.height; - this._updatePlaneSizeFromImage(); - this._src = null; - this._texture.image = this._image; - } - } - - /** - * Gets the ````HTMLImageElement```` the ````SpriteMarker````'s image is sourced from, if set. - * - * Returns null if not set. - * - * @type {HTMLImageElement} - */ - get image() { - return this._image; - } - - /** - * Sets an image file path that the ````SpriteMarker````'s image is sourced from. - * - * Accepted file types are PNG and JPEG. - * - * Sets {@link Texture#image} null. - * - * @type {String} - */ - set src(src) { - this._src = src; - if (this._src) { - this._image = null; - const image = new Image(); - image.onload = () => { - this._texture.image = image; - this._imageSize[0] = image.width; - this._imageSize[1] = image.height; - this._updatePlaneSizeFromImage(); - }; - image.src = this._src; - } - } - - /** - * Gets the image file path that the ````SpriteMarker````'s image is sourced from, if set. - * - * Returns null if not set. - * - * @type {String} - */ - get src() { - return this._src; - } - - /** - * Sets the World-space size of the longest edge of the ````SpriteMarker````. - * - * Note that ````SpriteMarker```` sets its aspect ratio to match its image. If we set a value of ````1000````, and - * the image has size ````400x300````, then the ````SpriteMarker```` will then have size ````1000 x 750````. - * - * Default value is ````1.0````. - * - * @param {Number} size New World-space size of the ````SpriteMarker````. - */ - set size(size) { - this._size = (size === undefined || size === null) ? 1.0 : size; - if (this._image) { - this._updatePlaneSizeFromImage(); - } - } - - /** - * Gets the World-space size of the longest edge of the ````SpriteMarker````. - * - * Returns {Number} World-space size of the ````SpriteMarker````. - */ - get size() { - return this._size; - } - - /** - * Sets if this ````SpriteMarker```` is included in boundary calculations. - * - * Default is ````true````. - * - * @type {Boolean} - */ - set collidable(value) { - this._mesh.collidable = (value !== false); - } - - /** - * Gets if this ````SpriteMarker```` is included in boundary calculations. - * - * Default is ````true````. - * - * @type {Boolean} - */ - get collidable() { - return this._mesh.collidable; - } - - /** - * Sets if this ````SpriteMarker```` is clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * Default is ````true````. - * - * @type {Boolean} - */ - set clippable(value) { - this._mesh.clippable = (value !== false); - } - - /** - * Gets if this ````SpriteMarker```` is clippable. - * - * Clipping is done by the {@link SectionPlane}s in {@link Scene#sectionPlanes}. - * - * Default is ````true````. - * - * @type {Boolean} - */ - get clippable() { - return this._mesh.clippable; - } - - /** - * Sets if this ````SpriteMarker```` is pickable. - * - * Default is ````true````. - * - * @type {Boolean} - */ - set pickable(value) { - this._mesh.pickable = (value !== false); - } - - /** - * Gets if this ````SpriteMarker```` is pickable. - * - * Default is ````true````. - * - * @type {Boolean} - */ - get pickable() { - return this._mesh.pickable; - } - - /** - * Sets the opacity factor for this ````SpriteMarker````. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - set opacity(opacity) { - this._mesh.opacity = opacity; - } - - /** - * Gets this ````SpriteMarker````'s opacity factor. - * - * This is a factor in range ````[0..1]```` which multiplies by the rendered fragment alphas. - * - * @type {Number} - */ - get opacity() { - return this._mesh.opacity; - } - - _updatePlaneSizeFromImage() { - const halfSize = this._size * 0.5; - const width = this._imageSize[0]; - const height = this._imageSize[1]; - const aspect = height / width; - if (width > height) { - this._geometry.positions = [ - halfSize, halfSize * aspect, 0, - -halfSize, halfSize * aspect, 0, - -halfSize, -halfSize * aspect, 0, - halfSize, -halfSize * aspect, 0 - ]; - } else { - this._geometry.positions = [ - halfSize / aspect, halfSize, 0, - -halfSize / aspect, halfSize, 0, - -halfSize / aspect, -halfSize, 0, - halfSize / aspect, -halfSize, 0 - ]; - } - } -} - -const color = math.vec3(); - -/** - * @desc Saves and restores a snapshot of the visual state of the {@link Entity}'s of a model within a {@link Scene}. - * - * ## Usage - * - * In the example below, we'll create a {@link Viewer} and use an {@link XKTLoaderPlugin} to load an ````.xkt```` model. When the model has loaded, we'll hide a couple of {@link Entity}s and save a snapshot of the visual states of all its Entitys in an ModelMemento. Then we'll show all the Entitys - * again, and then we'll restore the visual states of all the Entitys again from the ModelMemento, which will hide those two Entitys again. - * - * ## See Also - * - * * {@link CameraMemento} - Saves and restores the state of a {@link Scene}'s {@link Camera}. - * * {@link ObjectsMemento} - Saves and restores a snapshot of the visual state of the {@link Entity}'s that represent objects within a {@link Scene}. - * - * ````javascript - * import {Viewer, XKTLoaderPlugin, ModelMemento} from "xeokit-sdk.es.js"; - * - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * // Load a model - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * id: "myModel", - * src: "./models/xkt/schependomlaan/schependomlaan.xkt" - * }); - * - * model.on("loaded", () => { - * - * // Model has loaded - * - * // Hide a couple of objects - * viewer.scene.objects["0u4wgLe6n0ABVaiXyikbkA"].visible = false; - * viewer.scene.objects["3u4wgLe3n0AXVaiXyikbYO"].visible = false; - * - * // Save memento of all object states, which includes those two hidden objects - * const ModelMemento = new ModelMemento(); - * - * const metaModel = viewer.metaScene.metaModels - * ModelMemento.saveObjects(viewer.scene); - * - * // Show all objects - * viewer.scene.setObjectsVisible(viewer.scene.objectIds, true); - * - * // Restore the objects states again, which involves hiding those two objects again - * ModelMemento.restoreObjects(viewer.scene); - * }); - * ````` - * - * ## Masking Saved State - * - * We can optionally supply a mask to focus what state we save and restore. - * - * For example, to save and restore only the {@link Entity#visible} and {@link Entity#clippable} states: - * - * ````javascript - * ModelMemento.saveObjects(viewer.scene, { - * visible: true, - * clippable: true - * }); - * - * //... - * - * // Restore the objects states again - * ModelMemento.restoreObjects(viewer.scene); - * ```` - */ -class ModelMemento { - - /** - * Creates a ModelMemento. - * - * @param {MetaModel} [metaModel] When given, immediately saves the model's {@link Entity} states to this ModelMemento. - */ - constructor(metaModel) { - - /** @private */ - this.objectsVisible = []; - - /** @private */ - this.objectsEdges = []; - - /** @private */ - this.objectsXrayed = []; - - /** @private */ - this.objectsHighlighted = []; - - /** @private */ - this.objectsSelected = []; - - /** @private */ - this.objectsClippable = []; - - /** @private */ - this.objectsPickable = []; - - /** @private */ - this.objectsColorize = []; - - /** @private */ - this.objectsOpacity = []; - - /** @private */ - this.numObjects = 0; - - if (metaModel) { - const metaScene = metaModel.metaScene; - const scene = metaScene.scene; - this.saveObjects(scene, metaModel); + var moduleOverrides = {}; + var key; + for (key in Module) { + if (Module.hasOwnProperty(key)) { + moduleOverrides[key] = Module[key]; + } } - } - - /** - * Saves a snapshot of the visual state of the {@link Entity}'s that represent objects within a model. - * - * @param {Scene} scene The scene. - * @param {MetaModel} metaModel Represents the model. Corresponds with an {@link Entity} that represents the model in the scene. - * @param {Object} [mask] Masks what state gets saved. Saves all state when not supplied. - * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. - * @param {boolean} [mask.visible] Saves {@link Entity#visible} values when ````true````. - * @param {boolean} [mask.edges] Saves {@link Entity#edges} values when ````true````. - * @param {boolean} [mask.xrayed] Saves {@link Entity#xrayed} values when ````true````. - * @param {boolean} [mask.highlighted] Saves {@link Entity#highlighted} values when ````true````. - * @param {boolean} [mask.selected] Saves {@link Entity#selected} values when ````true````. - * @param {boolean} [mask.clippable] Saves {@link Entity#clippable} values when ````true````. - * @param {boolean} [mask.pickable] Saves {@link Entity#pickable} values when ````true````. - * @param {boolean} [mask.colorize] Saves {@link Entity#colorize} values when ````true````. - * @param {boolean} [mask.opacity] Saves {@link Entity#opacity} values when ````true````. - */ - saveObjects(scene, metaModel, mask) { - - const rootMetaObject = metaModel.rootMetaObject; - if (!rootMetaObject) { - return; + var thisProgram = "./this.program"; + var quit_ = function(status, toThrow) { + throw toThrow; + }; + var ENVIRONMENT_IS_WEB = typeof window === "object"; + var ENVIRONMENT_IS_WORKER = typeof importScripts === "function"; + var ENVIRONMENT_IS_NODE = typeof process === "object" && typeof process.versions === "object" && typeof process.versions.node === "string"; + var scriptDirectory = ""; + function locateFile(path) { + if (Module["locateFile"]) { + return Module["locateFile"](path, scriptDirectory); + } + return scriptDirectory + path; } - - const objectIds = rootMetaObject.getObjectIDsInSubtree(); - - this.numObjects = 0; - - this._mask = mask ? utils.apply(mask, {}) : null; - - const objects = scene.objects; - const visible = (!mask || mask.visible); - const edges = (!mask || mask.edges); - const xrayed = (!mask || mask.xrayed); - const highlighted = (!mask || mask.highlighted); - const selected = (!mask || mask.selected); - const clippable = (!mask || mask.clippable); - const pickable = (!mask || mask.pickable); - const colorize = (!mask || mask.colorize); - const opacity = (!mask || mask.opacity); - - for (var i = 0, len = objectIds.length; i < len; i++) { - const objectId = objectIds[i]; - const object = objects[objectId]; - if (!object) { - continue; - } - if (visible) { - this.objectsVisible[i] = object.visible; - } - if (edges) { - this.objectsEdges[i] = object.edges; - } - if (xrayed) { - this.objectsXrayed[i] = object.xrayed; - } - if (highlighted) { - this.objectsHighlighted[i] = object.highlighted; - } - if (selected) { - this.objectsSelected[i] = object.selected; - } - if (clippable) { - this.objectsClippable[i] = object.clippable; + var read_, readAsync, readBinary; + var nodeFS; + var nodePath; + if (ENVIRONMENT_IS_NODE) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = __require("path").dirname(scriptDirectory) + "/"; + } else { + scriptDirectory = __dirname + "/"; + } + read_ = function shell_read(filename, binary) { + if (!nodeFS) + nodeFS = __require("fs"); + if (!nodePath) + nodePath = __require("path"); + filename = nodePath["normalize"](filename); + return nodeFS["readFileSync"](filename, binary ? null : "utf8"); + }; + readBinary = function readBinary2(filename) { + var ret = read_(filename, true); + if (!ret.buffer) { + ret = new Uint8Array(ret); } - if (pickable) { - this.objectsPickable[i] = object.pickable; + assert(ret.buffer); + return ret; + }; + readAsync = function readAsync2(filename, onload, onerror) { + if (!nodeFS) + nodeFS = __require("fs"); + if (!nodePath) + nodePath = __require("path"); + filename = nodePath["normalize"](filename); + nodeFS["readFile"](filename, function(err2, data) { + if (err2) + onerror(err2); + else + onload(data.buffer); + }); + }; + if (process["argv"].length > 1) { + thisProgram = process["argv"][1].replace(/\\/g, "/"); + } + process["argv"].slice(2); + process["on"]("uncaughtException", function(ex) { + if (!(ex instanceof ExitStatus)) { + throw ex; } - if (colorize) { - const objectColor = object.colorize; - this.objectsColorize[i * 3 + 0] = objectColor[0]; - this.objectsColorize[i * 3 + 1] = objectColor[1]; - this.objectsColorize[i * 3 + 2] = objectColor[2]; + }); + process["on"]("unhandledRejection", abort); + quit_ = function(status, toThrow) { + if (keepRuntimeAlive()) { + process["exitCode"] = status; + throw toThrow; } - if (opacity) { - this.objectsOpacity[i] = object.opacity; + process["exit"](status); + }; + Module["inspect"] = function() { + return "[Emscripten Module object]"; + }; + } else if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { + if (ENVIRONMENT_IS_WORKER) { + scriptDirectory = self.location.href; + } else if (typeof document !== "undefined" && document.currentScript) { + scriptDirectory = document.currentScript.src; + } + if (_scriptDir) { + scriptDirectory = _scriptDir; + } + if (scriptDirectory.indexOf("blob:") !== 0) { + scriptDirectory = scriptDirectory.substr(0, scriptDirectory.lastIndexOf("/") + 1); + } else { + scriptDirectory = ""; + } + { + read_ = function(url) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, false); + xhr.send(null); + return xhr.responseText; + }; + if (ENVIRONMENT_IS_WORKER) { + readBinary = function(url) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, false); + xhr.responseType = "arraybuffer"; + xhr.send(null); + return new Uint8Array(xhr.response); + }; } - this.numObjects++; + readAsync = function(url, onload, onerror) { + var xhr = new XMLHttpRequest(); + xhr.open("GET", url, true); + xhr.responseType = "arraybuffer"; + xhr.onload = function() { + if (xhr.status == 200 || xhr.status == 0 && xhr.response) { + onload(xhr.response); + return; + } + onerror(); + }; + xhr.onerror = onerror; + xhr.send(null); + }; + } + } else ; + var out = Module["print"] || console.log.bind(console); + var err = Module["printErr"] || console.warn.bind(console); + for (key in moduleOverrides) { + if (moduleOverrides.hasOwnProperty(key)) { + Module[key] = moduleOverrides[key]; + } } - } - - /** - * Restores a {@link Scene}'s {@link Entity}'s to their state previously captured with {@link ModelMemento#saveObjects}. - * - * Assumes that the model has not been destroyed or modified since saving. - * - * @param {Scene} scene The scene that was given to {@link ModelMemento#saveObjects}. - * @param {MetaModel} metaModel The metamodel that was given to {@link ModelMemento#saveObjects}. - */ - restoreObjects(scene, metaModel) { - - const rootMetaObject = metaModel.rootMetaObject; - if (!rootMetaObject) { - return; + moduleOverrides = null; + if (Module["arguments"]) + ; + if (Module["thisProgram"]) + thisProgram = Module["thisProgram"]; + if (Module["quit"]) + quit_ = Module["quit"]; + var wasmBinary; + if (Module["wasmBinary"]) + wasmBinary = Module["wasmBinary"]; + var noExitRuntime = Module["noExitRuntime"] || true; + if (typeof WebAssembly !== "object") { + abort("no native wasm support detected"); } - - const objectIds = rootMetaObject.getObjectIDsInSubtree(); - - const mask = this._mask; - - const visible = (!mask || mask.visible); - const edges = (!mask || mask.edges); - const xrayed = (!mask || mask.xrayed); - const highlighted = (!mask || mask.highlighted); - const selected = (!mask || mask.selected); - const clippable = (!mask || mask.clippable); - const pickable = (!mask || mask.pickable); - const colorize = (!mask || mask.colorize); - const opacity = (!mask || mask.opacity); - - const objects = scene.objects; - - for (var i = 0, len = objectIds.length; i < len; i++) { - const objectId = objectIds[i]; - const object = objects[objectId]; - if (!object) { + var wasmMemory; + var ABORT = false; + function assert(condition, text) { + if (!condition) { + abort("Assertion failed: " + text); + } + } + var UTF8Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf8") : void 0; + function UTF8ArrayToString(heap, idx, maxBytesToRead) { + idx >>>= 0; + var endIdx = idx + maxBytesToRead; + var endPtr = idx; + while (heap[endPtr >>> 0] && !(endPtr >= endIdx)) + ++endPtr; + if (endPtr - idx > 16 && heap.subarray && UTF8Decoder) { + return UTF8Decoder.decode(heap.subarray(idx >>> 0, endPtr >>> 0)); + } else { + var str = ""; + while (idx < endPtr) { + var u0 = heap[idx++ >>> 0]; + if (!(u0 & 128)) { + str += String.fromCharCode(u0); continue; + } + var u1 = heap[idx++ >>> 0] & 63; + if ((u0 & 224) == 192) { + str += String.fromCharCode((u0 & 31) << 6 | u1); + continue; + } + var u2 = heap[idx++ >>> 0] & 63; + if ((u0 & 240) == 224) { + u0 = (u0 & 15) << 12 | u1 << 6 | u2; + } else { + u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | heap[idx++ >>> 0] & 63; + } + if (u0 < 65536) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 65536; + str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); + } } - if (visible) { - object.visible = this.objectsVisible[i]; - } - if (edges) { - object.edges = this.objectsEdges[i]; - } - if (xrayed) { - object.xrayed = this.objectsXrayed[i]; - } - if (highlighted) { - object.highlighted = this.objectsHighlighted[i]; - } - if (selected) { - object.selected = this.objectsSelected[i]; - } - if (clippable) { - object.clippable = this.objectsClippable[i]; - } - if (pickable) { - object.pickable = this.objectsPickable[i]; - } - if (colorize) { - color[0] = this.objectsColorize[i * 3 + 0]; - color[1] = this.objectsColorize[i * 3 + 1]; - color[2] = this.objectsColorize[i * 3 + 2]; - object.colorize = color; - } - if (opacity) { - object.opacity = this.objectsOpacity[i]; - } - } - } -} - -/** - * @desc A {@link Curve} along which a 3D position can be animated. - * - * * As shown in the diagram below, a CubicBezierCurve is defined by four control points. - * * You can sample a {@link CubicBezierCurve#point} and a {@link CubicBezierCurve#tangent} vector on a CubicBezierCurve for any given value of {@link CubicBezierCurve#t} in the range [0..1]. - * * When you set {@link CubicBezierCurve#t} on a CubicBezierCurve, its {@link CubicBezierCurve#point} and {@link CubicBezierCurve#tangent} properties will update accordingly. - * * To build a complex path, you can combine an unlimited combination of CubicBezierCurves, {@link QuadraticBezierCurve}s and {@link SplineCurve}s into a {@link Path}. - * - *
    - * - *
    - * [Cubic Bezier Curve from WikiPedia](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) - */ -class CubicBezierCurve extends Curve { - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this CubicBezierCurve as well. - * @param {*} [cfg] Configs - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {Number[]} [cfg.v0=[0,0,0]] The starting point. - * @param {Number[]} [cfg.v1=[0,0,0]] The first control point. - * @param {Number[]} [cfg.v2=[0,0,0]] The middle control point. - * @param {Number[]} [cfg.v3=[0,0,0]] The ending point. - * @param {Number} [cfg.t=0] Current position on this CubicBezierCurve, in range between 0..1. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this.v0 = cfg.v0; - this.v1 = cfg.v1; - this.v2 = cfg.v2; - this.v3 = cfg.v3; - this.t = cfg.t; - } - - /** - * Sets the starting point on this CubicBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @param {Number[]} value The starting point. - */ - set v0(value) { - this._v0 = value || math.vec3([0, 0, 0]); - } - - /** - * Gets the starting point on this CubicBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @returns {Number[]} The starting point. - */ - get v0() { - return this._v0; - } - - /** - * Sets the first control point on this CubicBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @param {Number[]} value The first control point. - */ - set v1(value) { - this._v1 = value || math.vec3([0, 0, 0]); - } - - /** - * Gets the first control point on this CubicBezierCurve. - * - * Fires a {@link CubicBezierCurve#v1:event} event on change. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @returns {Number[]} The first control point. - */ - get v1() { - return this._v1; - } - - /** - * Sets the second control point on this CubicBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @param {Number[]} value The second control point. - */ - set v2(value) { - this._v2 = value || math.vec3([0, 0, 0]); - } - - /** - * Gets the second control point on this CubicBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @returns {Number[]} The second control point. - */ - get v2() { - return this._v2; - } - - /** - * Sets the end point on this CubicBezierCurve. - * - * Fires a {@link CubicBezierCurve#v3:event} event on change. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @param {Number[]} value The end point. - */ - set v3(value) { - this.fire("v3", this._v3 = value || math.vec3([0, 0, 0])); - } - - /** - * Gets the end point on this CubicBezierCurve. - * - * Fires a {@link CubicBezierCurve#v3:event} event on change. - * - * Default value is ````[0.0, 0.0, 0.0]```` - * - * @returns {Number[]} The end point. - */ - get v3() { - return this._v3; - } - - /** - * Sets the current position of progress along this CubicBezierCurve. - * - * Automatically clamps to range ````[0..1]````. - * - * @param {Number} value New progress time value. - */ - set t(value) { - value = value || 0; - this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); - } - - /** - * Gets the current position of progress along this CubicBezierCurve. - * - * @returns {Number} Current progress time value. - */ - get t() { - return this._t; - } - - /** - * Returns point on this CubicBezierCurve at the given position. - * - * @param {Number} t Position to get point at. - * - * @returns {Number[]} The point at the given position. - */ - get point() { - return this.getPoint(this._t); - } - - /** - * Returns point on this CubicBezierCurve at the given position. - * - * @param {Number} t Position to get point at. - * - * @returns {Number[]} The point at the given position. - */ - getPoint(t) { - - var vector = math.vec3(); - - vector[0] = math.b3(t, this._v0[0], this._v1[0], this._v2[0], this._v3[0]); - vector[1] = math.b3(t, this._v0[1], this._v1[1], this._v2[1], this._v3[1]); - vector[2] = math.b3(t, this._v0[2], this._v1[2], this._v2[2], this._v3[2]); - - return vector; - } - - getJSON() { - return { - v0: this._v0, - v1: this._v1, - v2: this._v2, - v3: this._v3, - t: this._t - }; - } -} - -/** - * @desc A complex curved path constructed from various {@link Curve} subtypes. - * - * * A Path can be constructed from these {@link Curve} subtypes: {@link SplineCurve}, {@link CubicBezierCurve} and {@link QuadraticBezierCurve}. - * * You can sample a {@link Path#point} and a {@link Curve#tangent} vector on a Path for any given value of {@link Path#t} in the range ````[0..1]````. - * * When you set {@link Path#t} on a Path, its {@link Path#point} and {@link Curve#tangent} properties will update accordingly. - */ -class Path extends Curve { - - /** - * @constructor - * @param {Component} [owner] Owner component. When destroyed, the owner will destroy this SectionPlane as well. - * @param {*} [cfg] Path configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {@link Scene}, generated automatically when omitted. - * @param {String []} [cfg.paths=[]] IDs or instances of {{#crossLink "path"}}{{/crossLink}} subtypes to add to this Path. - * @param {Number} [cfg.t=0] Current position on this Path, in range between 0..1. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this._cachedLengths = []; - this._dirty = true; - this._curves = []; // Array of child Curve components - this._t = 0; - this._dirtySubs = []; // Subscriptions to "dirty" events from child Curve components - this._destroyedSubs = []; // Subscriptions to "destroyed" events from child Curve components - this.curves = cfg.curves || []; // Add initial curves - this.t = cfg.t; // Set initial progress - } - - /** - * Adds a {@link Curve} to this Path. - * - * @param {Curve} curve The {@link Curve} to add. - */ - addCurve(curve) { - this._curves.push(curve); - this._dirty = true; - } - - /** - * Sets the {@link Curve}s in this Path. - * - * Default value is ````[]````. - * - * @param {{Array of Spline, Path, QuadraticBezierCurve or CubicBezierCurve}} value. - */ - set curves(value) { - - value = value || []; - - var curve; - // Unsubscribe from events on old curves - var i; - var len; - for (i = 0, len = this._curves.length; i < len; i++) { - curve = this._curves[i]; - curve.off(this._dirtySubs[i]); - curve.off(this._destroyedSubs[i]); + } + return str; } - - this._curves = []; - this._dirtySubs = []; - this._destroyedSubs = []; - - var self = this; - - function curveDirty() { - self._dirty = true; + function UTF8ToString(ptr, maxBytesToRead) { + ptr >>>= 0; + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ""; } - - function curveDestroyed() { - var id = this.id; - for (i = 0, len = self._curves.length; i < len; i++) { - if (self._curves[i].id === id) { - self._curves = self._curves.slice(i, i + 1); - self._dirtySubs = self._dirtySubs.slice(i, i + 1); - self._destroyedSubs = self._destroyedSubs.slice(i, i + 1); - self._dirty = true; - return; - } + function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { + outIdx >>>= 0; + if (!(maxBytesToWrite > 0)) + return 0; + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 55296 && u <= 57343) { + var u1 = str.charCodeAt(++i); + u = 65536 + ((u & 1023) << 10) | u1 & 1023; + } + if (u <= 127) { + if (outIdx >= endIdx) + break; + heap[outIdx++ >>> 0] = u; + } else if (u <= 2047) { + if (outIdx + 1 >= endIdx) + break; + heap[outIdx++ >>> 0] = 192 | u >> 6; + heap[outIdx++ >>> 0] = 128 | u & 63; + } else if (u <= 65535) { + if (outIdx + 2 >= endIdx) + break; + heap[outIdx++ >>> 0] = 224 | u >> 12; + heap[outIdx++ >>> 0] = 128 | u >> 6 & 63; + heap[outIdx++ >>> 0] = 128 | u & 63; + } else { + if (outIdx + 3 >= endIdx) + break; + heap[outIdx++ >>> 0] = 240 | u >> 18; + heap[outIdx++ >>> 0] = 128 | u >> 12 & 63; + heap[outIdx++ >>> 0] = 128 | u >> 6 & 63; + heap[outIdx++ >>> 0] = 128 | u & 63; } + } + heap[outIdx >>> 0] = 0; + return outIdx - startIdx; } - - for (i = 0, len = value.length; i < len; i++) { - curve = value[i]; - if (utils.isNumeric(curve) || utils.isString(curve)) { - // ID given for curve - find the curve component - var id = curve; - curve = this.scene.components[id]; - if (!curve) { - this.error("Component not found: " + _inQuotes(id)); - continue; - } + function stringToUTF8(str, outPtr, maxBytesToWrite) { + return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + } + function lengthBytesUTF8(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var u = str.charCodeAt(i); + if (u >= 55296 && u <= 57343) + u = 65536 + ((u & 1023) << 10) | str.charCodeAt(++i) & 1023; + if (u <= 127) + ++len; + else if (u <= 2047) + len += 2; + else if (u <= 65535) + len += 3; + else + len += 4; + } + return len; + } + var UTF16Decoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le") : void 0; + function UTF16ToString(ptr, maxBytesToRead) { + var endPtr = ptr; + var idx = endPtr >> 1; + var maxIdx = idx + maxBytesToRead / 2; + while (!(idx >= maxIdx) && HEAPU16[idx >>> 0]) + ++idx; + endPtr = idx << 1; + if (endPtr - ptr > 32 && UTF16Decoder) { + return UTF16Decoder.decode(HEAPU8.subarray(ptr >>> 0, endPtr >>> 0)); + } else { + var str = ""; + for (var i = 0; !(i >= maxBytesToRead / 2); ++i) { + var codeUnit = HEAP16[ptr + i * 2 >>> 1]; + if (codeUnit == 0) + break; + str += String.fromCharCode(codeUnit); } - - var type = curve.type; - - if (type !== "xeokit.SplineCurve" && - type !== "xeokit.Path" && - type !== "xeokit.CubicBezierCurve" && - type !== "xeokit.QuadraticBezierCurve") { - - this.error("Component " + _inQuotes(curve.id) - + " is not a xeokit.SplineCurve, xeokit.Path or xeokit.QuadraticBezierCurve"); - - continue; + return str; + } + } + function stringToUTF16(str, outPtr, maxBytesToWrite) { + if (maxBytesToWrite === void 0) { + maxBytesToWrite = 2147483647; + } + if (maxBytesToWrite < 2) + return 0; + maxBytesToWrite -= 2; + var startPtr = outPtr; + var numCharsToWrite = maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length; + for (var i = 0; i < numCharsToWrite; ++i) { + var codeUnit = str.charCodeAt(i); + HEAP16[outPtr >>> 1] = codeUnit; + outPtr += 2; + } + HEAP16[outPtr >>> 1] = 0; + return outPtr - startPtr; + } + function lengthBytesUTF16(str) { + return str.length * 2; + } + function UTF32ToString(ptr, maxBytesToRead) { + var i = 0; + var str = ""; + while (!(i >= maxBytesToRead / 4)) { + var utf32 = HEAP32[ptr + i * 4 >>> 2]; + if (utf32 == 0) + break; + ++i; + if (utf32 >= 65536) { + var ch = utf32 - 65536; + str += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023); + } else { + str += String.fromCharCode(utf32); } - - this._curves.push(curve); - this._dirtySubs.push(curve.on("dirty", curveDirty)); - this._destroyedSubs.push(curve.once("destroyed", curveDestroyed)); + } + return str; } - - this._dirty = true; - } - - /** - * Gets the {@link Curve}s in this Path. - * - * @returns {{Array of Spline, Path, QuadraticBezierCurve or CubicBezierCurve}} the {@link Curve}s in this path. - */ - get curves() { - return this._curves; - } - - /** - * Sets the current point of progress along this Path. - * - * Automatically clamps to range ````[0..1]````. - * - * Default value is ````0````. - * - * @param {Number} value The current point of progress. - */ - set t(value) { - value = value || 0; - this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); - } - - /** - * Gets the current point of progress along this Path. - * - * Default value is ````0````. - * - * @returns {Number} The current point of progress. - */ - get t() { - return this._t; - } - - /** - * Gets point on this Path corresponding to the current value of {@link Path#t}. - * - * @returns {Number[]} The point. - */ - get point() { - return this.getPoint(this._t); - } - - /** - * Length of this Path, which is the cumulative length of all {@link Curve}s currently in {@link Path#curves}. - * - * @return {Number} Length of this path. - */ - get length() { - var lens = this._getCurveLengths(); - return lens[lens.length - 1]; - } - - /** - * Gets a point on this Path corresponding to the given progress position. - * - * @param {Number} t Indicates point of progress along this curve, in the range [0..1]. - * @returns {Number[]} - */ - getPoint(t) { - var d = t * this.length; - var curveLengths = this._getCurveLengths(); - var i = 0, diff, curve; - while (i < curveLengths.length) { - if (curveLengths[i] >= d) { - diff = curveLengths[i] - d; - curve = this._curves[i]; - var u = 1 - diff / curve.length; - return curve.getPointAt(u); + function stringToUTF32(str, outPtr, maxBytesToWrite) { + outPtr >>>= 0; + if (maxBytesToWrite === void 0) { + maxBytesToWrite = 2147483647; + } + if (maxBytesToWrite < 4) + return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + for (var i = 0; i < str.length; ++i) { + var codeUnit = str.charCodeAt(i); + if (codeUnit >= 55296 && codeUnit <= 57343) { + var trailSurrogate = str.charCodeAt(++i); + codeUnit = 65536 + ((codeUnit & 1023) << 10) | trailSurrogate & 1023; } - i++; + HEAP32[outPtr >>> 2] = codeUnit; + outPtr += 4; + if (outPtr + 4 > endPtr) + break; + } + HEAP32[outPtr >>> 2] = 0; + return outPtr - startPtr; } - return null; - } - - _getCurveLengths() { - if (!this._dirty) { - return this._cachedLengths; + function lengthBytesUTF32(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var codeUnit = str.charCodeAt(i); + if (codeUnit >= 55296 && codeUnit <= 57343) + ++i; + len += 4; + } + return len; } - var lengths = []; - var sums = 0; - var i, il = this._curves.length; - for (i = 0; i < il; i++) { - sums += this._curves[i].length; - lengths.push(sums); - + function writeArrayToMemory(array, buffer2) { + HEAP8.set(array, buffer2 >>> 0); } - this._cachedLengths = lengths; - this._dirty = false; - return lengths; - } - - _getJSON() { - var curveIds = []; - for (var i = 0, len = this._curves.length; i < len; i++) { - curveIds.push(this._curves[i].id); + function writeAsciiToMemory(str, buffer2, dontAddNull) { + for (var i = 0; i < str.length; ++i) { + HEAP8[buffer2++ >>> 0] = str.charCodeAt(i); + } + if (!dontAddNull) + HEAP8[buffer2 >>> 0] = 0; } - return { - curves: curveIds, - t: this._t - }; - } - - /** - * Destroys this Path. - */ - destroy() { - super.destroy(); - var i; - var len; - var curve; - for (i = 0, len = this._curves.length; i < len; i++) { - curve = this._curves[i]; - curve.off(this._dirtySubs[i]); - curve.off(this._destroyedSubs[i]); + function alignUp(x, multiple) { + if (x % multiple > 0) { + x += multiple - x % multiple; + } + return x; } - } -} - -/** - * A **QuadraticBezierCurve** is a {@link Curve} along which a 3D position can be animated. - * - * * As shown in the diagram below, a QuadraticBezierCurve is defined by three control points - * * You can sample a {@link QuadraticBezierCurve#point} and a {@link Curve#tangent} vector on a QuadraticBezierCurve for any given value of {@link QuadraticBezierCurve#t} in the range ````[0..1]```` - * * When you set {@link QuadraticBezierCurve#t} on a QuadraticBezierCurve, its {@link QuadraticBezierCurve#point} and {@link Curve#tangent} will update accordingly. - * * To build a complex path, you can combine an unlimited combination of QuadraticBezierCurves, {@link CubicBezierCurve}s and {@link SplineCurve}s into a {@link Path}.
  • - *
    - * - *
    - * *[Quadratic Bezier Curve from WikiPedia](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)* - */ -class QuadraticBezierCurve extends Curve { - - /** - * @constructor - * @param {Component} owner Owner component. When destroyed, the owner will destroy this MetallicMaterial as well. - * @param {*} [cfg] Configuration - * @param {String} [cfg.id] Optional ID, unique among all components in the parent {{#crossLink "Scene"}}Scene{{/crossLink}}, generated automatically when omitted. - * @param {Number[]} [cfg.v0=[0,0,0]] The starting point. - * @param {Number[]} [cfg.v1=[0,0,0]] The middle control point. - * @param {Number[]} [cfg.v2=[0,0,0]] The end point. - * @param {Number[]} [cfg.t=0] Current position on this QuadraticBezierCurve, in range between ````0..1````. - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - this.v0 = cfg.v0; - this.v1 = cfg.v1; - this.v2 = cfg.v2; - this.t = cfg.t; - } - - /** - * Sets the starting point on this QuadraticBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @param {Number[]} value New starting point. - */ - set v0(value) { - this._v0 = value || math.vec3([0, 0, 0]); - } - - /** - * Gets the starting point on this QuadraticBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @returns {Number[]} The starting point. - */ - get v0() { - return this._v0; - } - - /** - * Sets the middle control point on this QuadraticBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @param {Number[]} value New middle control point. - */ - set v1(value) { - this._v1 = value || math.vec3([0, 0, 0]); - } - - /** - * Gets the middle control point on this QuadraticBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @returns {Number[]} The middle control point. - */ - get v1() { - return this._v1; - } - - /** - * Sets the end point on this QuadraticBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @param {Number[]} value The new end point. - */ - set v2(value) { - this._v2 = value || math.vec3([0, 0, 0]); - } - - /** - * Gets the end point on this QuadraticBezierCurve. - * - * Default value is ````[0.0, 0.0, 0.0]````. - * - * @returns {Number[]} The end point. - */ - get v2() { - return this._v2; - } - - /** - * Sets the progress along this QuadraticBezierCurve. - * - * Automatically clamps to range [0..1]. - * - * Default value is ````0````. - * - * @param {Number} value The new progress location. - */ - set t(value) { - value = value || 0; - this._t = value < 0.0 ? 0.0 : (value > 1.0 ? 1.0 : value); - } - - /** - * Gets the progress along this QuadraticBezierCurve. - * - * Default value is ````0````. - * - * @returns {Number} The current progress location. - */ - get t() { - return this._t; - } - - /** - Point on this QuadraticBezierCurve at position {@link QuadraticBezierCurve/t}. - - @property point - @type {Number[]} - */ - get point() { - return this.getPoint(this._t); - } - - /** - * Returns the point on this QuadraticBezierCurve at the given position. - * - * @param {Number} t Position to get point at. - * @returns {Number[]} The point. - */ - getPoint(t) { - var vector = math.vec3(); - vector[0] = math.b2(t, this._v0[0], this._v1[0], this._v2[0]); - vector[1] = math.b2(t, this._v0[1], this._v1[1], this._v2[1]); - vector[2] = math.b2(t, this._v0[2], this._v1[2], this._v2[2]); - return vector; - } - - getJSON() { - return { - v0: this._v0, - v1: this._v1, - v2: this._v2, - t: this._t - }; - } -} - -/** - * @desc A high-performance model representation for efficient rendering and low memory usage. - * - * * This class was replaced with {@link VBOSceneModel} in ````xeokit-sdk v2.3.0````. - * * This class currently extends {@link VBOSceneModel}, in order to maintain backward-compatibility until we remove it. - * * See {@link VBOSceneModel} for API details. - * - * @deprecated - * @implements {Drawable} - * @implements {Entity} - * @implements {SceneModel} - */ -class PerformanceModel extends VBOSceneModel { - - /** - * See {@link VBOSceneModel} for details. - * - * @param owner - * @param cfg - */ - constructor(owner, cfg = {}) { - super(owner, cfg); - } -} - -const screenPos = math.vec4(); -const viewPos = math.vec4(); - -const tempVec3a$3 = math.vec3(); -const tempVec3b$3 = math.vec3(); -const tempVec3c$3 = math.vec3(); - -const tempVec4a$1 = math.vec4(); -const tempVec4b$1 = math.vec4(); -const tempVec4c$1 = math.vec4(); - -/** - * @private - */ -class PanController { - - constructor(scene) { - this._scene = scene; - } - - /** - * Dollys the Camera towards the given target 2D canvas position. - * - * When the target's corresponding World-space position is also provided, then this function will also test if we've - * dollied past the target, and will return ````true```` if that's the case. - * - * @param [optionalTargetWorldPos] Optional world position of the target - * @param targetCanvasPos Canvas position of the target - * @param dollyDelta Amount to dolly - * @return True if optionalTargetWorldPos was given, and we've dollied past that position. - */ - dollyToCanvasPos(optionalTargetWorldPos, targetCanvasPos, dollyDelta) { - - let dolliedThroughSurface = false; - - const camera = this._scene.camera; - - if (optionalTargetWorldPos) { - const eyeToWorldPosVec = math.subVec3(optionalTargetWorldPos, camera.eye, tempVec3a$3); - const eyeWorldPosDist = math.lenVec3(eyeToWorldPosVec); - dolliedThroughSurface = (eyeWorldPosDist < dollyDelta); + var buffer, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; + function updateGlobalBufferAndViews(buf) { + buffer = buf; + Module["HEAP8"] = HEAP8 = new Int8Array(buf); + Module["HEAP16"] = HEAP16 = new Int16Array(buf); + Module["HEAP32"] = HEAP32 = new Int32Array(buf); + Module["HEAPU8"] = HEAPU8 = new Uint8Array(buf); + Module["HEAPU16"] = HEAPU16 = new Uint16Array(buf); + Module["HEAPU32"] = HEAPU32 = new Uint32Array(buf); + Module["HEAPF32"] = HEAPF32 = new Float32Array(buf); + Module["HEAPF64"] = HEAPF64 = new Float64Array(buf); } - - if (camera.projection === "perspective") { - - camera.ortho.scale = camera.ortho.scale - dollyDelta; - - const unprojectedWorldPos = this._unproject(targetCanvasPos, tempVec4a$1); - const offset = math.subVec3(unprojectedWorldPos, camera.eye, tempVec4c$1); - const moveVec = math.mulVec3Scalar(math.normalizeVec3(offset), -dollyDelta, []); - - camera.eye = [camera.eye[0] - moveVec[0], camera.eye[1] - moveVec[1], camera.eye[2] - moveVec[2]]; - camera.look = [camera.look[0] - moveVec[0], camera.look[1] - moveVec[1], camera.look[2] - moveVec[2]]; - - if (optionalTargetWorldPos) { - - // Subtle UX tweak - if we have a target World position, then set camera eye->look distance to - // the same distance as from eye->target. This just gives us a better position for look, - // if we subsequently orbit eye about look, so that we don't orbit a position that's - // suddenly a lot closer than the point we pivoted about on the surface of the last object - // that we click-drag-pivoted on. - - const eyeTargetVec = math.subVec3(optionalTargetWorldPos, camera.eye, tempVec3a$3); - const lenEyeTargetVec = math.lenVec3(eyeTargetVec); - const eyeLookVec = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(camera.look, camera.eye, tempVec3b$3)), lenEyeTargetVec); - camera.look = [camera.eye[0] + eyeLookVec[0], camera.eye[1] + eyeLookVec[1], camera.eye[2] + eyeLookVec[2]]; - } - - } else if (camera.projection === "ortho") { - - // - set ortho scale, getting the unprojected targetCanvasPos before and after, get that difference in a vector; - // - get the vector in which we're dollying; - // - add both vectors to camera eye and look. - - const worldPos1 = this._unproject(targetCanvasPos, tempVec4a$1); - - camera.ortho.scale = camera.ortho.scale - dollyDelta; - camera.ortho._update(); // HACK - - const worldPos2 = this._unproject(targetCanvasPos, tempVec4b$1); - const offset = math.subVec3(worldPos2, worldPos1, tempVec4c$1); - const eyeLookMoveVec = math.mulVec3Scalar(math.normalizeVec3(math.subVec3(camera.look, camera.eye, tempVec3a$3)), -dollyDelta, tempVec3b$3); - const moveVec = math.addVec3(offset, eyeLookMoveVec, tempVec3c$3); - - camera.eye = [camera.eye[0] - moveVec[0], camera.eye[1] - moveVec[1], camera.eye[2] - moveVec[2]]; - camera.look = [camera.look[0] - moveVec[0], camera.look[1] - moveVec[1], camera.look[2] - moveVec[2]]; + Module["INITIAL_MEMORY"] || 16777216; + var wasmTable; + var __ATPRERUN__ = []; + var __ATINIT__ = []; + var __ATMAIN__ = []; + var __ATPOSTRUN__ = []; + var runtimeKeepaliveCounter = 0; + function keepRuntimeAlive() { + return noExitRuntime || runtimeKeepaliveCounter > 0; } - - return dolliedThroughSurface; - } - - _unproject(canvasPos, worldPos) { - - const camera = this._scene.camera; - const transposedProjectMat = camera.project.transposedMatrix; - const Pt3 = transposedProjectMat.subarray(8, 12); - const Pt4 = transposedProjectMat.subarray(12); - const D = [0, 0, -1.0, 1]; - const screenZ = math.dotVec4(D, Pt3) / math.dotVec4(D, Pt4); - - camera.project.unproject(canvasPos, screenZ, screenPos, viewPos, worldPos); - - return worldPos; - } - - destroy() { - } -} - -const tempVec3a$2 = math.vec3(); -const tempVec3b$2 = math.vec3(); -const tempVec3c$2 = math.vec3(); - -const tempVec4a = math.vec4(); -const tempVec4b = math.vec4(); -const tempVec4c = math.vec4(); - - -/** @private */ -class PivotController { - - /** - * @private - */ - constructor(scene, configs) { - - // Pivot math by: http://www.derschmale.com/ - - this._scene = scene; - this._configs = configs; - this._pivotWorldPos = math.vec3(); - this._cameraOffset = math.vec3(); - this._azimuth = 0; - this._polar = 0; - this._radius = 0; - this._pivotPosSet = false; // Initially false, true as soon as _pivotWorldPos has been set to some value - this._pivoting = false; // True while pivoting - this._shown = false; - - this._pivotViewPos = math.vec4(); - this._pivotProjPos = math.vec4(); - this._pivotCanvasPos = math.vec2(); - this._cameraDirty = true; - - this._onViewMatrix = this._scene.camera.on("viewMatrix", () => { - this._cameraDirty = true; - }); - - this._onProjMatrix = this._scene.camera.on("projMatrix", () => { - this._cameraDirty = true; - }); - - this._onTick = this._scene.on("tick", () => { - this.updatePivotElement(); - }); - } - - updatePivotElement() { - - const camera = this._scene.camera; - const canvas = this._scene.canvas; - - if (this._pivoting && this._cameraDirty) { - - math.transformPoint3(camera.viewMatrix, this.getPivotPos(), this._pivotViewPos); - this._pivotViewPos[3] = 1; - math.transformPoint4(camera.projMatrix, this._pivotViewPos, this._pivotProjPos); - - const canvasAABB = canvas.boundary; - const canvasWidth = canvasAABB[2]; - const canvasHeight = canvasAABB[3]; - - this._pivotCanvasPos[0] = Math.floor((1 + this._pivotProjPos[0] / this._pivotProjPos[3]) * canvasWidth / 2); - this._pivotCanvasPos[1] = Math.floor((1 - this._pivotProjPos[1] / this._pivotProjPos[3]) * canvasHeight / 2); - - const canvasElem = canvas.canvas; - const canvasBoundingRect = canvasElem.getBoundingClientRect(); - - if (this._pivotElement) { - this._pivotElement.style.left = (Math.floor(canvasBoundingRect.left + this._pivotCanvasPos[0]) - (this._pivotElement.clientWidth / 2) + window.scrollX) + "px"; - this._pivotElement.style.top = (Math.floor(canvasBoundingRect.top + this._pivotCanvasPos[1]) - (this._pivotElement.clientHeight / 2) + window.scrollY) + "px"; + function preRun() { + if (Module["preRun"]) { + if (typeof Module["preRun"] == "function") + Module["preRun"] = [Module["preRun"]]; + while (Module["preRun"].length) { + addOnPreRun(Module["preRun"].shift()); } - this._cameraDirty = false; + } + callRuntimeCallbacks(__ATPRERUN__); } - } - - /** - * Sets the HTML DOM element that will represent the pivot position. - * - * @param pivotElement - */ - setPivotElement(pivotElement) { - this._pivotElement = pivotElement; - } - - /** - * Begins pivoting. - */ - startPivot() { - - if (this._cameraLookingDownwards()) { - this._pivoting = false; - return false; + function initRuntime() { + if (!Module["noFSInit"] && !FS.init.initialized) + FS.init(); + FS.ignorePermissions = false; + callRuntimeCallbacks(__ATINIT__); } - - const camera = this._scene.camera; - - let lookat = math.lookAtMat4v(camera.eye, camera.look, camera.worldUp); - math.transformPoint3(lookat, this.getPivotPos(), this._cameraOffset); - - const pivotPos = this.getPivotPos(); - this._cameraOffset[2] += math.distVec3(camera.eye, pivotPos); - - lookat = math.inverseMat4(lookat); - - const offset = math.transformVec3(lookat, this._cameraOffset); - const diff = math.vec3(); - - math.subVec3(camera.eye, pivotPos, diff); - math.addVec3(diff, offset); - - if (camera.zUp) { - const t = diff[1]; - diff[1] = diff[2]; - diff[2] = t; + function preMain() { + callRuntimeCallbacks(__ATMAIN__); } - - this._radius = math.lenVec3(diff); - this._polar = Math.acos(diff[1] / this._radius); - this._azimuth = Math.atan2(diff[0], diff[2]); - this._pivoting = true; - } - - _cameraLookingDownwards() { // Returns true if angle between camera viewing direction and World-space "up" axis is too small - const camera = this._scene.camera; - const forwardAxis = math.normalizeVec3(math.subVec3(camera.look, camera.eye, tempVec3a$2)); - const rightAxis = math.cross3Vec3(forwardAxis, camera.worldUp, tempVec3b$2); - let rightAxisLen = math.sqLenVec3(rightAxis); - return (rightAxisLen <= 0.0001); - } - - /** - * Returns true if we are currently pivoting. - * - * @returns {boolean} - */ - getPivoting() { - return this._pivoting; - } - - /** - * Sets a 3D World-space position to pivot about. - * - * @param {Number[]} worldPos The new World-space pivot position. - */ - setPivotPos(worldPos) { - this._pivotWorldPos.set(worldPos); - this._pivotPosSet = true; - } - - /** - * Sets the pivot position to the 3D projection of the given 2D canvas coordinates on a sphere centered - * at the viewpoint. The radius of the sphere is configured via {@link CameraControl#smartPivot}. - * - * @param canvasPos - */ - setCanvasPivotPos(canvasPos) { - const camera = this._scene.camera; - const pivotShereRadius = Math.abs(math.distVec3(this._scene.center, camera.eye)); - const transposedProjectMat = camera.project.transposedMatrix; - const Pt3 = transposedProjectMat.subarray(8, 12); - const Pt4 = transposedProjectMat.subarray(12); - const D = [0, 0, -1.0, 1]; - const screenZ = math.dotVec4(D, Pt3) / math.dotVec4(D, Pt4); - const worldPos = tempVec4a; - camera.project.unproject(canvasPos, screenZ, tempVec4b, tempVec4c, worldPos); - const eyeWorldPosVec = math.normalizeVec3(math.subVec3(worldPos, camera.eye, tempVec3a$2)); - const posOnSphere = math.addVec3(camera.eye, math.mulVec3Scalar(eyeWorldPosVec, pivotShereRadius, tempVec3b$2), tempVec3c$2); - this.setPivotPos(posOnSphere); - } - - /** - * Gets the current position we're pivoting about. - * @returns {Number[]} The current World-space pivot position. - */ - getPivotPos() { - return (this._pivotPosSet) ? this._pivotWorldPos : this._scene.camera.look; // Avoid pivoting about [0,0,0] by default - } - - /** - * Continues to pivot. - * - * @param {Number} yawInc Yaw rotation increment. - * @param {Number} pitchInc Pitch rotation increment. - */ - continuePivot(yawInc, pitchInc) { - if (!this._pivoting) { - return; + function postRun() { + if (Module["postRun"]) { + if (typeof Module["postRun"] == "function") + Module["postRun"] = [Module["postRun"]]; + while (Module["postRun"].length) { + addOnPostRun(Module["postRun"].shift()); + } + } + callRuntimeCallbacks(__ATPOSTRUN__); } - if (yawInc === 0 && pitchInc === 0) { - return; + function addOnPreRun(cb) { + __ATPRERUN__.unshift(cb); } - const camera = this._scene.camera; - var dx = -yawInc; - const dy = -pitchInc; - if (camera.worldUp[2] === 1) { - dx = -dx; + function addOnInit(cb) { + __ATINIT__.unshift(cb); } - this._azimuth += -dx * .01; - this._polar += dy * .01; - this._polar = math.clamp(this._polar, .001, Math.PI - .001); - const pos = [ - this._radius * Math.sin(this._polar) * Math.sin(this._azimuth), - this._radius * Math.cos(this._polar), - this._radius * Math.sin(this._polar) * Math.cos(this._azimuth) - ]; - if (camera.worldUp[2] === 1) { - const t = pos[1]; - pos[1] = pos[2]; - pos[2] = t; + function addOnPostRun(cb) { + __ATPOSTRUN__.unshift(cb); } - // Preserve the eye->look distance, since in xeokit "look" is the point-of-interest, not the direction vector. - const eyeLookLen = math.lenVec3(math.subVec3(camera.look, camera.eye, math.vec3())); - const pivotPos = this.getPivotPos(); - math.addVec3(pos, pivotPos); - let lookat = math.lookAtMat4v(pos, pivotPos, camera.worldUp); - lookat = math.inverseMat4(lookat); - const offset = math.transformVec3(lookat, this._cameraOffset); - lookat[12] -= offset[0]; - lookat[13] -= offset[1]; - lookat[14] -= offset[2]; - const zAxis = [lookat[8], lookat[9], lookat[10]]; - camera.eye = [lookat[12], lookat[13], lookat[14]]; - math.subVec3(camera.eye, math.mulVec3Scalar(zAxis, eyeLookLen), camera.look); - camera.up = [lookat[4], lookat[5], lookat[6]]; - this.showPivot(); - } - - /** - * Shows the pivot position. - * - * Only works if we set an HTML DOM element to represent the pivot position. - */ - showPivot() { - if (this._shown) { - return; + var runDependencies = 0; + var dependenciesFulfilled = null; + function getUniqueRunDependency(id) { + return id; } - if (this._hideTimeout !== null) { - window.clearTimeout(this._hideTimeout); - this._hideTimeout = null; + function addRunDependency(id) { + runDependencies++; + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); + } } - if (this._pivotElement) { - this.updatePivotElement(); - this._pivotElement.style.visibility = "visible"; - this._shown = true; - this._hideTimeout = window.setTimeout(() => { - this.hidePivot(); - }, 1000); + function removeRunDependency(id) { + runDependencies--; + if (Module["monitorRunDependencies"]) { + Module["monitorRunDependencies"](runDependencies); + } + if (runDependencies == 0) { + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); + } + } } - } - - /** - * Hides the pivot position. - * - * Only works if we set an HTML DOM element to represent the pivot position. - */ - hidePivot() { - if (!this._shown) { - return; + Module["preloadedImages"] = {}; + Module["preloadedAudios"] = {}; + function abort(what) { + if (Module["onAbort"]) { + Module["onAbort"](what); + } + what += ""; + err(what); + ABORT = true; + what = "abort(" + what + "). Build with -s ASSERTIONS=1 for more info."; + var e = new WebAssembly.RuntimeError(what); + readyPromiseReject(e); + throw e; } - if (this._hideTimeout !== null) { - window.clearTimeout(this._hideTimeout); - this._hideTimeout = null; + var dataURIPrefix = "data:application/octet-stream;base64,"; + function isDataURI(filename) { + return filename.startsWith(dataURIPrefix); } - if (this._pivotElement) { - this._pivotElement.style.visibility = "hidden"; + function isFileURI(filename) { + return filename.startsWith("file://"); } - this._shown = false; - } - - /** - * Finishes pivoting. - */ - endPivot() { - this._pivoting = false; - } - - destroy() { - this._scene.camera.off(this._onViewMatrix); - this._scene.camera.off(this._onProjMatrix); - this._scene.off(this._onTick); - } -} - -/** - * - * @private - */ -class PickController { - - constructor(cameraControl, configs) { - - this._scene = cameraControl.scene; - - this._cameraControl = cameraControl; - - this._scene.canvas.canvas.oncontextmenu = function (e) { - e.preventDefault(); - }; - - this._configs = configs; - - /** - * Set true to schedule picking of an Entity. - * @type {boolean} - */ - this.schedulePickEntity = false; - - /** - * Set true to schedule picking of a position on teh surface of an Entity. - * @type {boolean} - */ - this.schedulePickSurface = false; - - /** - * The canvas position at which to do the next scheduled pick. - * @type {Number[]} - */ - this.pickCursorPos = math.vec2(); - - /** - * Will be true after picking to indicate that something was picked. - * @type {boolean} - */ - this.picked = false; - - /** - * Will be true after picking to indicate that a position on the surface of an Entity was picked. - * @type {boolean} - */ - this.pickedSurface = false; - - /** - * Will hold the PickResult after after picking. - * @type {PickResult} - */ - this.pickResult = null; - - this._lastPickedEntityId = null; - - this._needFireEvents = false; - } - - /** - * Immediately attempts a pick, if scheduled. - */ - update() { - - if (!this._configs.pointerEnabled) { - return; + var wasmBinaryFile; + wasmBinaryFile = "web-ifc.wasm"; + if (!isDataURI(wasmBinaryFile)) { + wasmBinaryFile = locateFile(wasmBinaryFile); } - - if (!this.schedulePickEntity && !this.schedulePickSurface) { - return; + function getBinary(file) { + try { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } else { + throw "both async and sync fetching of the wasm failed"; + } + } catch (err2) { + abort(err2); + } } - - this.picked = false; - this.pickedSurface = false; - this._needFireEvents = false; - - const hasHoverSurfaceSubs = this._cameraControl.hasSubs("hoverSurface"); - - if (this.schedulePickSurface) { - if (this.pickResult && this.pickResult.worldPos) { - const pickResultCanvasPos = this.pickResult.canvasPos; - if (pickResultCanvasPos[0] === this.pickCursorPos[0] && pickResultCanvasPos[1] === this.pickCursorPos[1]) { - this.picked = true; - this.pickedSurface = true; - this._needFireEvents = hasHoverSurfaceSubs; - this.schedulePickEntity = false; - this.schedulePickSurface = false; - return; + function getBinaryPromise() { + if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (typeof fetch === "function" && !isFileURI(wasmBinaryFile)) { + return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { + if (!response["ok"]) { + throw "failed to load wasm binary file at '" + wasmBinaryFile + "'"; } + return response["arrayBuffer"](); + }).catch(function() { + return getBinary(wasmBinaryFile); + }); + } else { + if (readAsync) { + return new Promise(function(resolve, reject) { + readAsync(wasmBinaryFile, function(response) { + resolve(new Uint8Array(response)); + }, reject); + }); + } + } + } + return Promise.resolve().then(function() { + return getBinary(wasmBinaryFile); + }); + } + function createWasm() { + var info = { "a": asmLibraryArg }; + function receiveInstance(instance, module2) { + var exports3 = instance.exports; + Module["asm"] = exports3; + wasmMemory = Module["asm"]["$"]; + updateGlobalBufferAndViews(wasmMemory.buffer); + wasmTable = Module["asm"]["ha"]; + addOnInit(Module["asm"]["aa"]); + removeRunDependency(); + } + addRunDependency(); + function receiveInstantiationResult(result) { + receiveInstance(result["instance"]); + } + function instantiateArrayBuffer(receiver) { + return getBinaryPromise().then(function(binary) { + var result = WebAssembly.instantiate(binary, info); + return result; + }).then(receiver, function(reason) { + err("failed to asynchronously prepare wasm: " + reason); + abort(reason); + }); + } + function instantiateAsync() { + if (!wasmBinary && typeof WebAssembly.instantiateStreaming === "function" && !isDataURI(wasmBinaryFile) && !isFileURI(wasmBinaryFile) && typeof fetch === "function") { + return fetch(wasmBinaryFile, { credentials: "same-origin" }).then(function(response) { + var result = WebAssembly.instantiateStreaming(response, info); + return result.then(receiveInstantiationResult, function(reason) { + err("wasm streaming compile failed: " + reason); + err("falling back to ArrayBuffer instantiation"); + return instantiateArrayBuffer(receiveInstantiationResult); + }); + }); + } else { + return instantiateArrayBuffer(receiveInstantiationResult); } - } - - if (this.schedulePickEntity) { - if (this.pickResult) { - const pickResultCanvasPos = this.pickResult.canvasPos; - if (pickResultCanvasPos[0] === this.pickCursorPos[0] && pickResultCanvasPos[1] === this.pickCursorPos[1]) { - this.picked = true; - this.pickedSurface = false; - this._needFireEvents = false; - this.schedulePickEntity = false; - this.schedulePickSurface = false; - return; - } + } + if (Module["instantiateWasm"]) { + try { + var exports2 = Module["instantiateWasm"](info, receiveInstance); + return exports2; + } catch (e) { + err("Module.instantiateWasm callback failed with error: " + e); + return false; } + } + instantiateAsync().catch(readyPromiseReject); + return {}; } - - if (this.schedulePickSurface) { - - this.pickResult = this._scene.pick({ - pickSurface: true, - pickSurfaceNormal: false, - canvasPos: this.pickCursorPos - }); - - if (this.pickResult) { - this.picked = true; - this.pickedSurface = true; - this._needFireEvents = true; + var tempDouble; + var tempI64; + function callRuntimeCallbacks(callbacks) { + while (callbacks.length > 0) { + var callback = callbacks.shift(); + if (typeof callback == "function") { + callback(Module); + continue; } - - } else { // schedulePickEntity == true - - this.pickResult = this._scene.pick({ - canvasPos: this.pickCursorPos - }); - - if (this.pickResult) { - this.picked = true; - this.pickedSurface = false; - this._needFireEvents = true; + var func = callback.func; + if (typeof func === "number") { + if (callback.arg === void 0) { + wasmTable.get(func)(); + } else { + wasmTable.get(func)(callback.arg); + } + } else { + func(callback.arg === void 0 ? null : callback.arg); } + } } - - this.schedulePickEntity = false; - this.schedulePickSurface = false; - } - - fireEvents() { - - if (!this._needFireEvents) { - return; + function ___assert_fail(condition, filename, line, func) { + abort("Assertion failed: " + UTF8ToString(condition) + ", at: " + [filename ? UTF8ToString(filename) : "unknown filename", line, func ? UTF8ToString(func) : "unknown function"]); } - - if (this.picked && this.pickResult && this.pickResult.entity) { - - const pickedEntityId = this.pickResult.entity.id; - - if (this._lastPickedEntityId !== pickedEntityId) { - - if (this._lastPickedEntityId !== undefined) { - this._cameraControl.fire("hoverOut", { - entity: this._scene.objects[this._lastPickedEntityId] - }, true); - } - - this._cameraControl.fire("hoverEnter", this.pickResult, true); - this._lastPickedEntityId = pickedEntityId; + function ___cxa_allocate_exception(size) { + return _malloc(size + 16) + 16; + } + function ExceptionInfo(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - 16; + this.set_type = function(type) { + HEAP32[this.ptr + 4 >>> 2] = type; + }; + this.get_type = function() { + return HEAP32[this.ptr + 4 >>> 2]; + }; + this.set_destructor = function(destructor) { + HEAP32[this.ptr + 8 >>> 2] = destructor; + }; + this.get_destructor = function() { + return HEAP32[this.ptr + 8 >>> 2]; + }; + this.set_refcount = function(refcount) { + HEAP32[this.ptr >>> 2] = refcount; + }; + this.set_caught = function(caught) { + caught = caught ? 1 : 0; + HEAP8[this.ptr + 12 >>> 0] = caught; + }; + this.get_caught = function() { + return HEAP8[this.ptr + 12 >>> 0] != 0; + }; + this.set_rethrown = function(rethrown) { + rethrown = rethrown ? 1 : 0; + HEAP8[this.ptr + 13 >>> 0] = rethrown; + }; + this.get_rethrown = function() { + return HEAP8[this.ptr + 13 >>> 0] != 0; + }; + this.init = function(type, destructor) { + this.set_type(type); + this.set_destructor(destructor); + this.set_refcount(0); + this.set_caught(false); + this.set_rethrown(false); + }; + this.add_ref = function() { + var value = HEAP32[this.ptr >>> 2]; + HEAP32[this.ptr >>> 2] = value + 1; + }; + this.release_ref = function() { + var prev = HEAP32[this.ptr >>> 2]; + HEAP32[this.ptr >>> 2] = prev - 1; + return prev === 1; + }; + } + function ___cxa_throw(ptr, type, destructor) { + var info = new ExceptionInfo(ptr); + info.init(type, destructor); + throw ptr; + } + function setErrNo(value) { + HEAP32[___errno_location() >>> 2] = value; + return value; + } + var PATH = { splitPath: function(filename) { + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, normalizeArray: function(parts, allowAboveRoot) { + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === ".") { + parts.splice(i, 1); + } else if (last === "..") { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; } - - this._cameraControl.fire("hover", this.pickResult, true); - - if (this.pickResult.worldPos) { - this.pickedSurface = true; - this._cameraControl.fire("hoverSurface", this.pickResult, true); + } + if (allowAboveRoot) { + for (; up; up--) { + parts.unshift(".."); } - - } else { - - if (this._lastPickedEntityId !== undefined) { - this._cameraControl.fire("hoverOut", { - entity: this._scene.objects[this._lastPickedEntityId] - }, true); - this._lastPickedEntityId = undefined; + } + return parts; + }, normalize: function(path) { + var isAbsolute = path.charAt(0) === "/", trailingSlash = path.substr(-1) === "/"; + path = PATH.normalizeArray(path.split("/").filter(function(p) { + return !!p; + }), !isAbsolute).join("/"); + if (!path && !isAbsolute) { + path = "."; + } + if (path && trailingSlash) { + path += "/"; + } + return (isAbsolute ? "/" : "") + path; + }, dirname: function(path) { + var result = PATH.splitPath(path), root = result[0], dir = result[1]; + if (!root && !dir) { + return "."; + } + if (dir) { + dir = dir.substr(0, dir.length - 1); + } + return root + dir; + }, basename: function(path) { + if (path === "/") + return "/"; + path = PATH.normalize(path); + path = path.replace(/\/$/, ""); + var lastSlash = path.lastIndexOf("/"); + if (lastSlash === -1) + return path; + return path.substr(lastSlash + 1); + }, extname: function(path) { + return PATH.splitPath(path)[3]; + }, join: function() { + var paths = Array.prototype.slice.call(arguments, 0); + return PATH.normalize(paths.join("/")); + }, join2: function(l, r) { + return PATH.normalize(l + "/" + r); + } }; + function getRandomDevice() { + if (typeof crypto === "object" && typeof crypto["getRandomValues"] === "function") { + var randomBuffer = new Uint8Array(1); + return function() { + crypto.getRandomValues(randomBuffer); + return randomBuffer[0]; + }; + } else if (ENVIRONMENT_IS_NODE) { + try { + var crypto_module = require_crypto(); + return function() { + return crypto_module["randomBytes"](1)[0]; + }; + } catch (e) { } - - this._cameraControl.fire("hoverOff", { - canvasPos: this.pickCursorPos - }, true); - } - - this.pickResult = null; - - this._needFireEvents = false; - } - - destroy() { - } -} - -/** - * @private - */ - -const canvasPos = math.vec2(); - -const getCanvasPosFromEvent$3 = function (event, canvasPos) { - if (!event) { - event = window.event; - canvasPos[0] = event.x; - canvasPos[1] = event.y; - } else { - let element = event.target; - let totalOffsetLeft = 0; - let totalOffsetTop = 0; - while (element.offsetParent) { - totalOffsetLeft += element.offsetLeft; - totalOffsetTop += element.offsetTop; - element = element.offsetParent; + } + return function() { + abort("randomDevice"); + }; } - canvasPos[0] = event.pageX - totalOffsetLeft; - canvasPos[1] = event.pageY - totalOffsetTop; - } - return canvasPos; -}; - -/** - * @private - */ -class MousePanRotateDollyHandler { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - - const pickController = controllers.pickController; - - let lastX = 0; - let lastY = 0; - let lastXDown = 0; - let lastYDown = 0; - - let mouseDownLeft; - let mouseDownMiddle; - let mouseDownRight; - - let mouseDownPicked = false; - const pickedWorldPos = math.vec3(); - - let mouseMovedOnCanvasSinceLastWheel = true; - - const canvas = this._scene.canvas.canvas; - - const keyDown = []; - - document.addEventListener("keydown", this._documentKeyDownHandler = (e) => { - if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { - return; + var PATH_FS = { resolve: function() { + var resolvedPath = "", resolvedAbsolute = false; + for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = i >= 0 ? arguments[i] : FS.cwd(); + if (typeof path !== "string") { + throw new TypeError("Arguments to path.resolve must be strings"); + } else if (!path) { + return ""; } - const keyCode = e.keyCode; - keyDown[keyCode] = true; - }); - - document.addEventListener("keyup", this._documentKeyUpHandler = (e) => { - if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { - return; + resolvedPath = path + "/" + resolvedPath; + resolvedAbsolute = path.charAt(0) === "/"; + } + resolvedPath = PATH.normalizeArray(resolvedPath.split("/").filter(function(p) { + return !!p; + }), !resolvedAbsolute).join("/"); + return (resolvedAbsolute ? "/" : "") + resolvedPath || "."; + }, relative: function(from, to) { + from = PATH_FS.resolve(from).substr(1); + to = PATH_FS.resolve(to).substr(1); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== "") + break; } - const keyCode = e.keyCode; - keyDown[keyCode] = false; - }); - - function setMousedownState(pick = true) { - canvas.style.cursor = "move"; - setMousedownPositions(); - if (pick) { - setMousedownPick(); + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== "") + break; } + if (start > end) + return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split("/")); + var toParts = trim(to.split("/")); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push(".."); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join("/"); + } }; + var TTY = { ttys: [], init: function() { + }, shutdown: function() { + }, register: function(dev, ops) { + TTY.ttys[dev] = { input: [], output: [], ops }; + FS.registerDevice(dev, TTY.stream_ops); + }, stream_ops: { open: function(stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, close: function(stream) { + stream.tty.ops.flush(stream.tty); + }, flush: function(stream) { + stream.tty.ops.flush(stream.tty); + }, read: function(stream, buffer2, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === void 0 && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === void 0) + break; + bytesRead++; + buffer2[offset + i] = result; + } + if (bytesRead) { + stream.node.timestamp = Date.now(); + } + return bytesRead; + }, write: function(stream, buffer2, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer2[offset + i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.timestamp = Date.now(); + } + return i; + } }, default_tty_ops: { get_char: function(tty) { + if (!tty.input.length) { + var result = null; + if (ENVIRONMENT_IS_NODE) { + var BUFSIZE = 256; + var buf = Buffer.alloc(BUFSIZE); + var bytesRead = 0; + try { + bytesRead = nodeFS.readSync(process.stdin.fd, buf, 0, BUFSIZE, null); + } catch (e) { + if (e.toString().includes("EOF")) + bytesRead = 0; + else + throw e; + } + if (bytesRead > 0) { + result = buf.slice(0, bytesRead).toString("utf-8"); + } else { + result = null; + } + } else if (typeof window != "undefined" && typeof window.prompt == "function") { + result = window.prompt("Input: "); + if (result !== null) { + result += "\n"; + } + } else if (typeof readline == "function") { + result = readline(); + if (result !== null) { + result += "\n"; + } + } + if (!result) { + return null; + } + tty.input = intArrayFromString(result, true); + } + return tty.input.shift(); + }, put_char: function(tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } else { + if (val != 0) + tty.output.push(val); + } + }, flush: function(tty) { + if (tty.output && tty.output.length > 0) { + out(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } + } }, default_tty1_ops: { put_char: function(tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } else { + if (val != 0) + tty.output.push(val); + } + }, flush: function(tty) { + if (tty.output && tty.output.length > 0) { + err(UTF8ArrayToString(tty.output, 0)); + tty.output = []; + } + } } }; + function mmapAlloc(size) { + abort(); } - - function setMousedownPositions() { - - lastX = states.pointerCanvasPos[0]; - lastY = states.pointerCanvasPos[1]; - lastXDown = states.pointerCanvasPos[0]; - lastYDown = states.pointerCanvasPos[1]; - } - - function setMousedownPick() { - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickSurface = true; - pickController.update(); - - if (pickController.picked && pickController.pickedSurface && pickController.pickResult && pickController.pickResult.worldPos) { - mouseDownPicked = true; - pickedWorldPos.set(pickController.pickResult.worldPos); + var MEMFS = { ops_table: null, mount: function(mount) { + return MEMFS.createNode(null, "/", 16384 | 511, 0); + }, createNode: function(parent, name2, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + throw new FS.ErrnoError(63); + } + if (!MEMFS.ops_table) { + MEMFS.ops_table = { dir: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr, lookup: MEMFS.node_ops.lookup, mknod: MEMFS.node_ops.mknod, rename: MEMFS.node_ops.rename, unlink: MEMFS.node_ops.unlink, rmdir: MEMFS.node_ops.rmdir, readdir: MEMFS.node_ops.readdir, symlink: MEMFS.node_ops.symlink }, stream: { llseek: MEMFS.stream_ops.llseek } }, file: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr }, stream: { llseek: MEMFS.stream_ops.llseek, read: MEMFS.stream_ops.read, write: MEMFS.stream_ops.write, allocate: MEMFS.stream_ops.allocate, mmap: MEMFS.stream_ops.mmap, msync: MEMFS.stream_ops.msync } }, link: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr, readlink: MEMFS.node_ops.readlink }, stream: {} }, chrdev: { node: { getattr: MEMFS.node_ops.getattr, setattr: MEMFS.node_ops.setattr }, stream: FS.chrdev_stream_ops } }; + } + var node = FS.createNode(parent, name2, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.timestamp = Date.now(); + if (parent) { + parent.contents[name2] = node; + parent.timestamp = node.timestamp; + } + return node; + }, getFileDataAsTypedArray: function(node) { + if (!node.contents) + return new Uint8Array(0); + if (node.contents.subarray) + return node.contents.subarray(0, node.usedBytes); + return new Uint8Array(node.contents); + }, expandFileStorage: function(node, newCapacity) { + newCapacity >>>= 0; + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) + return; + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max(newCapacity, prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2 : 1.125) >>> 0); + if (prevCapacity != 0) + newCapacity = Math.max(newCapacity, 256); + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); + if (node.usedBytes > 0) + node.contents.set(oldContents.subarray(0, node.usedBytes), 0); + }, resizeFileStorage: function(node, newSize) { + newSize >>>= 0; + if (node.usedBytes == newSize) + return; + if (newSize == 0) { + node.contents = null; + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); + if (oldContents) { + node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); + } + node.usedBytes = newSize; + } + }, node_ops: { getattr: function(node) { + var attr = {}; + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.timestamp); + attr.mtime = new Date(node.timestamp); + attr.ctime = new Date(node.timestamp); + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, setattr: function(node, attr) { + if (attr.mode !== void 0) { + node.mode = attr.mode; + } + if (attr.timestamp !== void 0) { + node.timestamp = attr.timestamp; + } + if (attr.size !== void 0) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, lookup: function(parent, name2) { + throw FS.genericErrors[44]; + }, mknod: function(parent, name2, mode, dev) { + return MEMFS.createNode(parent, name2, mode, dev); + }, rename: function(old_node, new_dir, new_name) { + if (FS.isDir(old_node.mode)) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) { + } + if (new_node) { + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + } + delete old_node.parent.contents[old_node.name]; + old_node.parent.timestamp = Date.now(); + old_node.name = new_name; + new_dir.contents[new_name] = old_node; + new_dir.timestamp = old_node.parent.timestamp; + old_node.parent = new_dir; + }, unlink: function(parent, name2) { + delete parent.contents[name2]; + parent.timestamp = Date.now(); + }, rmdir: function(parent, name2) { + var node = FS.lookupNode(parent, name2); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name2]; + parent.timestamp = Date.now(); + }, readdir: function(node) { + var entries = [".", ".."]; + for (var key2 in node.contents) { + if (!node.contents.hasOwnProperty(key2)) { + continue; + } + entries.push(key2); + } + return entries; + }, symlink: function(parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 511 | 40960, 0); + node.link = oldpath; + return node; + }, readlink: function(node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + } }, stream_ops: { read: function(stream, buffer2, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) + return 0; + var size = Math.min(stream.node.usedBytes - position, length); + if (size > 8 && contents.subarray) { + buffer2.set(contents.subarray(position, position + size), offset); + } else { + for (var i = 0; i < size; i++) + buffer2[offset + i] = contents[position + i]; + } + return size; + }, write: function(stream, buffer2, offset, length, position, canOwn) { + if (buffer2.buffer === HEAP8.buffer) { + canOwn = false; + } + if (!length) + return 0; + var node = stream.node; + node.timestamp = Date.now(); + if (buffer2.subarray && (!node.contents || node.contents.subarray)) { + if (canOwn) { + node.contents = buffer2.subarray(offset, offset + length); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { + node.contents = buffer2.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { + node.contents.set(buffer2.subarray(offset, offset + length), position); + return length; + } + } + MEMFS.expandFileStorage(node, position + length); + if (node.contents.subarray && buffer2.subarray) { + node.contents.set(buffer2.subarray(offset, offset + length), position); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer2[offset + i]; + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, llseek: function(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, allocate: function(stream, offset, length) { + MEMFS.expandFileStorage(stream.node, offset + length); + stream.node.usedBytes = Math.max(stream.node.usedBytes, offset + length); + }, mmap: function(stream, address, length, position, prot, flags) { + if (address !== 0) { + throw new FS.ErrnoError(28); + } + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; + if (!(flags & 2) && contents.buffer === buffer) { + allocated = false; + ptr = contents.byteOffset; + } else { + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call(contents, position, position + length); + } + } + allocated = true; + ptr = mmapAlloc(); + if (!ptr) { + throw new FS.ErrnoError(48); + } + ptr >>>= 0; + HEAP8.set(contents, ptr >>> 0); + } + return { ptr, allocated }; + }, msync: function(stream, buffer2, offset, length, mmapFlags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (mmapFlags & 2) { + return 0; + } + MEMFS.stream_ops.write(stream, buffer2, 0, length, offset, false); + return 0; + } } }; + function asyncLoad(url, onload, onerror, noRunDep) { + var dep = !noRunDep ? getUniqueRunDependency("al " + url) : ""; + readAsync(url, function(arrayBuffer) { + assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).'); + onload(new Uint8Array(arrayBuffer)); + if (dep) + removeRunDependency(); + }, function(event) { + if (onerror) { + onerror(); } else { - mouseDownPicked = false; + throw 'Loading data file "' + url + '" failed.'; } + }); + if (dep) + addRunDependency(); } - - canvas.addEventListener("mousedown", this._mouseDownHandler = (e) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; - } - - switch (e.which) { - - case 1: // Left button - - if (keyDown[scene.input.KEY_SHIFT] || configs.planView) { - - mouseDownLeft = true; - - setMousedownState(); - - } else { - - mouseDownLeft = true; - - setMousedownState(false); - } - - break; - - case 2: // Middle/both buttons - - mouseDownMiddle = true; - - setMousedownState(); - - break; - - case 3: // Right button - - mouseDownRight = true; - - if (configs.panRightClick) { - - setMousedownState(); - } - - break; + var FS = { root: null, mounts: [], devices: {}, streams: [], nextInode: 1, nameTable: null, currentPath: "/", initialized: false, ignorePermissions: true, trackingDelegate: {}, tracking: { openFlags: { READ: 1, WRITE: 2 } }, ErrnoError: null, genericErrors: {}, filesystems: null, syncFSRequests: 0, lookupPath: function(path, opts) { + path = PATH_FS.resolve(FS.cwd(), path); + opts = opts || {}; + if (!path) + return { path: "", node: null }; + var defaults = { follow_mount: true, recurse_count: 0 }; + for (var key2 in defaults) { + if (opts[key2] === void 0) { + opts[key2] = defaults[key2]; } - }); - - document.addEventListener("mousemove", this._documentMouseMoveHandler = () => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + } + if (opts.recurse_count > 8) { + throw new FS.ErrnoError(32); + } + var parts = PATH.normalizeArray(path.split("/").filter(function(p) { + return !!p; + }), false); + var current = FS.root; + var current_path = "/"; + for (var i = 0; i < parts.length; i++) { + var islast = i === parts.length - 1; + if (islast && opts.parent) { + break; } - - if (!mouseDownLeft && !mouseDownMiddle && !mouseDownRight) { - return; + current = FS.lookupNode(current, parts[i]); + current_path = PATH.join2(current_path, parts[i]); + if (FS.isMountpoint(current)) { + if (!islast || islast && opts.follow_mount) { + current = current.mounted.root; + } } - - // Scaling drag-rotate to canvas boundary - - const canvasBoundary = scene.canvas.boundary; - const canvasWidth = canvasBoundary[2] - canvasBoundary[0]; - const canvasHeight = canvasBoundary[3] - canvasBoundary[1]; - const x = states.pointerCanvasPos[0]; - const y = states.pointerCanvasPos[1]; - - const panning = keyDown[scene.input.KEY_SHIFT] || configs.planView || (!configs.panRightClick && mouseDownMiddle) || (configs.panRightClick && mouseDownRight); - - if (panning) { - - const xPanDelta = (x - lastX); - const yPanDelta = (y - lastY); - - const camera = scene.camera; - - // We use only canvasHeight here so that aspect ratio does not distort speed - - if (camera.projection === "perspective") { - - const depth = Math.abs(mouseDownPicked ? math.lenVec3(math.subVec3(pickedWorldPos, scene.camera.eye, [])) : scene.camera.eyeLookDist); - const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0); - - updates.panDeltaX += (1.5 * xPanDelta * targetDistance / canvasHeight); - updates.panDeltaY += (1.5 * yPanDelta * targetDistance / canvasHeight); - - } else { - - updates.panDeltaX += 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight); - updates.panDeltaY += 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight); - } - - } else if (mouseDownLeft && !mouseDownMiddle && !mouseDownRight) { - - if (!configs.planView) { // No rotating in plan-view mode - - if (configs.firstPerson) { - updates.rotateDeltaY -= ((x - lastX) / canvasWidth) * configs.dragRotationRate / 2; - updates.rotateDeltaX += ((y - lastY) / canvasHeight) * (configs.dragRotationRate / 4); - - } else { - updates.rotateDeltaY -= ((x - lastX) / canvasWidth) * (configs.dragRotationRate * 1.5); - updates.rotateDeltaX += ((y - lastY) / canvasHeight) * (configs.dragRotationRate * 1.5); - } + if (!islast || opts.follow) { + var count = 0; + while (FS.isLink(current.mode)) { + var link = FS.readlink(current_path); + current_path = PATH_FS.resolve(PATH.dirname(current_path), link); + var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count }); + current = lookup.node; + if (count++ > 40) { + throw new FS.ErrnoError(32); } + } } - - lastX = x; - lastY = y; - }); - - canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + } + return { path: current_path, node: current }; + }, getPath: function(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) + return mount; + return mount[mount.length - 1] !== "/" ? mount + "/" + path : mount + path; + } + path = path ? node.name + "/" + path : node.name; + node = node.parent; + } + }, hashName: function(parentid, name2) { + var hash = 0; + for (var i = 0; i < name2.length; i++) { + hash = (hash << 5) - hash + name2.charCodeAt(i) | 0; + } + return (parentid + hash >>> 0) % FS.nameTable.length; + }, hashAddNode: function(node) { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, hashRemoveNode: function(node) { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; + } else { + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; + break; + } + current = current.name_next; + } + } + }, lookupNode: function(parent, name2) { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode, parent); + } + var hash = FS.hashName(parent.id, name2); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name2) { + return node; + } + } + return FS.lookup(parent, name2); + }, createNode: function(parent, name2, mode, rdev) { + var node = new FS.FSNode(parent, name2, mode, rdev); + FS.hashAddNode(node); + return node; + }, destroyNode: function(node) { + FS.hashRemoveNode(node); + }, isRoot: function(node) { + return node === node.parent; + }, isMountpoint: function(node) { + return !!node.mounted; + }, isFile: function(mode) { + return (mode & 61440) === 32768; + }, isDir: function(mode) { + return (mode & 61440) === 16384; + }, isLink: function(mode) { + return (mode & 61440) === 40960; + }, isChrdev: function(mode) { + return (mode & 61440) === 8192; + }, isBlkdev: function(mode) { + return (mode & 61440) === 24576; + }, isFIFO: function(mode) { + return (mode & 61440) === 4096; + }, isSocket: function(mode) { + return (mode & 49152) === 49152; + }, flagModes: { "r": 0, "r+": 2, "w": 577, "w+": 578, "a": 1089, "a+": 1090 }, modeStringToFlags: function(str) { + var flags = FS.flagModes[str]; + if (typeof flags === "undefined") { + throw new Error("Unknown file open mode: " + str); + } + return flags; + }, flagsToPermissionString: function(flag) { + var perms = ["r", "w", "rw"][flag & 3]; + if (flag & 512) { + perms += "w"; + } + return perms; + }, nodePermissions: function(node, perms) { + if (FS.ignorePermissions) { + return 0; + } + if (perms.includes("r") && !(node.mode & 292)) { + return 2; + } else if (perms.includes("w") && !(node.mode & 146)) { + return 2; + } else if (perms.includes("x") && !(node.mode & 73)) { + return 2; + } + return 0; + }, mayLookup: function(dir) { + var errCode = FS.nodePermissions(dir, "x"); + if (errCode) + return errCode; + if (!dir.node_ops.lookup) + return 2; + return 0; + }, mayCreate: function(dir, name2) { + try { + var node = FS.lookupNode(dir, name2); + return 20; + } catch (e) { + } + return FS.nodePermissions(dir, "wx"); + }, mayDelete: function(dir, name2, isdir) { + var node; + try { + node = FS.lookupNode(dir, name2); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, "wx"); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; } - - if (!states.mouseover) { - return; + } else { + if (FS.isDir(node.mode)) { + return 31; } - - mouseMovedOnCanvasSinceLastWheel = true; - }); - - document.addEventListener("mouseup", this._documentMouseUpHandler = (e) => { - if (!(configs.active && configs.pointerEnabled)) { - return; + } + return 0; + }, mayOpen: function(node, flags) { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } else if (FS.isDir(node.mode)) { + if (FS.flagsToPermissionString(flags) !== "r" || flags & 512) { + return 31; } - switch (e.which) { - case 1: // Left button - mouseDownLeft = false; - mouseDownMiddle = false; - mouseDownRight = false; - break; - case 2: // Middle/both buttons - mouseDownLeft = false; - mouseDownMiddle = false; - mouseDownRight = false; - break; - case 3: // Right button - mouseDownLeft = false; - mouseDownMiddle = false; - mouseDownRight = false; - break; + } + return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); + }, MAX_OPEN_FDS: 4096, nextfd: function(fd_start, fd_end) { + fd_start = fd_start || 0; + fd_end = fd_end || FS.MAX_OPEN_FDS; + for (var fd = fd_start; fd <= fd_end; fd++) { + if (!FS.streams[fd]) { + return fd; } - }); - - canvas.addEventListener("mouseup", this._mouseUpHandler = (e) => { - if (!(configs.active && configs.pointerEnabled)) { - return; + } + throw new FS.ErrnoError(33); + }, getStream: function(fd) { + return FS.streams[fd]; + }, createStream: function(stream, fd_start, fd_end) { + if (!FS.FSStream) { + FS.FSStream = function() { + }; + FS.FSStream.prototype = { object: { get: function() { + return this.node; + }, set: function(val) { + this.node = val; + } }, isRead: { get: function() { + return (this.flags & 2097155) !== 1; + } }, isWrite: { get: function() { + return (this.flags & 2097155) !== 0; + } }, isAppend: { get: function() { + return this.flags & 1024; + } } }; + } + var newStream = new FS.FSStream(); + for (var p in stream) { + newStream[p] = stream[p]; + } + stream = newStream; + var fd = FS.nextfd(fd_start, fd_end); + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, closeStream: function(fd) { + FS.streams[fd] = null; + }, chrdev_stream_ops: { open: function(stream) { + var device = FS.getDevice(stream.node.rdev); + stream.stream_ops = device.stream_ops; + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + }, llseek: function() { + throw new FS.ErrnoError(70); + } }, major: function(dev) { + return dev >> 8; + }, minor: function(dev) { + return dev & 255; + }, makedev: function(ma, mi) { + return ma << 8 | mi; + }, registerDevice: function(dev, ops) { + FS.devices[dev] = { stream_ops: ops }; + }, getDevice: function(dev) { + return FS.devices[dev]; + }, getMounts: function(mount) { + var mounts = []; + var check = [mount]; + while (check.length) { + var m = check.pop(); + mounts.push(m); + check.push.apply(check, m.mounts); + } + return mounts; + }, syncfs: function(populate, callback) { + if (typeof populate === "function") { + callback = populate; + populate = false; + } + FS.syncFSRequests++; + if (FS.syncFSRequests > 1) { + err("warning: " + FS.syncFSRequests + " FS.syncfs operations in flight at once, probably just doing extra work"); + } + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + function doCallback(errCode) { + FS.syncFSRequests--; + return callback(errCode); + } + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; } - switch (e.which) { - case 3: // Right button - getCanvasPosFromEvent$3(e, canvasPos); - const x = canvasPos[0]; - const y = canvasPos[1]; - if (Math.abs(x - lastXDown) < 3 && Math.abs(y - lastYDown) < 3) { - controllers.cameraControl.fire("rightClick", { // For context menus - pagePos: [Math.round(e.pageX), Math.round(e.pageY)], - canvasPos: canvasPos, - event: e - }, true); - } - break; + if (++completed >= mounts.length) { + doCallback(null); } - canvas.style.removeProperty("cursor"); - }); - - canvas.addEventListener("mouseenter", this._mouseEnterHandler = () => { - if (!(configs.active && configs.pointerEnabled)) { - return; + } + mounts.forEach(function(mount) { + if (!mount.type.syncfs) { + return done(null); } - }); - - const maxElapsed = 1 / 20; - const minElapsed = 1 / 60; - - let secsNowLast = null; - - canvas.addEventListener("wheel", this._mouseWheelHandler = (e) => { - if (!(configs.active && configs.pointerEnabled)) { - return; + mount.type.syncfs(mount, populate, done); + }); + }, mount: function(type, opts, mountpoint) { + var root = mountpoint === "/"; + var pseudo = !mountpoint; + var node; + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + mountpoint = lookup.path; + node = lookup.node; + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); } - const secsNow = performance.now() / 1000.0; - var secsElapsed = (secsNowLast !== null) ? (secsNow - secsNowLast) : 0; - secsNowLast = secsNow; - if (secsElapsed > maxElapsed) { - secsElapsed = maxElapsed; + if (!FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); } - if (secsElapsed < minElapsed) { - secsElapsed = minElapsed; + } + var mount = { type, opts, mountpoint, mounts: [] }; + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + if (root) { + FS.root = mountRoot; + } else if (node) { + node.mounted = mount; + if (node.mount) { + node.mount.mounts.push(mount); } - const delta = Math.max(-1, Math.min(1, -e.deltaY * 40)); - if (delta === 0) { - return; + } + return mountRoot; + }, unmount: function(mountpoint) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + Object.keys(FS.nameTable).forEach(function(hash) { + var current = FS.nameTable[hash]; + while (current) { + var next = current.name_next; + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + current = next; } - const normalizedDelta = delta / Math.abs(delta); - updates.dollyDelta += -normalizedDelta * secsElapsed * configs.mouseWheelDollyRate; - - if (mouseMovedOnCanvasSinceLastWheel) { - states.followPointerDirty = true; - mouseMovedOnCanvasSinceLastWheel = false; + }); + node.mounted = null; + var idx = node.mount.mounts.indexOf(mount); + node.mount.mounts.splice(idx, 1); + }, lookup: function(parent, name2) { + return parent.node_ops.lookup(parent, name2); + }, mknod: function(path, mode, dev) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name2 = PATH.basename(path); + if (!name2 || name2 === "." || name2 === "..") { + throw new FS.ErrnoError(28); + } + var errCode = FS.mayCreate(parent, name2); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name2, mode, dev); + }, create: function(path, mode) { + mode = mode !== void 0 ? mode : 438; + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, mkdir: function(path, mode) { + mode = mode !== void 0 ? mode : 511; + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, mkdirTree: function(path, mode) { + var dirs = path.split("/"); + var d = ""; + for (var i = 0; i < dirs.length; ++i) { + if (!dirs[i]) + continue; + d += "/" + dirs[i]; + try { + FS.mkdir(d, mode); + } catch (e) { + if (e.errno != 20) + throw e; } - - }, {passive: true}); - } - - reset() { - } - - destroy() { - - const canvas = this._scene.canvas.canvas; - - document.removeEventListener("keydown", this._documentKeyDownHandler); - document.removeEventListener("keyup", this._documentKeyUpHandler); - canvas.removeEventListener("mousedown", this._mouseDownHandler); - document.removeEventListener("mousemove", this._documentMouseMoveHandler); - canvas.removeEventListener("mousemove", this._canvasMouseMoveHandler); - document.removeEventListener("mouseup", this._documentMouseUpHandler); - canvas.removeEventListener("mouseup", this._mouseUpHandler); - canvas.removeEventListener("mouseenter", this._mouseEnterHandler); - canvas.removeEventListener("wheel", this._mouseWheelHandler); - } -} - -const center = math.vec3(); -const tempVec3a$1 = math.vec3(); -const tempVec3b$1 = math.vec3(); -const tempVec3c$1 = math.vec3(); -const tempVec3d = math.vec3(); - -const tempCameraTarget = { - eye: math.vec3(), - look: math.vec3(), - up: math.vec3() -}; - -/** - * @private - */ -class KeyboardAxisViewHandler { - - constructor(scene, controllers, configs, states) { - - this._scene = scene; - const cameraControl = controllers.cameraControl; - const camera = scene.camera; - - this._onSceneKeyDown = scene.input.on("keydown", () => { - - if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { - return; + } + }, mkdev: function(path, mode, dev) { + if (typeof dev === "undefined") { + dev = mode; + mode = 438; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, symlink: function(oldpath, newpath) { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, rename: function(old_path, new_path) { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + var lookup, old_dir, new_dir; + lookup = FS.lookupPath(old_path, { parent: true }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { parent: true }); + new_dir = lookup.node; + if (!old_dir || !new_dir) + throw new FS.ErrnoError(44); + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + var old_node = FS.lookupNode(old_dir, old_name); + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== ".") { + throw new FS.ErrnoError(28); + } + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== ".") { + throw new FS.ErrnoError(55); + } + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) { + } + if (old_node === new_node) { + return; + } + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + errCode = new_node ? FS.mayDelete(new_dir, new_name, isdir) : FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(old_node) || new_node && FS.isMountpoint(new_node)) { + throw new FS.ErrnoError(10); + } + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, "w"); + if (errCode) { + throw new FS.ErrnoError(errCode); } - - if (!states.mouseover) { - return; + } + try { + if (FS.trackingDelegate["willMovePath"]) { + FS.trackingDelegate["willMovePath"](old_path, new_path); } - - const axisViewRight = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_RIGHT); - const axisViewBack = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_BACK); - const axisViewLeft = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_LEFT); - const axisViewFront = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_FRONT); - const axisViewTop = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_TOP); - const axisViewBottom = cameraControl._isKeyDownForAction(cameraControl.AXIS_VIEW_BOTTOM); - - if ((!axisViewRight) && (!axisViewBack) && (!axisViewLeft) && (!axisViewFront) && (!axisViewTop) && (!axisViewBottom)) { - return; + } catch (e) { + err("FS.trackingDelegate['willMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message); + } + FS.hashRemoveNode(old_node); + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + } catch (e) { + throw e; + } finally { + FS.hashAddNode(old_node); + } + try { + if (FS.trackingDelegate["onMovePath"]) + FS.trackingDelegate["onMovePath"](old_path, new_path); + } catch (e) { + err("FS.trackingDelegate['onMovePath']('" + old_path + "', '" + new_path + "') threw an exception: " + e.message); + } + }, rmdir: function(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name2 = PATH.basename(path); + var node = FS.lookupNode(parent, name2); + var errCode = FS.mayDelete(parent, name2, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + try { + if (FS.trackingDelegate["willDeletePath"]) { + FS.trackingDelegate["willDeletePath"](path); } - - const aabb = scene.aabb; - const diag = math.getAABB3Diag(aabb); - - math.getAABB3Center(aabb, center); - - const perspectiveDist = Math.abs(diag / Math.tan(controllers.cameraFlight.fitFOV * math.DEGTORAD)); - const orthoScale = diag * 1.1; - - tempCameraTarget.orthoScale = orthoScale; - - if (axisViewRight) { - - tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldRight, perspectiveDist, tempVec3a$1), tempVec3d)); - tempCameraTarget.look.set(center); - tempCameraTarget.up.set(camera.worldUp); - - } else if (axisViewBack) { - - tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldForward, perspectiveDist, tempVec3a$1), tempVec3d)); - tempCameraTarget.look.set(center); - tempCameraTarget.up.set(camera.worldUp); - - } else if (axisViewLeft) { - - tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldRight, -perspectiveDist, tempVec3a$1), tempVec3d)); - tempCameraTarget.look.set(center); - tempCameraTarget.up.set(camera.worldUp); - - } else if (axisViewFront) { - - tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldForward, -perspectiveDist, tempVec3a$1), tempVec3d)); - tempCameraTarget.look.set(center); - tempCameraTarget.up.set(camera.worldUp); - - } else if (axisViewTop) { - - tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldUp, perspectiveDist, tempVec3a$1), tempVec3d)); - tempCameraTarget.look.set(center); - tempCameraTarget.up.set(math.normalizeVec3(math.mulVec3Scalar(camera.worldForward, 1, tempVec3b$1), tempVec3c$1)); - - } else if (axisViewBottom) { - - tempCameraTarget.eye.set(math.addVec3(center, math.mulVec3Scalar(camera.worldUp, -perspectiveDist, tempVec3a$1), tempVec3d)); - tempCameraTarget.look.set(center); - tempCameraTarget.up.set(math.normalizeVec3(math.mulVec3Scalar(camera.worldForward, -1, tempVec3b$1))); + } catch (e) { + err("FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message); + } + parent.node_ops.rmdir(parent, name2); + FS.destroyNode(node); + try { + if (FS.trackingDelegate["onDeletePath"]) + FS.trackingDelegate["onDeletePath"](path); + } catch (e) { + err("FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message); + } + }, readdir: function(path) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node.node_ops.readdir) { + throw new FS.ErrnoError(54); + } + return node.node_ops.readdir(node); + }, unlink: function(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name2 = PATH.basename(path); + var node = FS.lookupNode(parent, name2); + var errCode = FS.mayDelete(parent, name2, false); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + try { + if (FS.trackingDelegate["willDeletePath"]) { + FS.trackingDelegate["willDeletePath"](path); } - - if ((!configs.firstPerson) && configs.followPointer) { - controllers.pivotController.setPivotPos(center); + } catch (e) { + err("FS.trackingDelegate['willDeletePath']('" + path + "') threw an exception: " + e.message); + } + parent.node_ops.unlink(parent, name2); + FS.destroyNode(node); + try { + if (FS.trackingDelegate["onDeletePath"]) + FS.trackingDelegate["onDeletePath"](path); + } catch (e) { + err("FS.trackingDelegate['onDeletePath']('" + path + "') threw an exception: " + e.message); + } + }, readlink: function(path) { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); + }, stat: function(path, dontFollow) { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + var node = lookup.node; + if (!node) { + throw new FS.ErrnoError(44); + } + if (!node.node_ops.getattr) { + throw new FS.ErrnoError(63); + } + return node.node_ops.getattr(node); + }, lstat: function(path) { + return FS.stat(path, true); + }, chmod: function(path, mode, dontFollow) { + var node; + if (typeof path === "string") { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { mode: mode & 4095 | node.mode & ~4095, timestamp: Date.now() }); + }, lchmod: function(path, mode) { + FS.chmod(path, mode, true); + }, fchmod: function(fd, mode) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + FS.chmod(stream.node, mode); + }, chown: function(path, uid, gid, dontFollow) { + var node; + if (typeof path === "string") { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + node.node_ops.setattr(node, { timestamp: Date.now() }); + }, lchown: function(path, uid, gid) { + FS.chown(path, uid, gid, true); + }, fchown: function(fd, uid, gid) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + FS.chown(stream.node, uid, gid); + }, truncate: function(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path === "string") { + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + } else { + node = path; + } + if (!node.node_ops.setattr) { + throw new FS.ErrnoError(63); + } + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, "w"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + node.node_ops.setattr(node, { size: len, timestamp: Date.now() }); + }, ftruncate: function(fd, len) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.truncate(stream.node, len); + }, utime: function(path, atime, mtime) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) }); + }, open: function(path, flags, mode, fd_start, fd_end) { + if (path === "") { + throw new FS.ErrnoError(44); + } + flags = typeof flags === "string" ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode === "undefined" ? 438 : mode; + if (flags & 64) { + mode = mode & 4095 | 32768; + } else { + mode = 0; + } + var node; + if (typeof path === "object") { + node = path; + } else { + path = PATH.normalize(path); + try { + var lookup = FS.lookupPath(path, { follow: !(flags & 131072) }); + node = lookup.node; + } catch (e) { } - - if (controllers.cameraFlight.duration > 0) { - controllers.cameraFlight.flyTo(tempCameraTarget, () => { - if (controllers.pivotController.getPivoting() && configs.followPointer) { - controllers.pivotController.showPivot(); - } - }); - + } + var created = false; + if (flags & 64) { + if (node) { + if (flags & 128) { + throw new FS.ErrnoError(20); + } } else { - controllers.cameraFlight.jumpTo(tempCameraTarget); - if (controllers.pivotController.getPivoting() && configs.followPointer) { - controllers.pivotController.showPivot(); - } + node = FS.mknod(path, mode, 0); + created = true; } - }); - } - - reset() { - } - - destroy() { - this._scene.input.off(this._onSceneKeyDown); - } -} - -/** - * @private - */ -class MousePickHandler { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - - const pickController = controllers.pickController; - const pivotController = controllers.pivotController; - const cameraControl = controllers.cameraControl; - - this._clicks = 0; - this._timeout = null; - this._lastPickedEntityId = null; - - let leftDown = false; - let rightDown = false; - - const canvas = this._scene.canvas.canvas; - - const flyCameraTo = (pickResult) => { - let pos; - if (pickResult && pickResult.worldPos) { - pos = pickResult.worldPos; + } + if (!node) { + throw new FS.ErrnoError(44); + } + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + if (flags & 65536 && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + if (flags & 512) { + FS.truncate(node, 0); + } + flags &= ~(128 | 512 | 131072); + var stream = FS.createStream({ node, path: FS.getPath(node), flags, seekable: true, position: 0, stream_ops: node.stream_ops, ungotten: [], error: false }, fd_start, fd_end); + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (Module["logReadFiles"] && !(flags & 1)) { + if (!FS.readFiles) + FS.readFiles = {}; + if (!(path in FS.readFiles)) { + FS.readFiles[path] = 1; + err("FS.trackingDelegate error on read file: " + path); + } + } + try { + if (FS.trackingDelegate["onOpenFile"]) { + var trackingFlags = 0; + if ((flags & 2097155) !== 1) { + trackingFlags |= FS.tracking.openFlags.READ; + } + if ((flags & 2097155) !== 0) { + trackingFlags |= FS.tracking.openFlags.WRITE; + } + FS.trackingDelegate["onOpenFile"](path, trackingFlags); + } + } catch (e) { + err("FS.trackingDelegate['onOpenFile']('" + path + "', flags) threw an exception: " + e.message); + } + return stream; + }, close: function(stream) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) + stream.getdents = null; + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, isClosed: function(stream) { + return stream.fd === null; + }, llseek: function(stream, offset, whence) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, read: function(stream, buffer2, offset, length, position) { + offset >>>= 0; + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position !== "undefined"; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read(stream, buffer2, offset, length, position); + if (!seeking) + stream.position += bytesRead; + return bytesRead; + }, write: function(stream, buffer2, offset, length, position, canOwn) { + offset >>>= 0; + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + FS.llseek(stream, 0, 2); + } + var seeking = typeof position !== "undefined"; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write(stream, buffer2, offset, length, position, canOwn); + if (!seeking) + stream.position += bytesWritten; + try { + if (stream.path && FS.trackingDelegate["onWriteToFile"]) + FS.trackingDelegate["onWriteToFile"](stream.path); + } catch (e) { + err("FS.trackingDelegate['onWriteToFile']('" + stream.path + "') threw an exception: " + e.message); + } + return bytesWritten; + }, allocate: function(stream, offset, length) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (offset < 0 || length <= 0) { + throw new FS.ErrnoError(28); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (!stream.stream_ops.allocate) { + throw new FS.ErrnoError(138); + } + stream.stream_ops.allocate(stream, offset, length); + }, mmap: function(stream, address, length, position, prot, flags) { + address >>>= 0; + if ((prot & 2) !== 0 && (flags & 2) === 0 && (stream.flags & 2097155) !== 2) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + return stream.stream_ops.mmap(stream, address, length, position, prot, flags); + }, msync: function(stream, buffer2, offset, length, mmapFlags) { + offset >>>= 0; + if (!stream || !stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync(stream, buffer2, offset, length, mmapFlags); + }, munmap: function(stream) { + return 0; + }, ioctl: function(stream, cmd, arg) { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, readFile: function(path, opts) { + opts = opts || {}; + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || "binary"; + if (opts.encoding !== "utf8" && opts.encoding !== "binary") { + throw new Error('Invalid encoding type "' + opts.encoding + '"'); + } + var ret; + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === "utf8") { + ret = UTF8ArrayToString(buf, 0); + } else if (opts.encoding === "binary") { + ret = buf; + } + FS.close(stream); + return ret; + }, writeFile: function(path, data, opts) { + opts = opts || {}; + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data === "string") { + var buf = new Uint8Array(lengthBytesUTF8(data) + 1); + var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); + FS.write(stream, buf, 0, actualNumBytes, void 0, opts.canOwn); + } else if (ArrayBuffer.isView(data)) { + FS.write(stream, data, 0, data.byteLength, void 0, opts.canOwn); + } else { + throw new Error("Unsupported data type"); + } + FS.close(stream); + }, cwd: function() { + return FS.currentPath; + }, chdir: function(path) { + var lookup = FS.lookupPath(path, { follow: true }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, "x"); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, createDefaultDirectories: function() { + FS.mkdir("/tmp"); + FS.mkdir("/home"); + FS.mkdir("/home/web_user"); + }, createDefaultDevices: function() { + FS.mkdir("/dev"); + FS.registerDevice(FS.makedev(1, 3), { read: function() { + return 0; + }, write: function(stream, buffer2, offset, length, pos) { + return length; + } }); + FS.mkdev("/dev/null", FS.makedev(1, 3)); + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev("/dev/tty", FS.makedev(5, 0)); + FS.mkdev("/dev/tty1", FS.makedev(6, 0)); + var random_device = getRandomDevice(); + FS.createDevice("/dev", "random", random_device); + FS.createDevice("/dev", "urandom", random_device); + FS.mkdir("/dev/shm"); + FS.mkdir("/dev/shm/tmp"); + }, createSpecialDirectories: function() { + FS.mkdir("/proc"); + var proc_self = FS.mkdir("/proc/self"); + FS.mkdir("/proc/self/fd"); + FS.mount({ mount: function() { + var node = FS.createNode(proc_self, "fd", 16384 | 511, 73); + node.node_ops = { lookup: function(parent, name2) { + var fd = +name2; + var stream = FS.getStream(fd); + if (!stream) + throw new FS.ErrnoError(8); + var ret = { parent: null, mount: { mountpoint: "fake" }, node_ops: { readlink: function() { + return stream.path; + } } }; + ret.parent = ret; + return ret; + } }; + return node; + } }, {}, "/proc/self/fd"); + }, createStandardStreams: function() { + if (Module["stdin"]) { + FS.createDevice("/dev", "stdin", Module["stdin"]); + } else { + FS.symlink("/dev/tty", "/dev/stdin"); + } + if (Module["stdout"]) { + FS.createDevice("/dev", "stdout", null, Module["stdout"]); + } else { + FS.symlink("/dev/tty", "/dev/stdout"); + } + if (Module["stderr"]) { + FS.createDevice("/dev", "stderr", null, Module["stderr"]); + } else { + FS.symlink("/dev/tty1", "/dev/stderr"); + } + FS.open("/dev/stdin", 0); + FS.open("/dev/stdout", 1); + FS.open("/dev/stderr", 1); + }, ensureErrnoError: function() { + if (FS.ErrnoError) + return; + FS.ErrnoError = function ErrnoError(errno, node) { + this.node = node; + this.setErrno = function(errno2) { + this.errno = errno2; + }; + this.setErrno(errno); + this.message = "FS error"; + }; + FS.ErrnoError.prototype = new Error(); + FS.ErrnoError.prototype.constructor = FS.ErrnoError; + [44].forEach(function(code) { + FS.genericErrors[code] = new FS.ErrnoError(code); + FS.genericErrors[code].stack = ""; + }); + }, staticInit: function() { + FS.ensureErrnoError(); + FS.nameTable = new Array(4096); + FS.mount(MEMFS, {}, "/"); + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + FS.filesystems = { "MEMFS": MEMFS }; + }, init: function(input, output, error) { + FS.init.initialized = true; + FS.ensureErrnoError(); + Module["stdin"] = input || Module["stdin"]; + Module["stdout"] = output || Module["stdout"]; + Module["stderr"] = error || Module["stderr"]; + FS.createStandardStreams(); + }, quit: function() { + FS.init.initialized = false; + var fflush = Module["_fflush"]; + if (fflush) + fflush(0); + for (var i = 0; i < FS.streams.length; i++) { + var stream = FS.streams[i]; + if (!stream) { + continue; } - const aabb = pickResult && pickResult.entity ? pickResult.entity.aabb : scene.aabb; - if (pos) { // Fly to look at point, don't change eye->look dist - const camera = scene.camera; - math.subVec3(camera.eye, camera.look, []); - controllers.cameraFlight.flyTo({ - // look: pos, - // eye: xeokit.math.addVec3(pos, diff, []), - // up: camera.up, - aabb: aabb - }); - // TODO: Option to back off to fit AABB in view - } else {// Fly to fit target boundary in view - controllers.cameraFlight.flyTo({ - aabb: aabb - }); + FS.close(stream); + } + }, getMode: function(canRead, canWrite) { + var mode = 0; + if (canRead) + mode |= 292 | 73; + if (canWrite) + mode |= 146; + return mode; + }, findObject: function(path, dontResolveLastLink) { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (ret.exists) { + return ret.object; + } else { + return null; + } + }, analyzePath: function(path, dontResolveLastLink) { + try { + var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + path = lookup.path; + } catch (e) { + } + var ret = { isRoot: false, exists: false, error: 0, name: null, path: null, object: null, parentExists: false, parentPath: null, parentObject: null }; + try { + var lookup = FS.lookupPath(path, { parent: true }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === "/"; + } catch (e) { + ret.error = e.errno; + } + return ret; + }, createPath: function(parent, path, canRead, canWrite) { + parent = typeof parent === "string" ? parent : FS.getPath(parent); + var parts = path.split("/").reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) + continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) { } - }; - - canvas.addEventListener("mousemove", this._canvasMouseMoveHandler = (e) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + parent = current; + } + return current; + }, createFile: function(parent, name2, properties, canRead, canWrite) { + var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name2); + var mode = FS.getMode(canRead, canWrite); + return FS.create(path, mode); + }, createDataFile: function(parent, name2, data, canRead, canWrite, canOwn) { + var path = name2 ? PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name2) : parent; + var mode = FS.getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data === "string") { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) + arr[i] = data.charCodeAt(i); + data = arr; } - - if (leftDown || rightDown) { - return; + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + return node; + }, createDevice: function(parent, name2, input, output) { + var path = PATH.join2(typeof parent === "string" ? parent : FS.getPath(parent), name2); + var mode = FS.getMode(!!input, !!output); + if (!FS.createDevice.major) + FS.createDevice.major = 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + FS.registerDevice(dev, { open: function(stream) { + stream.seekable = false; + }, close: function(stream) { + if (output && output.buffer && output.buffer.length) { + output(10); } - - const hoverSubs = cameraControl.hasSubs("hover"); - const hoverOutSubs = cameraControl.hasSubs("hoverOut"); - const hoverOffSubs = cameraControl.hasSubs("hoverOff"); - const hoverSurfaceSubs = cameraControl.hasSubs("hoverSurface"); - - if (hoverSubs || hoverOutSubs || hoverOffSubs || hoverSurfaceSubs) { - - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickEntity = true; - pickController.schedulePickSurface = hoverSurfaceSubs; - - pickController.update(); - - if (pickController.pickResult) { - - const pickedEntityId = pickController.pickResult.entity.id; - - if (this._lastPickedEntityId !== pickedEntityId) { - - if (this._lastPickedEntityId !== undefined) { - - cameraControl.fire("hoverOut", { // Hovered off an entity - entity: scene.objects[this._lastPickedEntityId] - }, true); - } - - cameraControl.fire("hoverEnter", pickController.pickResult, true); // Hovering over a new entity - - this._lastPickedEntityId = pickedEntityId; - } - - cameraControl.fire("hover", pickController.pickResult, true); - - if (pickController.pickResult.worldPos) { // Hovering the surface of an entity - cameraControl.fire("hoverSurface", pickController.pickResult, true); - } - - } else { - - if (this._lastPickedEntityId !== undefined) { - - cameraControl.fire("hoverOut", { // Hovered off an entity - entity: scene.objects[this._lastPickedEntityId] - }, true); - - this._lastPickedEntityId = undefined; - } - - cameraControl.fire("hoverOff", { // Not hovering on any entity - canvasPos: pickController.pickCursorPos - }, true); - } + }, read: function(stream, buffer2, offset, length, pos) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === void 0 && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === void 0) + break; + bytesRead++; + buffer2[offset + i] = result; } - }); - - canvas.addEventListener('mousedown', this._canvasMouseDownHandler = (e) => { - - if (e.which === 1) { - leftDown = true; + if (bytesRead) { + stream.node.timestamp = Date.now(); } - - if (e.which === 3) { - rightDown = true; + return bytesRead; + }, write: function(stream, buffer2, offset, length, pos) { + for (var i = 0; i < length; i++) { + try { + output(buffer2[offset + i]); + } catch (e) { + throw new FS.ErrnoError(29); + } } - - const leftButtonDown = (e.which === 1); - - if (!leftButtonDown) { - return; + if (length) { + stream.node.timestamp = Date.now(); } - - if (!(configs.active && configs.pointerEnabled)) { - return; + return i; + } }); + return FS.mkdev(path, mode, dev); + }, forceLoadFile: function(obj) { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) + return true; + if (typeof XMLHttpRequest !== "undefined") { + throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); + } else if (read_) { + try { + obj.contents = intArrayFromString(read_(obj.url), true); + obj.usedBytes = obj.contents.length; + } catch (e) { + throw new FS.ErrnoError(29); } - - // Left mouse button down to start pivoting - - states.mouseDownClientX = e.clientX; - states.mouseDownClientY = e.clientY; - states.mouseDownCursorX = states.pointerCanvasPos[0]; - states.mouseDownCursorY = states.pointerCanvasPos[1]; - - if ((!configs.firstPerson) && configs.followPointer) { - - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickSurface = true; - - pickController.update(); - - if (e.which === 1) {// Left button - const pickResult = pickController.pickResult; - if (pickResult && pickResult.worldPos) { - pivotController.setPivotPos(pickResult.worldPos); - pivotController.startPivot(); - } else { - if (configs.smartPivot) { - pivotController.setCanvasPivotPos(states.pointerCanvasPos); - } else { - pivotController.setPivotPos(scene.camera.look); - } - pivotController.startPivot(); - } - } + } else { + throw new Error("Cannot load without read() or XMLHttpRequest."); + } + }, createLazyFile: function(parent, name2, url, canRead, canWrite) { + function LazyUint8Array() { + this.lengthKnown = false; + this.chunks = []; + } + LazyUint8Array.prototype.get = function LazyUint8Array_get(idx) { + if (idx > this.length - 1 || idx < 0) { + return void 0; } - }); - - document.addEventListener('mouseup', this._documentMouseUpHandler = (e) => { - - if (e.which === 1) { - leftDown = false; + var chunkOffset = idx % this.chunkSize; + var chunkNum = idx / this.chunkSize | 0; + return this.getter(chunkNum)[chunkOffset]; + }; + LazyUint8Array.prototype.setDataGetter = function LazyUint8Array_setDataGetter(getter) { + this.getter = getter; + }; + LazyUint8Array.prototype.cacheLength = function LazyUint8Array_cacheLength() { + var xhr = new XMLHttpRequest(); + xhr.open("HEAD", url, false); + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) + throw new Error("Couldn't load " + url + ". Status: " + xhr.status); + var datalength = Number(xhr.getResponseHeader("Content-length")); + var header; + var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; + var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; + var chunkSize = 1024 * 1024; + if (!hasByteServing) + chunkSize = datalength; + var doXHR = function(from, to) { + if (from > to) + throw new Error("invalid range (" + from + ", " + to + ") or no bytes requested!"); + if (to > datalength - 1) + throw new Error("only " + datalength + " bytes available! programmer error!"); + var xhr2 = new XMLHttpRequest(); + xhr2.open("GET", url, false); + if (datalength !== chunkSize) + xhr2.setRequestHeader("Range", "bytes=" + from + "-" + to); + if (typeof Uint8Array != "undefined") + xhr2.responseType = "arraybuffer"; + if (xhr2.overrideMimeType) { + xhr2.overrideMimeType("text/plain; charset=x-user-defined"); + } + xhr2.send(null); + if (!(xhr2.status >= 200 && xhr2.status < 300 || xhr2.status === 304)) + throw new Error("Couldn't load " + url + ". Status: " + xhr2.status); + if (xhr2.response !== void 0) { + return new Uint8Array(xhr2.response || []); + } else { + return intArrayFromString(xhr2.responseText || "", true); + } + }; + var lazyArray2 = this; + lazyArray2.setDataGetter(function(chunkNum) { + var start = chunkNum * chunkSize; + var end = (chunkNum + 1) * chunkSize - 1; + end = Math.min(end, datalength - 1); + if (typeof lazyArray2.chunks[chunkNum] === "undefined") { + lazyArray2.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray2.chunks[chunkNum] === "undefined") + throw new Error("doXHR failed!"); + return lazyArray2.chunks[chunkNum]; + }); + if (usesGzip || !datalength) { + chunkSize = datalength = 1; + datalength = this.getter(0).length; + chunkSize = datalength; + out("LazyFiles on gzip forces download of the whole file when length is accessed"); } - - if (e.which === 3) { - rightDown = false; + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + }; + if (typeof XMLHttpRequest !== "undefined") { + if (!ENVIRONMENT_IS_WORKER) + throw "Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc"; + var lazyArray = new LazyUint8Array(); + Object.defineProperties(lazyArray, { length: { get: function() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } }, chunkSize: { get: function() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } } }); + var properties = { isDevice: false, contents: lazyArray }; + } else { + var properties = { isDevice: false, url }; + } + var node = FS.createFile(parent, name2, properties, canRead, canWrite); + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + Object.defineProperties(node, { usedBytes: { get: function() { + return this.contents.length; + } } }); + var stream_ops = {}; + var keys = Object.keys(node.stream_ops); + keys.forEach(function(key2) { + var fn = node.stream_ops[key2]; + stream_ops[key2] = function forceLoadLazyFile() { + FS.forceLoadFile(node); + return fn.apply(null, arguments); + }; + }); + stream_ops.read = function stream_ops_read(stream, buffer2, offset, length, position) { + FS.forceLoadFile(node); + var contents = stream.node.contents; + if (position >= contents.length) + return 0; + var size = Math.min(contents.length - position, length); + if (contents.slice) { + for (var i = 0; i < size; i++) { + buffer2[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { + buffer2[offset + i] = contents.get(position + i); + } } - }); - - canvas.addEventListener('mouseup', this._canvasMouseUpHandler = (e) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + return size; + }; + node.stream_ops = stream_ops; + return node; + }, createPreloadedFile: function(parent, name2, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) { + Browser.init(); + var fullname = name2 ? PATH_FS.resolve(PATH.join2(parent, name2)) : parent; + function processData(byteArray) { + function finish(byteArray2) { + if (preFinish) + preFinish(); + if (!dontCreateFile) { + FS.createDataFile(parent, name2, byteArray2, canRead, canWrite, canOwn); + } + if (onload) + onload(); + removeRunDependency(); } - - const leftButtonUp = (e.which === 1); - - if (!leftButtonUp) { + var handled = false; + Module["preloadPlugins"].forEach(function(plugin) { + if (handled) return; + if (plugin["canHandle"](fullname)) { + plugin["handle"](byteArray, fullname, finish, function() { + if (onerror) + onerror(); + removeRunDependency(); + }); + handled = true; + } + }); + if (!handled) + finish(byteArray); + } + addRunDependency(); + if (typeof url == "string") { + asyncLoad(url, function(byteArray) { + processData(byteArray); + }, onerror); + } else { + processData(url); + } + }, indexedDB: function() { + return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; + }, DB_NAME: function() { + return "EM_FS_" + window.location.pathname; + }, DB_VERSION: 20, DB_STORE_NAME: "FILE_DATA", saveFilesToDB: function(paths, onload, onerror) { + onload = onload || function() { + }; + onerror = onerror || function() { + }; + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = function openRequest_onupgradeneeded() { + out("creating db"); + var db = openRequest.result; + db.createObjectStore(FS.DB_STORE_NAME); + }; + openRequest.onsuccess = function openRequest_onsuccess() { + var db = openRequest.result; + var transaction = db.transaction([FS.DB_STORE_NAME], "readwrite"); + var files = transaction.objectStore(FS.DB_STORE_NAME); + var ok = 0, fail = 0, total = paths.length; + function finish() { + if (fail == 0) + onload(); + else + onerror(); } - - // Left mouse button up to possibly pick or double-pick - - pivotController.hidePivot(); - - if (Math.abs(e.clientX - states.mouseDownClientX) > 3 || Math.abs(e.clientY - states.mouseDownClientY) > 3) { - return; + paths.forEach(function(path) { + var putRequest = files.put(FS.analyzePath(path).object.contents, path); + putRequest.onsuccess = function putRequest_onsuccess() { + ok++; + if (ok + fail == total) + finish(); + }; + putRequest.onerror = function putRequest_onerror() { + fail++; + if (ok + fail == total) + finish(); + }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + }, loadFilesFromDB: function(paths, onload, onerror) { + onload = onload || function() { + }; + onerror = onerror || function() { + }; + var indexedDB = FS.indexedDB(); + try { + var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); + } catch (e) { + return onerror(e); + } + openRequest.onupgradeneeded = onerror; + openRequest.onsuccess = function openRequest_onsuccess() { + var db = openRequest.result; + try { + var transaction = db.transaction([FS.DB_STORE_NAME], "readonly"); + } catch (e) { + onerror(e); + return; } - - const pickedSubs = cameraControl.hasSubs("picked"); - const pickedNothingSubs = cameraControl.hasSubs("pickedNothing"); - const pickedSurfaceSubs = cameraControl.hasSubs("pickedSurface"); - const doublePickedSubs = cameraControl.hasSubs("doublePicked"); - const doublePickedSurfaceSubs = cameraControl.hasSubs("doublePickedSurface"); - const doublePickedNothingSubs = cameraControl.hasSubs("doublePickedNothing"); - - if ((!configs.doublePickFlyTo) && - (!doublePickedSubs) && - (!doublePickedSurfaceSubs) && - (!doublePickedNothingSubs)) { - - // Avoid the single/double click differentiation timeout - - if (pickedSubs || pickedNothingSubs || pickedSurfaceSubs) { - - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickEntity = true; - pickController.schedulePickSurface = pickedSurfaceSubs; - pickController.update(); - - if (pickController.pickResult) { - - cameraControl.fire("picked", pickController.pickResult, true); - - if (pickController.pickedSurface) { - cameraControl.fire("pickedSurface", pickController.pickResult, true); - } - } else { - cameraControl.fire("pickedNothing", { - canvasPos: states.pointerCanvasPos - }, true); - } - } - - this._clicks = 0; - - return; + var files = transaction.objectStore(FS.DB_STORE_NAME); + var ok = 0, fail = 0, total = paths.length; + function finish() { + if (fail == 0) + onload(); + else + onerror(); } - - this._clicks++; - - if (this._clicks === 1) { // First click - - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickEntity = configs.doublePickFlyTo; - pickController.schedulePickSurface = pickedSurfaceSubs; - pickController.update(); - - const firstClickPickResult = pickController.pickResult; - const firstClickPickSurface = pickController.pickedSurface; - - this._timeout = setTimeout(() => { - - if (firstClickPickResult) { - - cameraControl.fire("picked", firstClickPickResult, true); - - if (firstClickPickSurface) { - - cameraControl.fire("pickedSurface", firstClickPickResult, true); - - if ((!configs.firstPerson) && configs.followPointer) { - controllers.pivotController.setPivotPos(firstClickPickResult.worldPos); - if (controllers.pivotController.startPivot()) { - controllers.pivotController.showPivot(); - } - } - } - } else { - cameraControl.fire("pickedNothing", { - canvasPos: states.pointerCanvasPos - }, true); - } - - this._clicks = 0; - - }, configs.doubleClickTimeFrame); - - } else { // Second click - - if (this._timeout !== null) { - window.clearTimeout(this._timeout); - this._timeout = null; - } - - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickEntity = configs.doublePickFlyTo || doublePickedSubs || doublePickedSurfaceSubs; - pickController.schedulePickSurface = pickController.schedulePickEntity && doublePickedSurfaceSubs; - pickController.update(); - - if (pickController.pickResult) { - - cameraControl.fire("doublePicked", pickController.pickResult, true); - - if (pickController.pickedSurface) { - cameraControl.fire("doublePickedSurface", pickController.pickResult, true); - } - - if (configs.doublePickFlyTo) { - - flyCameraTo(pickController.pickResult); - - if ((!configs.firstPerson) && configs.followPointer) { - - const pickedEntityAABB = pickController.pickResult.entity.aabb; - const pickedEntityCenterPos = math.getAABB3Center(pickedEntityAABB); - - controllers.pivotController.setPivotPos(pickedEntityCenterPos); - - if (controllers.pivotController.startPivot()) { - controllers.pivotController.showPivot(); - } - } - } - - } else { - - cameraControl.fire("doublePickedNothing", { - canvasPos: states.pointerCanvasPos - }, true); - - if (configs.doublePickFlyTo) { - - flyCameraTo(); - - if ((!configs.firstPerson) && configs.followPointer) { - - const sceneAABB = scene.aabb; - const sceneCenterPos = math.getAABB3Center(sceneAABB); - - controllers.pivotController.setPivotPos(sceneCenterPos); - - if (controllers.pivotController.startPivot()) { - controllers.pivotController.showPivot(); - } - } - } + paths.forEach(function(path) { + var getRequest = files.get(path); + getRequest.onsuccess = function getRequest_onsuccess() { + if (FS.analyzePath(path).exists) { + FS.unlink(path); } - - this._clicks = 0; - } - }, false); - } - - reset() { - this._clicks = 0; - this._lastPickedEntityId = null; - if (this._timeout) { - window.clearTimeout(this._timeout); - this._timeout = null; - } - } - - destroy() { - const canvas = this._scene.canvas.canvas; - canvas.removeEventListener("mousemove", this._canvasMouseMoveHandler); - canvas.removeEventListener("mousedown", this._canvasMouseDownHandler); - document.removeEventListener("mouseup", this._documentMouseUpHandler); - canvas.removeEventListener("mouseup", this._canvasMouseUpHandler); - if (this._timeout) { - window.clearTimeout(this._timeout); - this._timeout = null; - } - } -} - -/** - * @private - */ -class KeyboardPanRotateDollyHandler { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - const input = scene.input; - - const keyDownMap = []; - - const canvas = scene.canvas.canvas; - - let mouseMovedSinceLastKeyboardDolly = true; - - this._onSceneMouseMove = input.on("mousemove", () => { - mouseMovedSinceLastKeyboardDolly = true; - }); - - this._onSceneKeyDown = input.on("keydown", (keyCode) => { - if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { - return; - } - if (!states.mouseover) { - return; - } - keyDownMap[keyCode] = true; - - if (keyCode === input.KEY_SHIFT) { - canvas.style.cursor = "move"; + FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true); + ok++; + if (ok + fail == total) + finish(); + }; + getRequest.onerror = function getRequest_onerror() { + fail++; + if (ok + fail == total) + finish(); + }; + }); + transaction.onerror = onerror; + }; + openRequest.onerror = onerror; + } }; + var SYSCALLS = { mappings: {}, DEFAULT_POLLMASK: 5, umask: 511, calculateAt: function(dirfd, path, allowEmpty) { + if (path[0] === "/") { + return path; + } + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = FS.getStream(dirfd); + if (!dirstream) + throw new FS.ErrnoError(8); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44); } - }); - - this._onSceneKeyUp = input.on("keyup", (keyCode) => { - if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { - return; + return dir; + } + return PATH.join2(dir, path); + }, doStat: function(func, path, buf) { + try { + var stat = func(path); + } catch (e) { + if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) { + return -54; } - if (!states.mouseover) { - return; + throw e; + } + HEAP32[buf >>> 2] = stat.dev; + HEAP32[buf + 4 >>> 2] = 0; + HEAP32[buf + 8 >>> 2] = stat.ino; + HEAP32[buf + 12 >>> 2] = stat.mode; + HEAP32[buf + 16 >>> 2] = stat.nlink; + HEAP32[buf + 20 >>> 2] = stat.uid; + HEAP32[buf + 24 >>> 2] = stat.gid; + HEAP32[buf + 28 >>> 2] = stat.rdev; + HEAP32[buf + 32 >>> 2] = 0; + tempI64 = [stat.size >>> 0, (tempDouble = stat.size, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], HEAP32[buf + 40 >>> 2] = tempI64[0], HEAP32[buf + 44 >>> 2] = tempI64[1]; + HEAP32[buf + 48 >>> 2] = 4096; + HEAP32[buf + 52 >>> 2] = stat.blocks; + HEAP32[buf + 56 >>> 2] = stat.atime.getTime() / 1e3 | 0; + HEAP32[buf + 60 >>> 2] = 0; + HEAP32[buf + 64 >>> 2] = stat.mtime.getTime() / 1e3 | 0; + HEAP32[buf + 68 >>> 2] = 0; + HEAP32[buf + 72 >>> 2] = stat.ctime.getTime() / 1e3 | 0; + HEAP32[buf + 76 >>> 2] = 0; + tempI64 = [stat.ino >>> 0, (tempDouble = stat.ino, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], HEAP32[buf + 80 >>> 2] = tempI64[0], HEAP32[buf + 84 >>> 2] = tempI64[1]; + return 0; + }, doMsync: function(addr, stream, len, flags, offset) { + var buffer2 = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer2, offset, len, flags); + }, doMkdir: function(path, mode) { + path = PATH.normalize(path); + if (path[path.length - 1] === "/") + path = path.substr(0, path.length - 1); + FS.mkdir(path, mode, 0); + return 0; + }, doMknod: function(path, mode, dev) { + switch (mode & 61440) { + case 32768: + case 8192: + case 24576: + case 4096: + case 49152: + break; + default: + return -28; + } + FS.mknod(path, mode, dev); + return 0; + }, doReadlink: function(path, buf, bufsize) { + if (bufsize <= 0) + return -28; + var ret = FS.readlink(path); + var len = Math.min(bufsize, lengthBytesUTF8(ret)); + var endChar = HEAP8[buf + len >>> 0]; + stringToUTF8(ret, buf, bufsize + 1); + HEAP8[buf + len >>> 0] = endChar; + return len; + }, doAccess: function(path, amode) { + if (amode & ~7) { + return -28; + } + var node; + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + if (!node) { + return -44; + } + var perms = ""; + if (amode & 4) + perms += "r"; + if (amode & 2) + perms += "w"; + if (amode & 1) + perms += "x"; + if (perms && FS.nodePermissions(node, perms)) { + return -2; + } + return 0; + }, doDup: function(path, flags, suggestFD) { + var suggest = FS.getStream(suggestFD); + if (suggest) + FS.close(suggest); + return FS.open(path, flags, 0, suggestFD, suggestFD).fd; + }, doReadv: function(stream, iov, iovcnt, offset) { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAP32[iov + i * 8 >>> 2]; + var len = HEAP32[iov + (i * 8 + 4) >>> 2]; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) + return -1; + ret += curr; + if (curr < len) + break; + } + return ret; + }, doWritev: function(stream, iov, iovcnt, offset) { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAP32[iov + i * 8 >>> 2]; + var len = HEAP32[iov + (i * 8 + 4) >>> 2]; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) + return -1; + ret += curr; + } + return ret; + }, varargs: void 0, get: function() { + SYSCALLS.varargs += 4; + var ret = HEAP32[SYSCALLS.varargs - 4 >>> 2]; + return ret; + }, getStr: function(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, getStreamFromFD: function(fd) { + var stream = FS.getStream(fd); + if (!stream) + throw new FS.ErrnoError(8); + return stream; + }, get64: function(low, high) { + return low; + } }; + function ___sys_fcntl64(fd, cmd, varargs) { + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: { + var arg = SYSCALLS.get(); + if (arg < 0) { + return -28; + } + var newStream; + newStream = FS.open(stream.path, stream.flags, 0, arg); + return newStream.fd; + } + case 1: + case 2: + return 0; + case 3: + return stream.flags; + case 4: { + var arg = SYSCALLS.get(); + stream.flags |= arg; + return 0; + } + case 12: { + var arg = SYSCALLS.get(); + var offset = 0; + HEAP16[arg + offset >>> 1] = 2; + return 0; + } + case 13: + case 14: + return 0; + case 16: + case 8: + return -28; + case 9: + setErrNo(28); + return -1; + default: { + return -28; + } } - keyDownMap[keyCode] = false; - - if (keyCode === input.KEY_SHIFT) { - canvas.style.cursor = null; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return -e.errno; + } + } + function ___sys_ioctl(fd, op, varargs) { + SYSCALLS.varargs = varargs; + try { + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: + case 21505: { + if (!stream.tty) + return -59; + return 0; + } + case 21510: + case 21511: + case 21512: + case 21506: + case 21507: + case 21508: { + if (!stream.tty) + return -59; + return 0; + } + case 21519: { + if (!stream.tty) + return -59; + var argp = SYSCALLS.get(); + HEAP32[argp >>> 2] = 0; + return 0; + } + case 21520: { + if (!stream.tty) + return -59; + return -28; + } + case 21531: { + var argp = SYSCALLS.get(); + return FS.ioctl(stream, op, argp); + } + case 21523: { + if (!stream.tty) + return -59; + return 0; + } + case 21524: { + if (!stream.tty) + return -59; + return 0; + } + default: + abort("bad ioctl syscall " + op); } - }); - - this._onTick = scene.on("tick", (e) => { - - if (!(configs.active && configs.pointerEnabled) || (!scene.input.keyboardEnabled)) { - return; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return -e.errno; + } + } + function ___sys_open(path, flags, varargs) { + SYSCALLS.varargs = varargs; + try { + var pathname = SYSCALLS.getStr(path); + var mode = varargs ? SYSCALLS.get() : 0; + var stream = FS.open(pathname, flags, mode); + return stream.fd; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return -e.errno; + } + } + var tupleRegistrations = {}; + function runDestructors(destructors) { + while (destructors.length) { + var ptr = destructors.pop(); + var del = destructors.pop(); + del(ptr); + } + } + function simpleReadValueFromPointer(pointer) { + return this["fromWireType"](HEAPU32[pointer >>> 2]); + } + var awaitingDependencies = {}; + var registeredTypes = {}; + var typeDependencies = {}; + var char_0 = 48; + var char_9 = 57; + function makeLegalFunctionName(name2) { + if (name2 === void 0) { + return "_unknown"; + } + name2 = name2.replace(/[^a-zA-Z0-9_]/g, "$"); + var f = name2.charCodeAt(0); + if (f >= char_0 && f <= char_9) { + return "_" + name2; + } else { + return name2; + } + } + function createNamedFunction(name2, body) { + name2 = makeLegalFunctionName(name2); + return new Function("body", "return function " + name2 + '() {\n "use strict"; return body.apply(this, arguments);\n};\n')(body); + } + function extendError(baseErrorType, errorName) { + var errorClass = createNamedFunction(errorName, function(message) { + this.name = errorName; + this.message = message; + var stack = new Error(message).stack; + if (stack !== void 0) { + this.stack = this.toString() + "\n" + stack.replace(/^Error(:[^\n]*)?\n/, ""); } - - if (!states.mouseover) { - return; + }); + errorClass.prototype = Object.create(baseErrorType.prototype); + errorClass.prototype.constructor = errorClass; + errorClass.prototype.toString = function() { + if (this.message === void 0) { + return this.name; + } else { + return this.name + ": " + this.message; } - - const cameraControl = controllers.cameraControl; - const elapsedSecs = (e.deltaTime / 1000.0); - - //------------------------------------------------------------------------------------------------- - // Keyboard rotation - //------------------------------------------------------------------------------------------------- - - if (!configs.planView) { - - const rotateYPos = cameraControl._isKeyDownForAction(cameraControl.ROTATE_Y_POS, keyDownMap); - const rotateYNeg = cameraControl._isKeyDownForAction(cameraControl.ROTATE_Y_NEG, keyDownMap); - const rotateXPos = cameraControl._isKeyDownForAction(cameraControl.ROTATE_X_POS, keyDownMap); - const rotateXNeg = cameraControl._isKeyDownForAction(cameraControl.ROTATE_X_NEG, keyDownMap); - - const orbitDelta = elapsedSecs * configs.keyboardRotationRate; - - if (rotateYPos || rotateYNeg || rotateXPos || rotateXNeg) { - - if ((!configs.firstPerson) && configs.followPointer) { - controllers.pivotController.startPivot(); - } - - if (rotateYPos) { - updates.rotateDeltaY += orbitDelta; - - } else if (rotateYNeg) { - updates.rotateDeltaY -= orbitDelta; - } - - if (rotateXPos) { - updates.rotateDeltaX += orbitDelta; - - } else if (rotateXNeg) { - updates.rotateDeltaX -= orbitDelta; - } - - if ((!configs.firstPerson) && configs.followPointer) { - controllers.pivotController.startPivot(); - } - } + }; + return errorClass; + } + var InternalError = void 0; + function throwInternalError(message) { + throw new InternalError(message); + } + function whenDependentTypesAreResolved(myTypes, dependentTypes, getTypeConverters) { + myTypes.forEach(function(type) { + typeDependencies[type] = dependentTypes; + }); + function onComplete(typeConverters2) { + var myTypeConverters = getTypeConverters(typeConverters2); + if (myTypeConverters.length !== myTypes.length) { + throwInternalError("Mismatched type converter count"); } - - //------------------------------------------------------------------------------------------------- - // Keyboard panning - //------------------------------------------------------------------------------------------------- - - if (!keyDownMap[input.KEY_CTRL] && !keyDownMap[input.KEY_ALT]) { - - const dollyBackwards = cameraControl._isKeyDownForAction(cameraControl.DOLLY_BACKWARDS, keyDownMap); - const dollyForwards = cameraControl._isKeyDownForAction(cameraControl.DOLLY_FORWARDS, keyDownMap); - - if (dollyBackwards || dollyForwards) { - - const dollyDelta = elapsedSecs * configs.keyboardDollyRate; - - if ((!configs.firstPerson) && configs.followPointer) { - controllers.pivotController.startPivot(); - } - if (dollyForwards) { - updates.dollyDelta -= dollyDelta; - } else if (dollyBackwards) { - updates.dollyDelta += dollyDelta; - } - - if (mouseMovedSinceLastKeyboardDolly) { - states.followPointerDirty = true; - mouseMovedSinceLastKeyboardDolly = false; - } - } + for (var i = 0; i < myTypes.length; ++i) { + registerType(myTypes[i], myTypeConverters[i]); } - - const panForwards = cameraControl._isKeyDownForAction(cameraControl.PAN_FORWARDS, keyDownMap); - const panBackwards = cameraControl._isKeyDownForAction(cameraControl.PAN_BACKWARDS, keyDownMap); - const panLeft = cameraControl._isKeyDownForAction(cameraControl.PAN_LEFT, keyDownMap); - const panRight = cameraControl._isKeyDownForAction(cameraControl.PAN_RIGHT, keyDownMap); - const panUp = cameraControl._isKeyDownForAction(cameraControl.PAN_UP, keyDownMap); - const panDown = cameraControl._isKeyDownForAction(cameraControl.PAN_DOWN, keyDownMap); - - const panDelta = (keyDownMap[input.KEY_ALT] ? 0.3 : 1.0) * elapsedSecs * configs.keyboardPanRate; // ALT for slower pan rate - - if (panForwards || panBackwards || panLeft || panRight || panUp || panDown) { - - if ((!configs.firstPerson) && configs.followPointer) { - controllers.pivotController.startPivot(); - } - - if (panDown) { - updates.panDeltaY += panDelta; - - } else if (panUp) { - updates.panDeltaY += -panDelta; - } - - if (panRight) { - updates.panDeltaX += -panDelta; - - } else if (panLeft) { - updates.panDeltaX += panDelta; + } + var typeConverters = new Array(dependentTypes.length); + var unregisteredTypes = []; + var registered = 0; + dependentTypes.forEach(function(dt, i) { + if (registeredTypes.hasOwnProperty(dt)) { + typeConverters[i] = registeredTypes[dt]; + } else { + unregisteredTypes.push(dt); + if (!awaitingDependencies.hasOwnProperty(dt)) { + awaitingDependencies[dt] = []; + } + awaitingDependencies[dt].push(function() { + typeConverters[i] = registeredTypes[dt]; + ++registered; + if (registered === unregisteredTypes.length) { + onComplete(typeConverters); } - - if (panBackwards) { - updates.panDeltaZ += panDelta; - - } else if (panForwards) { - updates.panDeltaZ += -panDelta; + }); + } + }); + if (unregisteredTypes.length === 0) { + onComplete(typeConverters); + } + } + function __embind_finalize_value_array(rawTupleType) { + var reg = tupleRegistrations[rawTupleType]; + delete tupleRegistrations[rawTupleType]; + var elements = reg.elements; + var elementsLength = elements.length; + var elementTypes = elements.map(function(elt) { + return elt.getterReturnType; + }).concat(elements.map(function(elt) { + return elt.setterArgumentType; + })); + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + whenDependentTypesAreResolved([rawTupleType], elementTypes, function(elementTypes2) { + elements.forEach(function(elt, i) { + var getterReturnType = elementTypes2[i]; + var getter = elt.getter; + var getterContext = elt.getterContext; + var setterArgumentType = elementTypes2[i + elementsLength]; + var setter = elt.setter; + var setterContext = elt.setterContext; + elt.read = function(ptr) { + return getterReturnType["fromWireType"](getter(getterContext, ptr)); + }; + elt.write = function(ptr, o) { + var destructors = []; + setter(setterContext, ptr, setterArgumentType["toWireType"](destructors, o)); + runDestructors(destructors); + }; + }); + return [{ name: reg.name, "fromWireType": function(ptr) { + var rv = new Array(elementsLength); + for (var i = 0; i < elementsLength; ++i) { + rv[i] = elements[i].read(ptr); + } + rawDestructor(ptr); + return rv; + }, "toWireType": function(destructors, o) { + if (elementsLength !== o.length) { + throw new TypeError("Incorrect number of tuple elements for " + reg.name + ": expected=" + elementsLength + ", actual=" + o.length); + } + var ptr = rawConstructor(); + for (var i = 0; i < elementsLength; ++i) { + elements[i].write(ptr, o[i]); + } + if (destructors !== null) { + destructors.push(rawDestructor, ptr); + } + return ptr; + }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: rawDestructor }]; + }); + } + var structRegistrations = {}; + function __embind_finalize_value_object(structType) { + var reg = structRegistrations[structType]; + delete structRegistrations[structType]; + var rawConstructor = reg.rawConstructor; + var rawDestructor = reg.rawDestructor; + var fieldRecords = reg.fields; + var fieldTypes = fieldRecords.map(function(field) { + return field.getterReturnType; + }).concat(fieldRecords.map(function(field) { + return field.setterArgumentType; + })); + whenDependentTypesAreResolved([structType], fieldTypes, function(fieldTypes2) { + var fields = {}; + fieldRecords.forEach(function(field, i) { + var fieldName = field.fieldName; + var getterReturnType = fieldTypes2[i]; + var getter = field.getter; + var getterContext = field.getterContext; + var setterArgumentType = fieldTypes2[i + fieldRecords.length]; + var setter = field.setter; + var setterContext = field.setterContext; + fields[fieldName] = { read: function(ptr) { + return getterReturnType["fromWireType"](getter(getterContext, ptr)); + }, write: function(ptr, o) { + var destructors = []; + setter(setterContext, ptr, setterArgumentType["toWireType"](destructors, o)); + runDestructors(destructors); + } }; + }); + return [{ name: reg.name, "fromWireType": function(ptr) { + var rv = {}; + for (var i in fields) { + rv[i] = fields[i].read(ptr); + } + rawDestructor(ptr); + return rv; + }, "toWireType": function(destructors, o) { + for (var fieldName in fields) { + if (!(fieldName in o)) { + throw new TypeError('Missing field: "' + fieldName + '"'); } + } + var ptr = rawConstructor(); + for (fieldName in fields) { + fields[fieldName].write(ptr, o[fieldName]); + } + if (destructors !== null) { + destructors.push(rawDestructor, ptr); + } + return ptr; + }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: rawDestructor }]; + }); + } + function __embind_register_bigint(primitiveType, name2, size, minRange, maxRange) { + } + function getShiftFromSize(size) { + switch (size) { + case 1: + return 0; + case 2: + return 1; + case 4: + return 2; + case 8: + return 3; + default: + throw new TypeError("Unknown type size: " + size); + } + } + function embind_init_charCodes() { + var codes = new Array(256); + for (var i = 0; i < 256; ++i) { + codes[i] = String.fromCharCode(i); + } + embind_charCodes = codes; + } + var embind_charCodes = void 0; + function readLatin1String(ptr) { + var ret = ""; + var c = ptr; + while (HEAPU8[c >>> 0]) { + ret += embind_charCodes[HEAPU8[c++ >>> 0]]; + } + return ret; + } + var BindingError = void 0; + function throwBindingError(message) { + throw new BindingError(message); + } + function registerType(rawType, registeredInstance, options) { + options = options || {}; + if (!("argPackAdvance" in registeredInstance)) { + throw new TypeError("registerType registeredInstance requires argPackAdvance"); + } + var name2 = registeredInstance.name; + if (!rawType) { + throwBindingError('type "' + name2 + '" must have a positive integer typeid pointer'); + } + if (registeredTypes.hasOwnProperty(rawType)) { + if (options.ignoreDuplicateRegistrations) { + return; + } else { + throwBindingError("Cannot register type '" + name2 + "' twice"); } - }); - } - - reset() { - } - - destroy() { - - this._scene.off(this._onTick); - - this._scene.input.off(this._onSceneMouseMove); - this._scene.input.off(this._onSceneKeyDown); - this._scene.input.off(this._onSceneKeyUp); - } -} - -const SCALE_DOLLY_EACH_FRAME = 1; // Recalculate dolly speed for eye->target distance on each Nth frame -const EPSILON = 0.001; -const tempVec3 = math.vec3(); - -/** - * Handles camera updates on each "tick" that were scheduled by the various controllers. - * - * @private - */ -class CameraUpdater { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - const camera = scene.camera; - const pickController = controllers.pickController; - const pivotController = controllers.pivotController; - const panController = controllers.panController; - - let countDown = SCALE_DOLLY_EACH_FRAME; // Decrements on each tick - let dollyDistFactor = 1.0; // Calculated when countDown is zero - let followPointerWorldPos = null; // Holds the pointer's World position when configs.followPointer is true - - this._onTick = scene.on("tick", () => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + } + registeredTypes[rawType] = registeredInstance; + delete typeDependencies[rawType]; + if (awaitingDependencies.hasOwnProperty(rawType)) { + var callbacks = awaitingDependencies[rawType]; + delete awaitingDependencies[rawType]; + callbacks.forEach(function(cb) { + cb(); + }); + } + } + function __embind_register_bool(rawType, name2, size, trueValue, falseValue) { + var shift = getShiftFromSize(size); + name2 = readLatin1String(name2); + registerType(rawType, { name: name2, "fromWireType": function(wt) { + return !!wt; + }, "toWireType": function(destructors, o) { + return o ? trueValue : falseValue; + }, "argPackAdvance": 8, "readValueFromPointer": function(pointer) { + var heap; + if (size === 1) { + heap = HEAP8; + } else if (size === 2) { + heap = HEAP16; + } else if (size === 4) { + heap = HEAP32; + } else { + throw new TypeError("Unknown boolean type size: " + name2); } - - let cursorType = "default"; - - //---------------------------------------------------------------------------------------------------------- - // Dolly decay - //------------------------------------------------------------------------------------ ---------------------- - - if (Math.abs(updates.dollyDelta) < EPSILON) { - updates.dollyDelta = 0; + return this["fromWireType"](heap[pointer >>> shift]); + }, destructorFunction: null }); + } + function ClassHandle_isAliasOf(other) { + if (!(this instanceof ClassHandle)) { + return false; + } + if (!(other instanceof ClassHandle)) { + return false; + } + var leftClass = this.$$.ptrType.registeredClass; + var left = this.$$.ptr; + var rightClass = other.$$.ptrType.registeredClass; + var right = other.$$.ptr; + while (leftClass.baseClass) { + left = leftClass.upcast(left); + leftClass = leftClass.baseClass; + } + while (rightClass.baseClass) { + right = rightClass.upcast(right); + rightClass = rightClass.baseClass; + } + return leftClass === rightClass && left === right; + } + function shallowCopyInternalPointer(o) { + return { count: o.count, deleteScheduled: o.deleteScheduled, preservePointerOnDelete: o.preservePointerOnDelete, ptr: o.ptr, ptrType: o.ptrType, smartPtr: o.smartPtr, smartPtrType: o.smartPtrType }; + } + function throwInstanceAlreadyDeleted(obj) { + function getInstanceTypeName(handle) { + return handle.$$.ptrType.registeredClass.name; + } + throwBindingError(getInstanceTypeName(obj) + " instance already deleted"); + } + var finalizationGroup = false; + function detachFinalizer(handle) { + } + function runDestructor($$) { + if ($$.smartPtr) { + $$.smartPtrType.rawDestructor($$.smartPtr); + } else { + $$.ptrType.registeredClass.rawDestructor($$.ptr); + } + } + function releaseClassHandle($$) { + $$.count.value -= 1; + var toDelete = $$.count.value === 0; + if (toDelete) { + runDestructor($$); + } + } + function attachFinalizer(handle) { + if (typeof FinalizationGroup === "undefined") { + attachFinalizer = function(handle2) { + return handle2; + }; + return handle; + } + finalizationGroup = new FinalizationGroup(function(iter) { + for (var result = iter.next(); !result.done; result = iter.next()) { + var $$ = result.value; + if (!$$.ptr) { + console.warn("object already deleted: " + $$.ptr); + } else { + releaseClassHandle($$); + } } - - //---------------------------------------------------------------------------------------------------------- - // Rotation decay - //---------------------------------------------------------------------------------------------------------- - - if (Math.abs(updates.rotateDeltaX) < EPSILON) { - updates.rotateDeltaX = 0; + }); + attachFinalizer = function(handle2) { + finalizationGroup.register(handle2, handle2.$$, handle2.$$); + return handle2; + }; + detachFinalizer = function(handle2) { + finalizationGroup.unregister(handle2.$$); + }; + return attachFinalizer(handle); + } + function ClassHandle_clone() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.preservePointerOnDelete) { + this.$$.count.value += 1; + return this; + } else { + var clone = attachFinalizer(Object.create(Object.getPrototypeOf(this), { $$: { value: shallowCopyInternalPointer(this.$$) } })); + clone.$$.count.value += 1; + clone.$$.deleteScheduled = false; + return clone; + } + } + function ClassHandle_delete() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { + throwBindingError("Object already scheduled for deletion"); + } + detachFinalizer(this); + releaseClassHandle(this.$$); + if (!this.$$.preservePointerOnDelete) { + this.$$.smartPtr = void 0; + this.$$.ptr = void 0; + } + } + function ClassHandle_isDeleted() { + return !this.$$.ptr; + } + var delayFunction = void 0; + var deletionQueue = []; + function flushPendingDeletes() { + while (deletionQueue.length) { + var obj = deletionQueue.pop(); + obj.$$.deleteScheduled = false; + obj["delete"](); + } + } + function ClassHandle_deleteLater() { + if (!this.$$.ptr) { + throwInstanceAlreadyDeleted(this); + } + if (this.$$.deleteScheduled && !this.$$.preservePointerOnDelete) { + throwBindingError("Object already scheduled for deletion"); + } + deletionQueue.push(this); + if (deletionQueue.length === 1 && delayFunction) { + delayFunction(flushPendingDeletes); + } + this.$$.deleteScheduled = true; + return this; + } + function init_ClassHandle() { + ClassHandle.prototype["isAliasOf"] = ClassHandle_isAliasOf; + ClassHandle.prototype["clone"] = ClassHandle_clone; + ClassHandle.prototype["delete"] = ClassHandle_delete; + ClassHandle.prototype["isDeleted"] = ClassHandle_isDeleted; + ClassHandle.prototype["deleteLater"] = ClassHandle_deleteLater; + } + function ClassHandle() { + } + var registeredPointers = {}; + function ensureOverloadTable(proto, methodName, humanName) { + if (proto[methodName].overloadTable === void 0) { + var prevFunc = proto[methodName]; + proto[methodName] = function() { + if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { + throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); + } + return proto[methodName].overloadTable[arguments.length].apply(this, arguments); + }; + proto[methodName].overloadTable = []; + proto[methodName].overloadTable[prevFunc.argCount] = prevFunc; + } + } + function exposePublicSymbol(name2, value, numArguments) { + if (Module.hasOwnProperty(name2)) { + if (numArguments === void 0 || Module[name2].overloadTable !== void 0 && Module[name2].overloadTable[numArguments] !== void 0) { + throwBindingError("Cannot register public name '" + name2 + "' twice"); } - - if (Math.abs(updates.rotateDeltaY) < EPSILON) { - updates.rotateDeltaY = 0; + ensureOverloadTable(Module, name2, name2); + if (Module.hasOwnProperty(numArguments)) { + throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); } - - if (updates.rotateDeltaX !== 0 || updates.rotateDeltaY !== 0) { - updates.dollyDelta = 0; + Module[name2].overloadTable[numArguments] = value; + } else { + Module[name2] = value; + if (numArguments !== void 0) { + Module[name2].numArguments = numArguments; } - - //---------------------------------------------------------------------------------------------------------- - // Dolly speed eye->look scaling - // - // If pointer is over an object, then dolly speed is proportional to the distance to that object. - // - // If pointer is not over an object, then dolly speed is proportional to the distance to the last - // object the pointer was over. This is so that we can dolly to structures that may have gaps through - // which empty background shows, that the pointer may inadvertently be over. In these cases, we don't - // want dolly speed wildly varying depending on how accurately the user avoids the gaps with the pointer. - //---------------------------------------------------------------------------------------------------------- - - if (configs.followPointer) { - - if (--countDown <= 0) { - - countDown = SCALE_DOLLY_EACH_FRAME; - - if (updates.dollyDelta !== 0) { - if (updates.rotateDeltaY === 0 && updates.rotateDeltaX === 0) { - - if (configs.followPointer && states.followPointerDirty) { - - pickController.pickCursorPos = states.pointerCanvasPos; - pickController.schedulePickSurface = true; - pickController.update(); - - if (pickController.pickResult && pickController.pickResult.worldPos) { - followPointerWorldPos = pickController.pickResult.worldPos; - - } else { - dollyDistFactor = 1.0; - followPointerWorldPos = null; - } - - states.followPointerDirty = false; - } - } - - if (followPointerWorldPos) { - const dist = Math.abs(math.lenVec3(math.subVec3(followPointerWorldPos, scene.camera.eye, tempVec3))); - dollyDistFactor = dist / configs.dollyProximityThreshold; - } - - if (dollyDistFactor < configs.dollyMinSpeed) { - dollyDistFactor = configs.dollyMinSpeed; - } - } - } + } + } + function RegisteredClass(name2, constructor, instancePrototype, rawDestructor, baseClass, getActualType, upcast, downcast) { + this.name = name2; + this.constructor = constructor; + this.instancePrototype = instancePrototype; + this.rawDestructor = rawDestructor; + this.baseClass = baseClass; + this.getActualType = getActualType; + this.upcast = upcast; + this.downcast = downcast; + this.pureVirtualFunctions = []; + } + function upcastPointer(ptr, ptrClass, desiredClass) { + while (ptrClass !== desiredClass) { + if (!ptrClass.upcast) { + throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); } - - const dollyDeltaForDist = (updates.dollyDelta * dollyDistFactor); - - //---------------------------------------------------------------------------------------------------------- - // Rotation - //---------------------------------------------------------------------------------------------------------- - - if (updates.rotateDeltaY !== 0 || updates.rotateDeltaX !== 0) { - - if ((!configs.firstPerson) && configs.followPointer && pivotController.getPivoting()) { - pivotController.continuePivot(updates.rotateDeltaY, updates.rotateDeltaX); - pivotController.showPivot(); - - } else { - - if (updates.rotateDeltaX !== 0) { - if (configs.firstPerson) { - camera.pitch(-updates.rotateDeltaX); - } else { - camera.orbitPitch(updates.rotateDeltaX); - } - } - - if (updates.rotateDeltaY !== 0) { - if (configs.firstPerson) { - camera.yaw(updates.rotateDeltaY); - } else { - camera.orbitYaw(updates.rotateDeltaY); - } - } - } - - updates.rotateDeltaX *= configs.rotationInertia; - updates.rotateDeltaY *= configs.rotationInertia; - - cursorType = "grabbing"; + ptr = ptrClass.upcast(ptr); + ptrClass = ptrClass.baseClass; + } + return ptr; + } + function constNoSmartPtrRawPointerToWireType(destructors, handle) { + if (handle === null) { + if (this.isReference) { + throwBindingError("null is not a valid " + this.name); } - - //---------------------------------------------------------------------------------------------------------- - // Panning - //---------------------------------------------------------------------------------------------------------- - - if (Math.abs(updates.panDeltaX) < EPSILON) { - updates.panDeltaX = 0; + return 0; + } + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + return ptr; + } + function genericPointerToWireType(destructors, handle) { + var ptr; + if (handle === null) { + if (this.isReference) { + throwBindingError("null is not a valid " + this.name); } - - if (Math.abs(updates.panDeltaY) < EPSILON) { - updates.panDeltaY = 0; + if (this.isSmartPointer) { + ptr = this.rawConstructor(); + if (destructors !== null) { + destructors.push(this.rawDestructor, ptr); + } + return ptr; + } else { + return 0; } - - if (Math.abs(updates.panDeltaZ) < EPSILON) { - updates.panDeltaZ = 0; + } + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); + } + if (!this.isConst && handle.$$.ptrType.isConst) { + throwBindingError("Cannot convert argument of type " + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + " to parameter type " + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + if (this.isSmartPointer) { + if (handle.$$.smartPtr === void 0) { + throwBindingError("Passing raw pointer to smart pointer is illegal"); } - - if (updates.panDeltaX !== 0 || updates.panDeltaY !== 0 || updates.panDeltaZ !== 0) { - - const vec = math.vec3(); - - vec[0] = updates.panDeltaX; - vec[1] = updates.panDeltaY; - vec[2] = updates.panDeltaZ; - - let verticalEye; - let verticalLook; - - if (configs.constrainVertical) { - - if (camera.xUp) { - verticalEye = camera.eye[0]; - verticalLook = camera.look[0]; - } else if (camera.yUp) { - verticalEye = camera.eye[1]; - verticalLook = camera.look[1]; - } else if (camera.zUp) { - verticalEye = camera.eye[2]; - verticalLook = camera.look[2]; - } - - camera.pan(vec); - - const eye = camera.eye; - const look = camera.look; - - if (camera.xUp) { - eye[0] = verticalEye; - look[0] = verticalLook; - } else if (camera.yUp) { - eye[1] = verticalEye; - look[1] = verticalLook; - } else if (camera.zUp) { - eye[2] = verticalEye; - look[2] = verticalLook; - } - - camera.eye = eye; - camera.look = look; - + switch (this.sharingPolicy) { + case 0: + if (handle.$$.smartPtrType === this) { + ptr = handle.$$.smartPtr; } else { - camera.pan(vec); + throwBindingError("Cannot convert argument of type " + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + " to parameter type " + this.name); } - - cursorType = "grabbing"; - } - - updates.panDeltaX *= configs.panInertia; - updates.panDeltaY *= configs.panInertia; - updates.panDeltaZ *= configs.panInertia; - - //---------------------------------------------------------------------------------------------------------- - // Dollying - //---------------------------------------------------------------------------------------------------------- - - if (dollyDeltaForDist !== 0) { - - if (dollyDeltaForDist < 0) { - cursorType = "zoom-in"; + break; + case 1: + ptr = handle.$$.smartPtr; + break; + case 2: + if (handle.$$.smartPtrType === this) { + ptr = handle.$$.smartPtr; } else { - cursorType = "zoom-out"; - } - - if (configs.firstPerson) { - - let verticalEye; - let verticalLook; - - if (configs.constrainVertical) { - if (camera.xUp) { - verticalEye = camera.eye[0]; - verticalLook = camera.look[0]; - } else if (camera.yUp) { - verticalEye = camera.eye[1]; - verticalLook = camera.look[1]; - } else if (camera.zUp) { - verticalEye = camera.eye[2]; - verticalLook = camera.look[2]; - } - } - - if (configs.followPointer) { - const dolliedThroughSurface = panController.dollyToCanvasPos(followPointerWorldPos, states.pointerCanvasPos, -dollyDeltaForDist); - if (dolliedThroughSurface) { - states.followPointerDirty = true; - } - } else { - camera.pan([0, 0, dollyDeltaForDist]); - camera.ortho.scale = camera.ortho.scale - dollyDeltaForDist; - } - - if (configs.constrainVertical) { - const eye = camera.eye; - const look = camera.look; - if (camera.xUp) { - eye[0] = verticalEye; - look[0] = verticalLook; - } else if (camera.yUp) { - eye[1] = verticalEye; - look[1] = verticalLook; - } else if (camera.zUp) { - eye[2] = verticalEye; - look[2] = verticalLook; - } - camera.eye = eye; - camera.look = look; - } - - } else if (configs.planView) { - - if (configs.followPointer) { - const dolliedThroughSurface = panController.dollyToCanvasPos(followPointerWorldPos, states.pointerCanvasPos, -dollyDeltaForDist); - if (dolliedThroughSurface) { - states.followPointerDirty = true; - } - } else { - camera.ortho.scale = camera.ortho.scale + dollyDeltaForDist; - camera.zoom(dollyDeltaForDist); - } - - } else { // Orbiting - - if (configs.followPointer) { - const dolliedThroughSurface = panController.dollyToCanvasPos(followPointerWorldPos, states.pointerCanvasPos, -dollyDeltaForDist); - if (dolliedThroughSurface) { - states.followPointerDirty = true; - } - } else { - camera.ortho.scale = camera.ortho.scale + dollyDeltaForDist; - camera.zoom(dollyDeltaForDist); - } + var clonedHandle = handle["clone"](); + ptr = this.rawShare(ptr, __emval_register(function() { + clonedHandle["delete"](); + })); + if (destructors !== null) { + destructors.push(this.rawDestructor, ptr); + } } - - updates.dollyDelta *= configs.dollyInertia; + break; + default: + throwBindingError("Unsupporting sharing policy"); } - - pickController.fireEvents(); - - document.body.style.cursor = cursorType; - }); - } - - - destroy() { - this._scene.off(this._onTick); - } -} - -/** - * @private - */ -class MouseMiscHandler { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - - const canvas = this._scene.canvas.canvas; - - canvas.addEventListener("mouseenter", this._mouseEnterHandler = () => { - states.mouseover = true; - }); - - canvas.addEventListener("mouseleave", this._mouseLeaveHandler = () => { - states.mouseover = false; - canvas.style.cursor = null; - }); - - document.addEventListener("mousemove", this._mouseMoveHandler = (e) => { - getCanvasPosFromEvent$2(e, canvas, states.pointerCanvasPos); - }); - - canvas.addEventListener("mousedown", this._mouseDownHandler = (e) => { - if (!(configs.active && configs.pointerEnabled)) { - return; + } + return ptr; + } + function nonConstNoSmartPtrRawPointerToWireType(destructors, handle) { + if (handle === null) { + if (this.isReference) { + throwBindingError("null is not a valid " + this.name); + } + return 0; + } + if (!handle.$$) { + throwBindingError('Cannot pass "' + _embind_repr(handle) + '" as a ' + this.name); + } + if (!handle.$$.ptr) { + throwBindingError("Cannot pass deleted object as a pointer of type " + this.name); + } + if (handle.$$.ptrType.isConst) { + throwBindingError("Cannot convert argument of type " + handle.$$.ptrType.name + " to parameter type " + this.name); + } + var handleClass = handle.$$.ptrType.registeredClass; + var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); + return ptr; + } + function RegisteredPointer_getPointee(ptr) { + if (this.rawGetPointee) { + ptr = this.rawGetPointee(ptr); + } + return ptr; + } + function RegisteredPointer_destructor(ptr) { + if (this.rawDestructor) { + this.rawDestructor(ptr); + } + } + function RegisteredPointer_deleteObject(handle) { + if (handle !== null) { + handle["delete"](); + } + } + function downcastPointer(ptr, ptrClass, desiredClass) { + if (ptrClass === desiredClass) { + return ptr; + } + if (desiredClass.baseClass === void 0) { + return null; + } + var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); + if (rv === null) { + return null; + } + return desiredClass.downcast(rv); + } + function getInheritedInstanceCount() { + return Object.keys(registeredInstances).length; + } + function getLiveInheritedInstances() { + var rv = []; + for (var k in registeredInstances) { + if (registeredInstances.hasOwnProperty(k)) { + rv.push(registeredInstances[k]); + } + } + return rv; + } + function setDelayFunction(fn) { + delayFunction = fn; + if (deletionQueue.length && delayFunction) { + delayFunction(flushPendingDeletes); + } + } + function init_embind() { + Module["getInheritedInstanceCount"] = getInheritedInstanceCount; + Module["getLiveInheritedInstances"] = getLiveInheritedInstances; + Module["flushPendingDeletes"] = flushPendingDeletes; + Module["setDelayFunction"] = setDelayFunction; + } + var registeredInstances = {}; + function getBasestPointer(class_, ptr) { + if (ptr === void 0) { + throwBindingError("ptr should not be undefined"); + } + while (class_.baseClass) { + ptr = class_.upcast(ptr); + class_ = class_.baseClass; + } + return ptr; + } + function getInheritedInstance(class_, ptr) { + ptr = getBasestPointer(class_, ptr); + return registeredInstances[ptr]; + } + function makeClassHandle(prototype, record) { + if (!record.ptrType || !record.ptr) { + throwInternalError("makeClassHandle requires ptr and ptrType"); + } + var hasSmartPtrType = !!record.smartPtrType; + var hasSmartPtr = !!record.smartPtr; + if (hasSmartPtrType !== hasSmartPtr) { + throwInternalError("Both smartPtrType and smartPtr must be specified"); + } + record.count = { value: 1 }; + return attachFinalizer(Object.create(prototype, { $$: { value: record } })); + } + function RegisteredPointer_fromWireType(ptr) { + var rawPointer = this.getPointee(ptr); + if (!rawPointer) { + this.destructor(ptr); + return null; + } + var registeredInstance = getInheritedInstance(this.registeredClass, rawPointer); + if (registeredInstance !== void 0) { + if (registeredInstance.$$.count.value === 0) { + registeredInstance.$$.ptr = rawPointer; + registeredInstance.$$.smartPtr = ptr; + return registeredInstance["clone"](); + } else { + var rv = registeredInstance["clone"](); + this.destructor(ptr); + return rv; } - getCanvasPosFromEvent$2(e, canvas, states.pointerCanvasPos); - states.mouseover = true; - }); - - canvas.addEventListener("mouseup", this._mouseUpHandler = (e) => { - if (!(configs.active && configs.pointerEnabled)) { - return; + } + function makeDefaultHandle() { + if (this.isSmartPointer) { + return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this.pointeeType, ptr: rawPointer, smartPtrType: this, smartPtr: ptr }); + } else { + return makeClassHandle(this.registeredClass.instancePrototype, { ptrType: this, ptr }); } - }); - } - - reset() { - } - - destroy() { - - const canvas = this._scene.canvas.canvas; - - document.removeEventListener("mousemove", this._mouseMoveHandler); - canvas.removeEventListener("mouseenter", this._mouseEnterHandler); - canvas.removeEventListener("mouseleave", this._mouseLeaveHandler); - canvas.removeEventListener("mousedown", this._mouseDownHandler); - canvas.removeEventListener("mouseup", this._mouseUpHandler); - } -} - -function getCanvasPosFromEvent$2(event, canvas, canvasPos) { - if (!event) { - event = window.event; - canvasPos[0] = event.x; - canvasPos[1] = event.y; - } else { - const { x, y } = canvas.getBoundingClientRect(); - canvasPos[0] = event.clientX - x; - canvasPos[1] = event.clientY - y; - } - return canvasPos; -} - -const getCanvasPosFromEvent$1 = function (event, canvasPos) { - if (!event) { - event = window.event; - canvasPos[0] = event.x; - canvasPos[1] = event.y; - } else { - let element = event.target; - let totalOffsetLeft = 0; - let totalOffsetTop = 0; - while (element.offsetParent) { - totalOffsetLeft += element.offsetLeft; - totalOffsetTop += element.offsetTop; - element = element.offsetParent; + } + var actualType = this.registeredClass.getActualType(rawPointer); + var registeredPointerRecord = registeredPointers[actualType]; + if (!registeredPointerRecord) { + return makeDefaultHandle.call(this); + } + var toType; + if (this.isConst) { + toType = registeredPointerRecord.constPointerType; + } else { + toType = registeredPointerRecord.pointerType; + } + var dp = downcastPointer(rawPointer, this.registeredClass, toType.registeredClass); + if (dp === null) { + return makeDefaultHandle.call(this); + } + if (this.isSmartPointer) { + return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp, smartPtrType: this, smartPtr: ptr }); + } else { + return makeClassHandle(toType.registeredClass.instancePrototype, { ptrType: toType, ptr: dp }); + } } - canvasPos[0] = event.pageX - totalOffsetLeft; - canvasPos[1] = event.pageY - totalOffsetTop; - } - return canvasPos; -}; - -/** - * @private - */ -class TouchPanRotateAndDollyHandler { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - - const pickController = controllers.pickController; - const pivotController = controllers.pivotController; - - const tapStartCanvasPos = math.vec2(); - const tapCanvasPos0 = math.vec2(); - const tapCanvasPos1 = math.vec2(); - const touch0Vec = math.vec2(); - - const lastCanvasTouchPosList = []; - const canvas = this._scene.canvas.canvas; - - let numTouches = 0; - let waitForTick = false; - - this._onTick = scene.on("tick", () => { - waitForTick = false; - }); - - canvas.addEventListener("touchstart", this._canvasTouchStartHandler = (event) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + function init_RegisteredPointer() { + RegisteredPointer.prototype.getPointee = RegisteredPointer_getPointee; + RegisteredPointer.prototype.destructor = RegisteredPointer_destructor; + RegisteredPointer.prototype["argPackAdvance"] = 8; + RegisteredPointer.prototype["readValueFromPointer"] = simpleReadValueFromPointer; + RegisteredPointer.prototype["deleteObject"] = RegisteredPointer_deleteObject; + RegisteredPointer.prototype["fromWireType"] = RegisteredPointer_fromWireType; + } + function RegisteredPointer(name2, registeredClass, isReference, isConst, isSmartPointer, pointeeType, sharingPolicy, rawGetPointee, rawConstructor, rawShare, rawDestructor) { + this.name = name2; + this.registeredClass = registeredClass; + this.isReference = isReference; + this.isConst = isConst; + this.isSmartPointer = isSmartPointer; + this.pointeeType = pointeeType; + this.sharingPolicy = sharingPolicy; + this.rawGetPointee = rawGetPointee; + this.rawConstructor = rawConstructor; + this.rawShare = rawShare; + this.rawDestructor = rawDestructor; + if (!isSmartPointer && registeredClass.baseClass === void 0) { + if (isConst) { + this["toWireType"] = constNoSmartPtrRawPointerToWireType; + this.destructorFunction = null; + } else { + this["toWireType"] = nonConstNoSmartPtrRawPointerToWireType; + this.destructorFunction = null; } - - event.preventDefault(); - - const touches = event.touches; - const changedTouches = event.changedTouches; - - states.touchStartTime = Date.now(); - - if (touches.length === 1 && changedTouches.length === 1) { - - getCanvasPosFromEvent$1(touches[0], tapStartCanvasPos); - - if (configs.followPointer) { - - pickController.pickCursorPos = tapStartCanvasPos; - pickController.schedulePickSurface = true; - pickController.update(); - - if (!configs.planView) { - - if (pickController.picked && pickController.pickedSurface && pickController.pickResult && pickController.pickResult.worldPos) { - - pivotController.setPivotPos(pickController.pickResult.worldPos); - - if (!configs.firstPerson && pivotController.startPivot()) { - pivotController.showPivot(); - } - - } else { - - if (configs.smartPivot) { - pivotController.setCanvasPivotPos(states.pointerCanvasPos); - } else { - pivotController.setPivotPos(scene.camera.look); - } - - if (!configs.firstPerson && pivotController.startPivot()) { - pivotController.showPivot(); - } - } - } - } - + } else { + this["toWireType"] = genericPointerToWireType; + } + } + function replacePublicSymbol(name2, value, numArguments) { + if (!Module.hasOwnProperty(name2)) { + throwInternalError("Replacing nonexistant public symbol"); + } + if (Module[name2].overloadTable !== void 0 && numArguments !== void 0) { + Module[name2].overloadTable[numArguments] = value; + } else { + Module[name2] = value; + Module[name2].argCount = numArguments; + } + } + function dynCallLegacy(sig, ptr, args) { + var f = Module["dynCall_" + sig]; + return args && args.length ? f.apply(null, [ptr].concat(args)) : f.call(null, ptr); + } + function dynCall(sig, ptr, args) { + if (sig.includes("j")) { + return dynCallLegacy(sig, ptr, args); + } + return wasmTable.get(ptr).apply(null, args); + } + function getDynCaller(sig, ptr) { + var argCache = []; + return function() { + argCache.length = arguments.length; + for (var i = 0; i < arguments.length; i++) { + argCache[i] = arguments[i]; } - - while (lastCanvasTouchPosList.length < touches.length) { - lastCanvasTouchPosList.push(math.vec2()); + return dynCall(sig, ptr, argCache); + }; + } + function embind__requireFunction(signature, rawFunction) { + signature = readLatin1String(signature); + function makeDynCaller() { + if (signature.includes("j")) { + return getDynCaller(signature, rawFunction); } - - for (let i = 0, len = touches.length; i < len; ++i) { - getCanvasPosFromEvent$1(touches[i], lastCanvasTouchPosList[i]); + return wasmTable.get(rawFunction); + } + var fp = makeDynCaller(); + if (typeof fp !== "function") { + throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); + } + return fp; + } + var UnboundTypeError = void 0; + function getTypeName(type) { + var ptr = ___getTypeName(type); + var rv = readLatin1String(ptr); + _free(ptr); + return rv; + } + function throwUnboundTypeError(message, types) { + var unboundTypes = []; + var seen = {}; + function visit(type) { + if (seen[type]) { + return; } - - numTouches = touches.length; - }); - - canvas.addEventListener("touchmove", this._canvasTouchMoveHandler = (event) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + if (registeredTypes[type]) { + return; } - - event.stopPropagation(); - event.preventDefault(); - - if (waitForTick) { - // Limit changes detection to one per frame - return; + if (typeDependencies[type]) { + typeDependencies[type].forEach(visit); + return; } - - waitForTick = true; - - // Scaling drag-rotate to canvas boundary - - const canvasBoundary = scene.canvas.boundary; - const canvasWidth = canvasBoundary[2] - canvasBoundary[0]; - const canvasHeight = canvasBoundary[3] - canvasBoundary[1]; - - const touches = event.touches; - - if (event.touches.length !== numTouches) { - // Two fingers were pressed, then one of them is removed - // We don't want to rotate in this case (weird behavior) - return; + unboundTypes.push(type); + seen[type] = true; + } + types.forEach(visit); + throw new UnboundTypeError(message + ": " + unboundTypes.map(getTypeName).join([", "])); + } + function __embind_register_class(rawType, rawPointerType, rawConstPointerType, baseClassRawType, getActualTypeSignature, getActualType, upcastSignature, upcast, downcastSignature, downcast, name2, destructorSignature, rawDestructor) { + name2 = readLatin1String(name2); + getActualType = embind__requireFunction(getActualTypeSignature, getActualType); + if (upcast) { + upcast = embind__requireFunction(upcastSignature, upcast); + } + if (downcast) { + downcast = embind__requireFunction(downcastSignature, downcast); + } + rawDestructor = embind__requireFunction(destructorSignature, rawDestructor); + var legalFunctionName = makeLegalFunctionName(name2); + exposePublicSymbol(legalFunctionName, function() { + throwUnboundTypeError("Cannot construct " + name2 + " due to unbound types", [baseClassRawType]); + }); + whenDependentTypesAreResolved([rawType, rawPointerType, rawConstPointerType], baseClassRawType ? [baseClassRawType] : [], function(base) { + base = base[0]; + var baseClass; + var basePrototype; + if (baseClassRawType) { + baseClass = base.registeredClass; + basePrototype = baseClass.instancePrototype; + } else { + basePrototype = ClassHandle.prototype; } - - if (numTouches === 1) { - - getCanvasPosFromEvent$1(touches[0], tapCanvasPos0); - - //----------------------------------------------------------------------------------------------- - // Drag rotation - //----------------------------------------------------------------------------------------------- - - math.subVec2(tapCanvasPos0, lastCanvasTouchPosList[0], touch0Vec); - - const xPanDelta = touch0Vec[0]; - const yPanDelta = touch0Vec[1]; - - if (states.longTouchTimeout !== null && (Math.abs(xPanDelta) > configs.longTapRadius || Math.abs(yPanDelta) > configs.longTapRadius)) { - clearTimeout(states.longTouchTimeout); - states.longTouchTimeout = null; - } - - if (configs.planView) { // No rotating in plan-view mode - - const camera = scene.camera; - - // We use only canvasHeight here so that aspect ratio does not distort speed - - if (camera.projection === "perspective") { - - const depth = Math.abs(scene.camera.eyeLookDist); - const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0); - - updates.panDeltaX += (xPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; - updates.panDeltaY += (yPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; - - } else { - - updates.panDeltaX += 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight) * configs.touchPanRate; - updates.panDeltaY += 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight) * configs.touchPanRate; - } - - } else { - updates.rotateDeltaY -= (xPanDelta / canvasWidth) * (configs.dragRotationRate * 1.0); // Full horizontal rotation - updates.rotateDeltaX += (yPanDelta / canvasHeight) * (configs.dragRotationRate * 1.5); // Half vertical rotation + var constructor = createNamedFunction(legalFunctionName, function() { + if (Object.getPrototypeOf(this) !== instancePrototype) { + throw new BindingError("Use 'new' to construct " + name2); + } + if (registeredClass.constructor_body === void 0) { + throw new BindingError(name2 + " has no accessible constructor"); + } + var body = registeredClass.constructor_body[arguments.length]; + if (body === void 0) { + throw new BindingError("Tried to invoke ctor of " + name2 + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); + } + return body.apply(this, arguments); + }); + var instancePrototype = Object.create(basePrototype, { constructor: { value: constructor } }); + constructor.prototype = instancePrototype; + var registeredClass = new RegisteredClass(name2, constructor, instancePrototype, rawDestructor, baseClass, getActualType, upcast, downcast); + var referenceConverter = new RegisteredPointer(name2, registeredClass, true, false, false); + var pointerConverter = new RegisteredPointer(name2 + "*", registeredClass, false, false, false); + var constPointerConverter = new RegisteredPointer(name2 + " const*", registeredClass, false, true, false); + registeredPointers[rawType] = { pointerType: pointerConverter, constPointerType: constPointerConverter }; + replacePublicSymbol(legalFunctionName, constructor); + return [referenceConverter, pointerConverter, constPointerConverter]; + }); + } + function heap32VectorToArray(count, firstElement) { + var array = []; + for (var i = 0; i < count; i++) { + array.push(HEAP32[(firstElement >> 2) + i >>> 0]); + } + return array; + } + function __embind_register_class_constructor(rawClassType, argCount, rawArgTypesAddr, invokerSignature, invoker, rawConstructor) { + assert(argCount > 0); + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + invoker = embind__requireFunction(invokerSignature, invoker); + var args = [rawConstructor]; + var destructors = []; + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; + var humanName = "constructor " + classType.name; + if (classType.registeredClass.constructor_body === void 0) { + classType.registeredClass.constructor_body = []; + } + if (classType.registeredClass.constructor_body[argCount - 1] !== void 0) { + throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount - 1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); + } + classType.registeredClass.constructor_body[argCount - 1] = function unboundTypeHandler() { + throwUnboundTypeError("Cannot construct " + classType.name + " due to unbound types", rawArgTypes); + }; + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + classType.registeredClass.constructor_body[argCount - 1] = function constructor_body() { + if (arguments.length !== argCount - 1) { + throwBindingError(humanName + " called with " + arguments.length + " arguments, expected " + (argCount - 1)); } - - } else if (numTouches === 2) { - - const touch0 = touches[0]; - const touch1 = touches[1]; - - getCanvasPosFromEvent$1(touch0, tapCanvasPos0); - getCanvasPosFromEvent$1(touch1, tapCanvasPos1); - - const lastMiddleTouch = math.geometricMeanVec2(lastCanvasTouchPosList[0], lastCanvasTouchPosList[1]); - const currentMiddleTouch = math.geometricMeanVec2(tapCanvasPos0, tapCanvasPos1); - - const touchDelta = math.vec2(); - - math.subVec2(lastMiddleTouch, currentMiddleTouch, touchDelta); - - const xPanDelta = touchDelta[0]; - const yPanDelta = touchDelta[1]; - - const camera = scene.camera; - - // Dollying - - const d1 = math.distVec2([touch0.pageX, touch0.pageY], [touch1.pageX, touch1.pageY]); - const d2 = math.distVec2(lastCanvasTouchPosList[0], lastCanvasTouchPosList[1]); - - const dollyDelta = (d2 - d1) * configs.touchDollyRate; - - updates.dollyDelta = dollyDelta; - - if (Math.abs(dollyDelta) < 1.0) { - - // We use only canvasHeight here so that aspect ratio does not distort speed - - if (camera.projection === "perspective") { - const pickedWorldPos = pickController.pickResult ? pickController.pickResult.worldPos : scene.center; - - const depth = Math.abs(math.lenVec3(math.subVec3(pickedWorldPos, scene.camera.eye, []))); - const targetDistance = depth * Math.tan((camera.perspective.fov / 2) * Math.PI / 180.0); - - updates.panDeltaX -= (xPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; - updates.panDeltaY -= (yPanDelta * targetDistance / canvasHeight) * configs.touchPanRate; - - } else { - - updates.panDeltaX -= 0.5 * camera.ortho.scale * (xPanDelta / canvasHeight) * configs.touchPanRate; - updates.panDeltaY -= 0.5 * camera.ortho.scale * (yPanDelta / canvasHeight) * configs.touchPanRate; - } + destructors.length = 0; + args.length = argCount; + for (var i = 1; i < argCount; ++i) { + args[i] = argTypes[i]["toWireType"](destructors, arguments[i - 1]); } - - - states.pointerCanvasPos = currentMiddleTouch; + var ptr = invoker.apply(null, args); + runDestructors(destructors); + return argTypes[0]["fromWireType"](ptr); + }; + return []; + }); + return []; + }); + } + function new_(constructor, argumentList) { + if (!(constructor instanceof Function)) { + throw new TypeError("new_ called with constructor type " + typeof constructor + " which is not a function"); + } + var dummy = createNamedFunction(constructor.name || "unknownFunctionName", function() { + }); + dummy.prototype = constructor.prototype; + var obj = new dummy(); + var r = constructor.apply(obj, argumentList); + return r instanceof Object ? r : obj; + } + function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc) { + var argCount = argTypes.length; + if (argCount < 2) { + throwBindingError("argTypes array size mismatch! Must at least get return value and 'this' types!"); + } + var isClassMethodFunc = argTypes[1] !== null && classType !== null; + var needsDestructorStack = false; + for (var i = 1; i < argTypes.length; ++i) { + if (argTypes[i] !== null && argTypes[i].destructorFunction === void 0) { + needsDestructorStack = true; + break; } - - for (let i = 0; i < numTouches; ++i) { - getCanvasPosFromEvent$1(touches[i], lastCanvasTouchPosList[i]); + } + var returns = argTypes[0].name !== "void"; + var argsList = ""; + var argsListWired = ""; + for (var i = 0; i < argCount - 2; ++i) { + argsList += (i !== 0 ? ", " : "") + "arg" + i; + argsListWired += (i !== 0 ? ", " : "") + "arg" + i + "Wired"; + } + var invokerFnBody = "return function " + makeLegalFunctionName(humanName) + "(" + argsList + ") {\nif (arguments.length !== " + (argCount - 2) + ") {\nthrowBindingError('function " + humanName + " called with ' + arguments.length + ' arguments, expected " + (argCount - 2) + " args!');\n}\n"; + if (needsDestructorStack) { + invokerFnBody += "var destructors = [];\n"; + } + var dtorStack = needsDestructorStack ? "destructors" : "null"; + var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; + if (isClassMethodFunc) { + invokerFnBody += "var thisWired = classParam.toWireType(" + dtorStack + ", this);\n"; + } + for (var i = 0; i < argCount - 2; ++i) { + invokerFnBody += "var arg" + i + "Wired = argType" + i + ".toWireType(" + dtorStack + ", arg" + i + "); // " + argTypes[i + 2].name + "\n"; + args1.push("argType" + i); + args2.push(argTypes[i + 2]); + } + if (isClassMethodFunc) { + argsListWired = "thisWired" + (argsListWired.length > 0 ? ", " : "") + argsListWired; + } + invokerFnBody += (returns ? "var rv = " : "") + "invoker(fn" + (argsListWired.length > 0 ? ", " : "") + argsListWired + ");\n"; + if (needsDestructorStack) { + invokerFnBody += "runDestructors(destructors);\n"; + } else { + for (var i = isClassMethodFunc ? 1 : 2; i < argTypes.length; ++i) { + var paramName = i === 1 ? "thisWired" : "arg" + (i - 2) + "Wired"; + if (argTypes[i].destructorFunction !== null) { + invokerFnBody += paramName + "_dtor(" + paramName + "); // " + argTypes[i].name + "\n"; + args1.push(paramName + "_dtor"); + args2.push(argTypes[i].destructorFunction); + } } - }); - } - - reset() { - } - - destroy() { - const canvas = this._scene.canvas.canvas; - canvas.removeEventListener("touchstart", this._canvasTouchStartHandler); - canvas.removeEventListener("touchmove", this._canvasTouchMoveHandler); - this._scene.off(this._onTick); - } -} - -const TAP_INTERVAL = 150; -const DBL_TAP_INTERVAL = 325; -const TAP_DISTANCE_THRESHOLD = 4; - -const getCanvasPosFromEvent = function (event, canvasPos) { - if (!event) { - event = window.event; - canvasPos[0] = event.x; - canvasPos[1] = event.y; - } else { - let element = event.target; - let totalOffsetLeft = 0; - let totalOffsetTop = 0; - while (element.offsetParent) { - totalOffsetLeft += element.offsetLeft; - totalOffsetTop += element.offsetTop; - element = element.offsetParent; + } + if (returns) { + invokerFnBody += "var ret = retType.fromWireType(rv);\nreturn ret;\n"; + } + invokerFnBody += "}\n"; + args1.push(invokerFnBody); + var invokerFunction = new_(Function, args1).apply(null, args2); + return invokerFunction; } - canvasPos[0] = event.pageX - totalOffsetLeft; - canvasPos[1] = event.pageY - totalOffsetTop; - } - return canvasPos; -}; - -/** - * @private - */ -class TouchPickHandler { - - constructor(scene, controllers, configs, states, updates) { - - this._scene = scene; - - const pickController = controllers.pickController; - const cameraControl = controllers.cameraControl; - - let touchStartTime; - const activeTouches = []; - const tapStartPos = new Float32Array(2); - let tapStartTime = -1; - let lastTapTime = -1; - - const canvas = this._scene.canvas.canvas; - - const flyCameraTo = (pickResult) => { - let pos; - if (pickResult && pickResult.worldPos) { - pos = pickResult.worldPos; - } - const aabb = pickResult ? pickResult.entity.aabb : scene.aabb; - if (pos) { // Fly to look at point, don't change eye->look dist - const camera = scene.camera; - math.subVec3(camera.eye, camera.look, []); - controllers.cameraFlight.flyTo({ - aabb: aabb - }); - // TODO: Option to back off to fit AABB in view - } else {// Fly to fit target boundary in view - controllers.cameraFlight.flyTo({ - aabb: aabb - }); + function __embind_register_class_function(rawClassType, methodName, argCount, rawArgTypesAddr, invokerSignature, rawInvoker, context, isPureVirtual) { + var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + methodName = readLatin1String(methodName); + rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; + var humanName = classType.name + "." + methodName; + if (methodName.startsWith("@@")) { + methodName = Symbol[methodName.substring(2)]; } - }; - - canvas.addEventListener("touchstart", this._canvasTouchStartHandler = (e) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + if (isPureVirtual) { + classType.registeredClass.pureVirtualFunctions.push(methodName); } - - if (states.longTouchTimeout !== null) { - clearTimeout(states.longTouchTimeout); - states.longTouchTimeout = null; + function unboundTypesHandler() { + throwUnboundTypeError("Cannot call " + humanName + " due to unbound types", rawArgTypes); } - - const touches = e.touches; - const changedTouches = e.changedTouches; - - touchStartTime = Date.now(); - - if (touches.length === 1 && changedTouches.length === 1) { - tapStartTime = touchStartTime; - - getCanvasPosFromEvent(touches[0], tapStartPos); - - const rightClickClientX = tapStartPos[0]; - const rightClickClientY = tapStartPos[1]; - - const rightClickPageX = touches[0].pageX; - const rightClickPageY = touches[0].pageY; - - states.longTouchTimeout = setTimeout(() => { - controllers.cameraControl.fire("rightClick", { // For context menus - pagePos: [Math.round(rightClickPageX), Math.round(rightClickPageY)], - canvasPos: [Math.round(rightClickClientX), Math.round(rightClickClientY)], - event: e - }, true); - - states.longTouchTimeout = null; - }, configs.longTapTimeout); - + var proto = classType.registeredClass.instancePrototype; + var method = proto[methodName]; + if (method === void 0 || method.overloadTable === void 0 && method.className !== classType.name && method.argCount === argCount - 2) { + unboundTypesHandler.argCount = argCount - 2; + unboundTypesHandler.className = classType.name; + proto[methodName] = unboundTypesHandler; } else { - tapStartTime = -1; + ensureOverloadTable(proto, methodName, humanName); + proto[methodName].overloadTable[argCount - 2] = unboundTypesHandler; } - - while (activeTouches.length < touches.length) { - activeTouches.push(new Float32Array(2)); + whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { + var memberFunction = craftInvokerFunction(humanName, argTypes, classType, rawInvoker, context); + if (proto[methodName].overloadTable === void 0) { + memberFunction.argCount = argCount - 2; + proto[methodName] = memberFunction; + } else { + proto[methodName].overloadTable[argCount - 2] = memberFunction; + } + return []; + }); + return []; + }); + } + var emval_free_list = []; + var emval_handle_array = [{}, { value: void 0 }, { value: null }, { value: true }, { value: false }]; + function __emval_decref(handle) { + if (handle > 4 && --emval_handle_array[handle].refcount === 0) { + emval_handle_array[handle] = void 0; + emval_free_list.push(handle); + } + } + function count_emval_handles() { + var count = 0; + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== void 0) { + ++count; } - - for (let i = 0, len = touches.length; i < len; ++i) { - getCanvasPosFromEvent(touches[i], activeTouches[i]); + } + return count; + } + function get_first_emval() { + for (var i = 5; i < emval_handle_array.length; ++i) { + if (emval_handle_array[i] !== void 0) { + return emval_handle_array[i]; } - - activeTouches.length = touches.length; - - }, {passive: true}); - - - canvas.addEventListener("touchend", this._canvasTouchEndHandler = (e) => { - - if (!(configs.active && configs.pointerEnabled)) { - return; + } + return null; + } + function init_emval() { + Module["count_emval_handles"] = count_emval_handles; + Module["get_first_emval"] = get_first_emval; + } + function __emval_register(value) { + switch (value) { + case void 0: { + return 1; } - - const currentTime = Date.now(); - const touches = e.touches; - const changedTouches = e.changedTouches; - - const pickedSurfaceSubs = cameraControl.hasSubs("pickedSurface"); - - if (states.longTouchTimeout !== null) { - clearTimeout(states.longTouchTimeout); - states.longTouchTimeout = null; + case null: { + return 2; } - - // process tap - - if (touches.length === 0 && changedTouches.length === 1) { - - if (tapStartTime > -1 && currentTime - tapStartTime < TAP_INTERVAL) { - - if (lastTapTime > -1 && tapStartTime - lastTapTime < DBL_TAP_INTERVAL) { - - // Double-tap - - getCanvasPosFromEvent(changedTouches[0], pickController.pickCursorPos); - pickController.schedulePickEntity = true; - pickController.schedulePickSurface = pickedSurfaceSubs; - - pickController.update(); - - if (pickController.pickResult) { - - cameraControl.fire("doublePicked", pickController.pickResult); - - if (pickController.pickedSurface) { - cameraControl.fire("doublePickedSurface", pickController.pickResult); - } - - if (configs.doublePickFlyTo) { - flyCameraTo(pickController.pickResult); - } - } else { - cameraControl.fire("doublePickedNothing"); - if (configs.doublePickFlyTo) { - flyCameraTo(); - } - } - - lastTapTime = -1; - - } else if (math.distVec2(activeTouches[0], tapStartPos) < TAP_DISTANCE_THRESHOLD) { - - // Single-tap - - getCanvasPosFromEvent(changedTouches[0], pickController.pickCursorPos); - pickController.schedulePickEntity = true; - pickController.schedulePickSurface = pickedSurfaceSubs; - - pickController.update(); - - if (pickController.pickResult) { - - cameraControl.fire("picked", pickController.pickResult); - - if (pickController.pickedSurface) { - cameraControl.fire("pickedSurface", pickController.pickResult); - } - - } else { - cameraControl.fire("pickedNothing"); - } - - lastTapTime = currentTime; - } - - tapStartTime = -1; + case true: { + return 3; + } + case false: { + return 4; + } + default: { + var handle = emval_free_list.length ? emval_free_list.pop() : emval_handle_array.length; + emval_handle_array[handle] = { refcount: 1, value }; + return handle; + } + } + } + function __embind_register_emval(rawType, name2) { + name2 = readLatin1String(name2); + registerType(rawType, { name: name2, "fromWireType": function(handle) { + var rv = emval_handle_array[handle].value; + __emval_decref(handle); + return rv; + }, "toWireType": function(destructors, value) { + return __emval_register(value); + }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: null }); + } + function enumReadValueFromPointer(name2, shift, signed) { + switch (shift) { + case 0: + return function(pointer) { + var heap = signed ? HEAP8 : HEAPU8; + return this["fromWireType"](heap[pointer >>> 0]); + }; + case 1: + return function(pointer) { + var heap = signed ? HEAP16 : HEAPU16; + return this["fromWireType"](heap[pointer >>> 1]); + }; + case 2: + return function(pointer) { + var heap = signed ? HEAP32 : HEAPU32; + return this["fromWireType"](heap[pointer >>> 2]); + }; + default: + throw new TypeError("Unknown integer type: " + name2); + } + } + function __embind_register_enum(rawType, name2, size, isSigned) { + var shift = getShiftFromSize(size); + name2 = readLatin1String(name2); + function ctor() { + } + ctor.values = {}; + registerType(rawType, { name: name2, constructor: ctor, "fromWireType": function(c) { + return this.constructor.values[c]; + }, "toWireType": function(destructors, c) { + return c.value; + }, "argPackAdvance": 8, "readValueFromPointer": enumReadValueFromPointer(name2, shift, isSigned), destructorFunction: null }); + exposePublicSymbol(name2, ctor); + } + function requireRegisteredType(rawType, humanName) { + var impl = registeredTypes[rawType]; + if (impl === void 0) { + throwBindingError(humanName + " has unknown type " + getTypeName(rawType)); + } + return impl; + } + function __embind_register_enum_value(rawEnumType, name2, enumValue) { + var enumType = requireRegisteredType(rawEnumType, "enum"); + name2 = readLatin1String(name2); + var Enum = enumType.constructor; + var Value2 = Object.create(enumType.constructor.prototype, { value: { value: enumValue }, constructor: { value: createNamedFunction(enumType.name + "_" + name2, function() { + }) } }); + Enum.values[enumValue] = Value2; + Enum[name2] = Value2; + } + function _embind_repr(v) { + if (v === null) { + return "null"; + } + var t = typeof v; + if (t === "object" || t === "array" || t === "function") { + return v.toString(); + } else { + return "" + v; + } + } + function floatReadValueFromPointer(name2, shift) { + switch (shift) { + case 2: + return function(pointer) { + return this["fromWireType"](HEAPF32[pointer >>> 2]); + }; + case 3: + return function(pointer) { + return this["fromWireType"](HEAPF64[pointer >>> 3]); + }; + default: + throw new TypeError("Unknown float type: " + name2); + } + } + function __embind_register_float(rawType, name2, size) { + var shift = getShiftFromSize(size); + name2 = readLatin1String(name2); + registerType(rawType, { name: name2, "fromWireType": function(value) { + return value; + }, "toWireType": function(destructors, value) { + if (typeof value !== "number" && typeof value !== "boolean") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); + } + return value; + }, "argPackAdvance": 8, "readValueFromPointer": floatReadValueFromPointer(name2, shift), destructorFunction: null }); + } + function __embind_register_function(name2, argCount, rawArgTypesAddr, signature, rawInvoker, fn) { + var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + name2 = readLatin1String(name2); + rawInvoker = embind__requireFunction(signature, rawInvoker); + exposePublicSymbol(name2, function() { + throwUnboundTypeError("Cannot call " + name2 + " due to unbound types", argTypes); + }, argCount - 1); + whenDependentTypesAreResolved([], argTypes, function(argTypes2) { + var invokerArgsArray = [argTypes2[0], null].concat(argTypes2.slice(1)); + replacePublicSymbol(name2, craftInvokerFunction(name2, invokerArgsArray, null, rawInvoker, fn), argCount - 1); + return []; + }); + } + function integerReadValueFromPointer(name2, shift, signed) { + switch (shift) { + case 0: + return signed ? function readS8FromPointer(pointer) { + return HEAP8[pointer >>> 0]; + } : function readU8FromPointer(pointer) { + return HEAPU8[pointer >>> 0]; + }; + case 1: + return signed ? function readS16FromPointer(pointer) { + return HEAP16[pointer >>> 1]; + } : function readU16FromPointer(pointer) { + return HEAPU16[pointer >>> 1]; + }; + case 2: + return signed ? function readS32FromPointer(pointer) { + return HEAP32[pointer >>> 2]; + } : function readU32FromPointer(pointer) { + return HEAPU32[pointer >>> 2]; + }; + default: + throw new TypeError("Unknown integer type: " + name2); + } + } + function __embind_register_integer(primitiveType, name2, size, minRange, maxRange) { + name2 = readLatin1String(name2); + if (maxRange === -1) { + maxRange = 4294967295; + } + var shift = getShiftFromSize(size); + var fromWireType = function(value) { + return value; + }; + if (minRange === 0) { + var bitshift = 32 - 8 * size; + fromWireType = function(value) { + return value << bitshift >>> bitshift; + }; + } + var isUnsignedType = name2.includes("unsigned"); + registerType(primitiveType, { name: name2, "fromWireType": fromWireType, "toWireType": function(destructors, value) { + if (typeof value !== "number" && typeof value !== "boolean") { + throw new TypeError('Cannot convert "' + _embind_repr(value) + '" to ' + this.name); + } + if (value < minRange || value > maxRange) { + throw new TypeError('Passing a number "' + _embind_repr(value) + '" from JS side to C/C++ side to an argument of type "' + name2 + '", which is outside the valid range [' + minRange + ", " + maxRange + "]!"); + } + return isUnsignedType ? value >>> 0 : value | 0; + }, "argPackAdvance": 8, "readValueFromPointer": integerReadValueFromPointer(name2, shift, minRange !== 0), destructorFunction: null }); + } + function __embind_register_memory_view(rawType, dataTypeIndex, name2) { + var typeMapping = [Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array]; + var TA = typeMapping[dataTypeIndex]; + function decodeMemoryView(handle) { + handle = handle >> 2; + var heap = HEAPU32; + var size = heap[handle >>> 0]; + var data = heap[handle + 1 >>> 0]; + return new TA(buffer, data, size); + } + name2 = readLatin1String(name2); + registerType(rawType, { name: name2, "fromWireType": decodeMemoryView, "argPackAdvance": 8, "readValueFromPointer": decodeMemoryView }, { ignoreDuplicateRegistrations: true }); + } + function __embind_register_std_string(rawType, name2) { + name2 = readLatin1String(name2); + var stdStringIsUTF8 = name2 === "std::string"; + registerType(rawType, { name: name2, "fromWireType": function(value) { + var length = HEAPU32[value >>> 2]; + var str; + if (stdStringIsUTF8) { + var decodeStartPtr = value + 4; + for (var i = 0; i <= length; ++i) { + var currentBytePtr = value + 4 + i; + if (i == length || HEAPU8[currentBytePtr >>> 0] == 0) { + var maxRead = currentBytePtr - decodeStartPtr; + var stringSegment = UTF8ToString(decodeStartPtr, maxRead); + if (str === void 0) { + str = stringSegment; + } else { + str += String.fromCharCode(0); + str += stringSegment; + } + decodeStartPtr = currentBytePtr + 1; + } + } + } else { + var a = new Array(length); + for (var i = 0; i < length; ++i) { + a[i] = String.fromCharCode(HEAPU8[value + 4 + i >>> 0]); + } + str = a.join(""); + } + _free(value); + return str; + }, "toWireType": function(destructors, value) { + if (value instanceof ArrayBuffer) { + value = new Uint8Array(value); + } + var getLength; + var valueIsOfTypeString = typeof value === "string"; + if (!(valueIsOfTypeString || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int8Array)) { + throwBindingError("Cannot pass non-string to std::string"); + } + if (stdStringIsUTF8 && valueIsOfTypeString) { + getLength = function() { + return lengthBytesUTF8(value); + }; + } else { + getLength = function() { + return value.length; + }; + } + var length = getLength(); + var ptr = _malloc(4 + length + 1); + ptr >>>= 0; + HEAPU32[ptr >>> 2] = length; + if (stdStringIsUTF8 && valueIsOfTypeString) { + stringToUTF8(value, ptr + 4, length + 1); + } else { + if (valueIsOfTypeString) { + for (var i = 0; i < length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode > 255) { + _free(ptr); + throwBindingError("String has UTF-16 code units that do not fit in 8 bits"); + } + HEAPU8[ptr + 4 + i >>> 0] = charCode; + } + } else { + for (var i = 0; i < length; ++i) { + HEAPU8[ptr + 4 + i >>> 0] = value[i]; } + } } - - activeTouches.length = touches.length; - - for (let i = 0, len = touches.length; i < len; ++i) { - activeTouches[i][0] = touches[i].pageX; - activeTouches[i][1] = touches[i].pageY; + if (destructors !== null) { + destructors.push(_free, ptr); } - - e.stopPropagation(); - - }, {passive: true}); - - } - - reset() { - // TODO - // tapStartTime = -1; - // lastTapTime = -1; - - } - - destroy() { - const canvas = this._scene.canvas.canvas; - canvas.removeEventListener("touchstart", this._canvasTouchStartHandler); - canvas.removeEventListener("touchend", this._canvasTouchEndHandler); - } -} - -/** - * @desc Controls the {@link Camera} with user input, and fires events when the user interacts with pickable {@link Entity}s. - * - * # Contents - * - * * [Overview](#overview) - * * [Examples](#examples) - * * [Orbit Mode](#orbit-mode) - * + [Following the Pointer in Orbit Mode](#--following-the-pointer-in-orbit-mode--) - * + [Showing the Pivot Position](#--showing-the-pivot-position--) - * + [Axis-Aligned Views in Orbit Mode](#--axis-aligned-views-in-orbit-mode--) - * + [View-Fitting Entitys in Orbit Mode](#--view-fitting-entitys-in-orbit-mode--) - * * [First-Person Mode](#first-person-mode) - * + [Following the Pointer in First-Person Mode](#--following-the-pointer-in-first-person-mode--) - * + [Constraining Vertical Position in First-Person Mode](#--constraining-vertical-position-in-first-person-mode--) - * + [Axis-Aligned Views in First-Person Mode](#--axis-aligned-views-in-first-person-mode--) - * + [View-Fitting Entitys in First-Person Mode](#--view-fitting-entitys-in-first-person-mode--) - * * [Plan-View Mode](#plan-view-mode) - * + [Following the Pointer in Plan-View Mode](#--following-the-pointer-in-plan-view-mode--) - * + [Axis-Aligned Views in Plan-View Mode](#--axis-aligned-views-in-plan-view-mode--) - * * [CameraControl Events](#cameracontrol-events) - * + ["hover"](#---hover---) - * + ["hoverOff"](#---hoveroff---) - * + ["hoverEnter"](#---hoverenter---) - * + ["hoverOut"](#---hoverout---) - * + ["picked"](#---picked---) - * + ["pickedSurface"](#---pickedsurface---) - * + ["pickedNothing"](#---pickednothing---) - * + ["doublePicked"](#---doublepicked---) - * + ["doublePickedSurface"](#---doublepickedsurface---) - * + ["doublePickedNothing"](#---doublepickednothing---) - * + ["rightClick"](#---rightclick---) - * * [Custom Keyboard Mappings](#custom-keyboard-mappings) - * - *

    - * - * # Overview - * - * * Each {@link Viewer} has a ````CameraControl````, located at {@link Viewer#cameraControl}. - * * {@link CameraControl#navMode} selects the navigation mode: - * * ````"orbit"```` rotates the {@link Camera} position about the target. - * * ````"firstPerson"```` rotates the World about the Camera position. - * * ````"planView"```` never rotates, but still allows to pan and dolly, typically for an axis-aligned view. - * * {@link CameraControl#followPointer} makes the Camera follow the mouse or touch pointer. - * * {@link CameraControl#constrainVertical} locks the Camera to its current height when in first-person mode. - * * ````CameraControl```` fires pick events when we hover, click or tap on an {@link Entity}. - *

    - * - * # Examples - * - * * [Orbit Navigation - Duplex Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_orbit_Duplex) - * * [Orbit Navigation - Holter Tower Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_orbit_HolterTower) - * * [First-Person Navigation - Duplex Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_firstPerson_Duplex) - * * [First-Person Navigation - Holter Tower Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_firstPerson_HolterTower) - * * [Plan-view Navigation - Schependomlaan Model](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_planView_Schependomlaan) - * * [Custom Keyboard Mapping](https://xeokit.github.io/xeokit-sdk/examples/#CameraControl_keyMap) - *

    - * - * # Orbit Mode - * - * In orbit mode, ````CameraControl```` orbits the {@link Camera} about the target. - * - * To enable orbit mode: - * - * ````javascript - * const cameraControl = myViewer.cameraControl; - * cameraControl.navMode = "orbit"; - * ```` - * - * Then orbit by: - * - * * left-dragging the mouse, - * * tap-dragging the touch pad, and - * * pressing arrow keys, or ````Q```` and ````E```` on a QWERTY keyboard, or ````A```` and ````E```` on an AZERTY keyboard. - *

    - * - * Dolly forwards and backwards by: - * - * * spinning the mouse wheel, - * * pinching on the touch pad, and - * * pressing the ````+```` and ````-```` keys, or ````W```` and ````S```` on a QWERTY keyboard, or ````Z```` and ````S```` for AZERTY. - *

    - * - * Pan horizontally and vertically by: - * - * * right-dragging the mouse, - * * left-dragging the mouse with the SHIFT key down, - * * tap-dragging the touch pad with SHIFT down, - * * pressing the ````A````, ````D````, ````Z```` and ````X```` keys on a QWERTY keyboard, and - * * pressing the ````Q````, ````D````, ````W```` and ````X```` keys on an AZERTY keyboard, - *

    - * - * ## Following the Pointer in Orbit Mode - * - * When {@link CameraControl#followPointer} is ````true````in orbiting mode, the mouse or touch pointer will dynamically - * indicate the target that the {@link Camera} will orbit, as well as dolly to and from. - * - * Lets ensure that we're in orbit mode, then enable the {@link Camera} to follow the pointer: - * - * ````javascript - * cameraControl.navMode = "orbit"; - * cameraControl.followPointer = true; - * ```` - * - * ## Smart Pivoting - * - * TODO - * - * ## Showing the Pivot Position - * - * We can configure {@link CameraControl#pivotElement} with an HTML element to indicate the current - * pivot position. The indicator will appear momentarily each time we move the {@link Camera} while in orbit mode with - * {@link CameraControl#followPointer} set ````true````. - * - * First we'll define some CSS to style our pivot indicator as a black dot with a white border: - * - * ````css - * .camera-pivot-marker { - * color: #ffffff; - * position: absolute; - * width: 25px; - * height: 25px; - * border-radius: 15px; - * border: 2px solid #ebebeb; - * background: black; - * visibility: hidden; - * box-shadow: 5px 5px 15px 1px #000000; - * z-index: 10000; - * pointer-events: none; - * } - * ```` - * - * Then we'll attach our pivot indicator's HTML element to the ````CameraControl````: - * - * ````javascript - * const pivotElement = document.createRange().createContextualFragment("
    ").firstChild; - * - * document.body.appendChild(pivotElement); - * - * cameraControl.pivotElement = pivotElement; - * ```` - * - * ## Axis-Aligned Views in Orbit Mode - * - * In orbit mode, we can use keys 1-6 to position the {@link Camera} to look at the center of the {@link Scene} from along each of the - * six World-space axis. Pressing one of these keys will fly the {@link Camera} to the corresponding axis-aligned view. - * - * ## View-Fitting Entitys in Orbit Mode - * - * When {@link CameraControl#doublePickFlyTo} is ````true````, we can left-double-click or - * double-tap (ie. "double-pick") an {@link Entity} to fit it to view. This will cause the {@link Camera} - * to fly to that Entity. Our target then becomes the center of that Entity. If we are currently pivoting, - * then our pivot position is then also set to the Entity center. - * - * Disable that behaviour by setting {@link CameraControl#doublePickFlyTo} ````false````. - * - * # First-Person Mode - * - * In first-person mode, ````CameraControl```` rotates the World about the {@link Camera} position. - * - * To enable first-person mode: - * - * ````javascript - * cameraControl.navMode = "firstPerson"; - * ```` - * - * Then rotate by: - * - * * left-dragging the mouse, - * * tap-dragging the touch pad, - * * pressing arrow keys, or ````Q```` and ````E```` on a QWERTY keyboard, or ````A```` and ````E```` on an AZERTY keyboard. - *

    - * - * Dolly forwards and backwards by: - * - * * spinning the mouse wheel, - * * pinching on the touch pad, and - * * pressing the ````+```` and ````-```` keys, or ````W```` and ````S```` on a QWERTY keyboard, or ````Z```` and ````S```` for AZERTY. - *

    - * - * Pan left, right, up and down by: - * - * * left-dragging or right-dragging the mouse, and - * * tap-dragging the touch pad with SHIFT down. - * - * Pan forwards, backwards, left, right, up and down by pressing the ````WSADZX```` keys on a QWERTY keyboard, - * or ````WSQDWX```` keys on an AZERTY keyboard. - *

    - * - * ## Following the Pointer in First-Person Mode - * - * When {@link CameraControl#followPointer} is ````true```` in first-person mode, the mouse or touch pointer will dynamically - * indicate the target to which the {@link Camera} will dolly to and from. In first-person mode, however, the World will always rotate - * about the {@link Camera} position. - * - * Lets ensure that we're in first-person mode, then enable the {@link Camera} to follow the pointer: - * - * ````javascript - * cameraControl.navMode = "firstPerson"; - * cameraControl.followPointer = true; - * ```` - * - * When the pointer is over empty space, the target will remain the last object that the pointer was over. - * - * ## Constraining Vertical Position in First-Person Mode - * - * In first-person mode, we can lock the {@link Camera} to its current position on the vertical World axis, which is useful for walk-through navigation: - * - * ````javascript - * cameraControl.constrainVertical = true; - * ```` - * - * ## Axis-Aligned Views in First-Person Mode - * - * In first-person mode we can use keys 1-6 to position the {@link Camera} to look at the center of - * the {@link Scene} from along each of the six World-space axis. Pressing one of these keys will fly the {@link Camera} to the - * corresponding axis-aligned view. - * - * ## View-Fitting Entitys in First-Person Mode - * - * As in orbit mode, when in first-person mode and {@link CameraControl#doublePickFlyTo} is ````true````, we can double-click - * or double-tap an {@link Entity} (ie. "double-picking") to fit it in view. This will cause the {@link Camera} to fly to - * that Entity. Our target then becomes the center of that Entity. - * - * Disable that behaviour by setting {@link CameraControl#doublePickFlyTo} ````false````. - * - * # Plan-View Mode - * - * In plan-view mode, ````CameraControl```` pans and rotates the {@link Camera}, without rotating it. - * - * To enable plan-view mode: - * - * ````javascript - * cameraControl.navMode = "planView"; - * ```` - * - * Dolly forwards and backwards by: - * - * * spinning the mouse wheel, - * * pinching on the touch pad, and - * * pressing the ````+```` and ````-```` keys. - * - *
    - * Pan left, right, up and down by: - * - * * left-dragging or right-dragging the mouse, and - * * tap-dragging the touch pad with SHIFT down. - * - * Pan forwards, backwards, left, right, up and down by pressing the ````WSADZX```` keys on a QWERTY keyboard, - * or ````WSQDWX```` keys on an AZERTY keyboard. - *

    - * - * ## Following the Pointer in Plan-View Mode - * - * When {@link CameraControl#followPointer} is ````true```` in plan-view mode, the mouse or touch pointer will dynamically - * indicate the target to which the {@link Camera} will dolly to and from. In plan-view mode, however, the {@link Camera} cannot rotate. - * - * Lets ensure that we're in plan-view mode, then enable the {@link Camera} to follow the pointer: - * - * ````javascript - * cameraControl.navMode = "planView"; - * cameraControl.followPointer = true; // Default - * ```` - * - * When the pointer is over empty space, the target will remain the last object that the pointer was over. - * - * ## Axis-Aligned Views in Plan-View Mode - * - * As in orbit and first-person modes, in plan-view mode we can use keys 1-6 to position the {@link Camera} to look at the center of - * the {@link Scene} from along each of the six World-space axis. Pressing one of these keys will fly the {@link Camera} to the - * corresponding axis-aligned view. - * - * # CameraControl Events - * - * ````CameraControl```` fires events as we interact with {@link Entity}s using mouse or touch input. - * - * The following examples demonstrate how to subscribe to those events. - * - * The first example shows how to save a handle to a subscription, which we can later use to unsubscribe. - * - * ## "hover" - * - * Event fired when the pointer moves while hovering over an Entity. - * - * ````javascript - * const onHover = cameraControl.on("hover", (e) => { - * const entity = e.entity; // Entity - * const canvasPos = e.canvasPos; // 2D canvas position - * }); - * ```` - * - * To unsubscribe from the event: - * - * ````javascript - * cameraControl.off(onHover); - * ```` - * - * ## "hoverOff" - * - * Event fired when the pointer moves while hovering over empty space. - * - * ````javascript - * cameraControl.on("hoverOff", (e) => { - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "hoverEnter" - * - * Event fired when the pointer moves onto an Entity. - * - * ````javascript - * cameraControl.on("hoverEnter", (e) => { - * const entity = e.entity; - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "hoverOut" - * - * Event fired when the pointer moves off an Entity. - * - * ````javascript - * cameraControl.on("hoverOut", (e) => { - * const entity = e.entity; - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "picked" - * - * Event fired when we left-click or tap on an Entity. - * - * ````javascript - * cameraControl.on("picked", (e) => { - * const entity = e.entity; - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "pickedSurface" - * - * Event fired when we left-click or tap on the surface of an Entity. - * - * ````javascript - * cameraControl.on("picked", (e) => { - * const entity = e.entity; - * const canvasPos = e.canvasPos; - * const worldPos = e.worldPos; // 3D World-space position - * const viewPos = e.viewPos; // 3D View-space position - * const worldNormal = e.worldNormal; // 3D World-space normal vector - * }); - * ```` - * - * ## "pickedNothing" - * - * Event fired when we left-click or tap on empty space. - * - * ````javascript - * cameraControl.on("pickedNothing", (e) => { - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "doublePicked" - * - * Event fired wwhen we left-double-click or double-tap on an Entity. - * - * ````javascript - * cameraControl.on("doublePicked", (e) => { - * const entity = e.entity; - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "doublePickedSurface" - * - * Event fired when we left-double-click or double-tap on the surface of an Entity. - * - * ````javascript - * cameraControl.on("doublePickedSurface", (e) => { - * const entity = e.entity; - * const canvasPos = e.canvasPos; - * const worldPos = e.worldPos; - * const viewPos = e.viewPos; - * const worldNormal = e.worldNormal; - * }); - * ```` - * - * ## "doublePickedNothing" - * - * Event fired when we left-double-click or double-tap on empty space. - * - * ````javascript - * cameraControl.on("doublePickedNothing", (e) => { - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## "rightClick" - * - * Event fired when we right-click on the canvas. - * - * ````javascript - * cameraControl.on("rightClick", (e) => { - * const event = e.event; // Mouse event - * const canvasPos = e.canvasPos; - * }); - * ```` - * - * ## Custom Keyboard Mappings - * - * We can customize````CameraControl```` key bindings as shown below. - * - * In this example, we'll just set the default bindings for a QWERTY keyboard. - * - * ````javascript - * const input = myViewer.scene.input; - * - * cameraControl.navMode = "orbit"; - * cameraControl.followPointer = true; - * - * const keyMap = {}; - * - * keyMap[cameraControl.PAN_LEFT] = [input.KEY_A]; - * keyMap[cameraControl.PAN_RIGHT] = [input.KEY_D]; - * keyMap[cameraControl.PAN_UP] = [input.KEY_Z]; - * keyMap[cameraControl.PAN_DOWN] = [input.KEY_X]; - * keyMap[cameraControl.DOLLY_FORWARDS] = [input.KEY_W, input.KEY_ADD]; - * keyMap[cameraControl.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT]; - * keyMap[cameraControl.ROTATE_X_POS] = [input.KEY_DOWN_ARROW]; - * keyMap[cameraControl.ROTATE_X_NEG] = [input.KEY_UP_ARROW]; - * keyMap[cameraControl.ROTATE_Y_POS] = [input.KEY_LEFT_ARROW]; - * keyMap[cameraControl.ROTATE_Y_NEG] = [input.KEY_RIGHT_ARROW]; - * keyMap[cameraControl.AXIS_VIEW_RIGHT] = [input.KEY_NUM_1]; - * keyMap[cameraControl.AXIS_VIEW_BACK] = [input.KEY_NUM_2]; - * keyMap[cameraControl.AXIS_VIEW_LEFT] = [input.KEY_NUM_3]; - * keyMap[cameraControl.AXIS_VIEW_FRONT] = [input.KEY_NUM_4]; - * keyMap[cameraControl.AXIS_VIEW_TOP] = [input.KEY_NUM_5]; - * keyMap[cameraControl.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6]; - * - * cameraControl.keyMap = keyMap; - * ```` - * - * We can also just configure default bindings for a specified keyboard layout, like this: - * - * ````javascript - * cameraControl.keyMap = "qwerty"; - * ```` - * - * Then, ````CameraControl```` will internally set {@link CameraControl#keyMap} to the default key map for the QWERTY - * layout (which is the same set of mappings we set in the previous example). In other words, if we subsequently - * read {@link CameraControl#keyMap}, it will now be a key map, instead of the "qwerty" string value we set it to. - * - * Supported layouts are, so far: - * - * * ````"qwerty"```` - * * ````"azerty"```` - */ -class CameraControl extends Component { - - /** - * @private - * @constructor - */ - constructor(owner, cfg = {}) { - - super(owner, cfg); - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.PAN_LEFT = 0; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.PAN_RIGHT = 1; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.PAN_UP = 2; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.PAN_DOWN = 3; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.PAN_FORWARDS = 4; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.PAN_BACKWARDS = 5; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.ROTATE_X_POS = 6; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.ROTATE_X_NEG = 7; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.ROTATE_Y_POS = 8; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.ROTATE_Y_NEG = 9; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.DOLLY_FORWARDS = 10; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.DOLLY_BACKWARDS = 11; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.AXIS_VIEW_RIGHT = 12; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.AXIS_VIEW_BACK = 13; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.AXIS_VIEW_LEFT = 14; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.AXIS_VIEW_FRONT = 15; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.AXIS_VIEW_TOP = 16; - - /** - * Identifies the XX action. - * @final - * @type {Number} - */ - this.AXIS_VIEW_BOTTOM = 17; - - this._keyMap = {}; // Maps key codes to the above actions - - this.scene.canvas.canvas.oncontextmenu = (e) => { - e.preventDefault(); - }; - - // User-settable CameraControl configurations - - this._configs = { - - // Private - - longTapTimeout: 600, // Millisecs - longTapRadius: 5, // Pixels - - // General - - active: true, - keyboardLayout: "qwerty", - navMode: "orbit", - planView: false, - firstPerson: false, - followPointer: true, - doublePickFlyTo: true, - panRightClick: true, - showPivot: false, - pointerEnabled: true, - constrainVertical: false, - smartPivot: false, - doubleClickTimeFrame: 250, - - // Rotation - - dragRotationRate: 360.0, - keyboardRotationRate: 90.0, - rotationInertia: 0.0, - - // Panning - - keyboardPanRate: 1.0, - touchPanRate: 1.0, - panInertia: 0.5, - - // Dollying - - keyboardDollyRate: 10, - mouseWheelDollyRate: 100, - touchDollyRate: 0.2, - dollyInertia: 0, - dollyProximityThreshold: 30.0, - dollyMinSpeed: 0.04 - }; - - // Current runtime state of the CameraControl - - this._states = { - pointerCanvasPos: math.vec2(), - mouseover: false, - followPointerDirty: true, - mouseDownClientX: 0, - mouseDownClientY: 0, - mouseDownCursorX: 0, - mouseDownCursorY: 0, - touchStartTime: null, - activeTouches: [], - tapStartPos: math.vec2(), - tapStartTime: -1, - lastTapTime: -1, - longTouchTimeout: null - }; - - // Updates for CameraUpdater to process on next Scene "tick" event - - this._updates = { - rotateDeltaX: 0, - rotateDeltaY: 0, - panDeltaX: 0, - panDeltaY: 0, - panDeltaZ: 0, - dollyDelta: 0 - }; - - // Controllers to assist input event handlers with controlling the Camera - - const scene = this.scene; - - this._controllers = { - cameraControl: this, - pickController: new PickController(this, this._configs), - pivotController: new PivotController(scene, this._configs), - panController: new PanController(scene), - cameraFlight: new CameraFlightAnimation(this, { - duration: 0.5 - }) - }; - - // Input event handlers - - this._handlers = [ - new MouseMiscHandler(this.scene, this._controllers, this._configs, this._states, this._updates), - new TouchPanRotateAndDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates), - new MousePanRotateDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates), - new KeyboardAxisViewHandler(this.scene, this._controllers, this._configs, this._states, this._updates), - new MousePickHandler(this.scene, this._controllers, this._configs, this._states, this._updates), - new TouchPickHandler(this.scene, this._controllers, this._configs, this._states, this._updates), - new KeyboardPanRotateDollyHandler(this.scene, this._controllers, this._configs, this._states, this._updates) - ]; - - // Applies scheduled updates to the Camera on each Scene "tick" event - - this._cameraUpdater = new CameraUpdater(this.scene, this._controllers, this._configs, this._states, this._updates); - - // Set initial user configurations - - this.navMode = cfg.navMode; - if (cfg.planView) { - this.planView = cfg.planView; - } - this.constrainVertical = cfg.constrainVertical; - if (cfg.keyboardLayout) { - this.keyboardLayout = cfg.keyboardLayout; // Deprecated - } else { - this.keyMap = cfg.keyMap; + return ptr; + }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: function(ptr) { + _free(ptr); + } }); } - this.doublePickFlyTo = cfg.doublePickFlyTo; - this.panRightClick = cfg.panRightClick; - this.active = cfg.active; - this.followPointer = cfg.followPointer; - this.rotationInertia = cfg.rotationInertia; - this.keyboardPanRate = cfg.keyboardPanRate; - this.touchPanRate = cfg.touchPanRate; - this.keyboardRotationRate = cfg.keyboardRotationRate; - this.dragRotationRate = cfg.dragRotationRate; - this.touchDollyRate = cfg.touchDollyRate; - this.dollyInertia = cfg.dollyInertia; - this.dollyProximityThreshold = cfg.dollyProximityThreshold; - this.dollyMinSpeed = cfg.dollyMinSpeed; - this.panInertia = cfg.panInertia; - this.pointerEnabled = true; - this.keyboardDollyRate = cfg.keyboardDollyRate; - this.mouseWheelDollyRate = cfg.mouseWheelDollyRate; - } - - /** - * Sets custom mappings of keys to ````CameraControl```` actions. - * - * See class docs for usage. - * - * @param {{Number:Number}|String} value Either a set of new key mappings, or a string to select a keyboard layout, - * which causes ````CameraControl```` to use the default key mappings for that layout. - */ - set keyMap(value) { - value = value || "qwerty"; - if (utils.isString(value)) { - const input = this.scene.input; - const keyMap = {}; - - switch (value) { - - default: - this.error("Unsupported value for 'keyMap': " + value + " defaulting to 'qwerty'"); - // Intentional fall-through to "qwerty" - case "qwerty": - keyMap[this.PAN_LEFT] = [input.KEY_A]; - keyMap[this.PAN_RIGHT] = [input.KEY_D]; - keyMap[this.PAN_UP] = [input.KEY_Z]; - keyMap[this.PAN_DOWN] = [input.KEY_X]; - keyMap[this.PAN_BACKWARDS] = []; - keyMap[this.PAN_FORWARDS] = []; - keyMap[this.DOLLY_FORWARDS] = [input.KEY_W, input.KEY_ADD]; - keyMap[this.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT]; - keyMap[this.ROTATE_X_POS] = [input.KEY_DOWN_ARROW]; - keyMap[this.ROTATE_X_NEG] = [input.KEY_UP_ARROW]; - keyMap[this.ROTATE_Y_POS] = [input.KEY_Q, input.KEY_LEFT_ARROW]; - keyMap[this.ROTATE_Y_NEG] = [input.KEY_E, input.KEY_RIGHT_ARROW]; - keyMap[this.AXIS_VIEW_RIGHT] = [input.KEY_NUM_1]; - keyMap[this.AXIS_VIEW_BACK] = [input.KEY_NUM_2]; - keyMap[this.AXIS_VIEW_LEFT] = [input.KEY_NUM_3]; - keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4]; - keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5]; - keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6]; - break; - - case "azerty": - keyMap[this.PAN_LEFT] = [input.KEY_Q]; - keyMap[this.PAN_RIGHT] = [input.KEY_D]; - keyMap[this.PAN_UP] = [input.KEY_W]; - keyMap[this.PAN_DOWN] = [input.KEY_X]; - keyMap[this.PAN_BACKWARDS] = []; - keyMap[this.PAN_FORWARDS] = []; - keyMap[this.DOLLY_FORWARDS] = [input.KEY_Z, input.KEY_ADD]; - keyMap[this.DOLLY_BACKWARDS] = [input.KEY_S, input.KEY_SUBTRACT]; - keyMap[this.ROTATE_X_POS] = [input.KEY_DOWN_ARROW]; - keyMap[this.ROTATE_X_NEG] = [input.KEY_UP_ARROW]; - keyMap[this.ROTATE_Y_POS] = [input.KEY_A, input.KEY_LEFT_ARROW]; - keyMap[this.ROTATE_Y_NEG] = [input.KEY_E, input.KEY_RIGHT_ARROW]; - keyMap[this.AXIS_VIEW_RIGHT] = [input.KEY_NUM_1]; - keyMap[this.AXIS_VIEW_BACK] = [input.KEY_NUM_2]; - keyMap[this.AXIS_VIEW_LEFT] = [input.KEY_NUM_3]; - keyMap[this.AXIS_VIEW_FRONT] = [input.KEY_NUM_4]; - keyMap[this.AXIS_VIEW_TOP] = [input.KEY_NUM_5]; - keyMap[this.AXIS_VIEW_BOTTOM] = [input.KEY_NUM_6]; - break; + function __embind_register_std_wstring(rawType, charSize, name2) { + name2 = readLatin1String(name2); + var decodeString, encodeString, getHeap, lengthBytesUTF, shift; + if (charSize === 2) { + decodeString = UTF16ToString; + encodeString = stringToUTF16; + lengthBytesUTF = lengthBytesUTF16; + getHeap = function() { + return HEAPU16; + }; + shift = 1; + } else if (charSize === 4) { + decodeString = UTF32ToString; + encodeString = stringToUTF32; + lengthBytesUTF = lengthBytesUTF32; + getHeap = function() { + return HEAPU32; + }; + shift = 2; + } + registerType(rawType, { name: name2, "fromWireType": function(value) { + var length = HEAPU32[value >>> 2]; + var HEAP = getHeap(); + var str; + var decodeStartPtr = value + 4; + for (var i = 0; i <= length; ++i) { + var currentBytePtr = value + 4 + i * charSize; + if (i == length || HEAP[currentBytePtr >>> shift] == 0) { + var maxReadBytes = currentBytePtr - decodeStartPtr; + var stringSegment = decodeString(decodeStartPtr, maxReadBytes); + if (str === void 0) { + str = stringSegment; + } else { + str += String.fromCharCode(0); + str += stringSegment; + } + decodeStartPtr = currentBytePtr + charSize; + } } - - this._keyMap = keyMap; - } else { - const keyMap = value; - this._keyMap = keyMap; + _free(value); + return str; + }, "toWireType": function(destructors, value) { + if (!(typeof value === "string")) { + throwBindingError("Cannot pass non-string to C++ string type " + name2); + } + var length = lengthBytesUTF(value); + var ptr = _malloc(4 + length + charSize); + ptr >>>= 0; + HEAPU32[ptr >>> 2] = length >> shift; + encodeString(value, ptr + 4, length + charSize); + if (destructors !== null) { + destructors.push(_free, ptr); + } + return ptr; + }, "argPackAdvance": 8, "readValueFromPointer": simpleReadValueFromPointer, destructorFunction: function(ptr) { + _free(ptr); + } }); + } + function __embind_register_value_array(rawType, name2, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { + tupleRegistrations[rawType] = { name: readLatin1String(name2), rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), elements: [] }; + } + function __embind_register_value_array_element(rawTupleType, getterReturnType, getterSignature, getter, getterContext, setterArgumentType, setterSignature, setter, setterContext) { + tupleRegistrations[rawTupleType].elements.push({ getterReturnType, getter: embind__requireFunction(getterSignature, getter), getterContext, setterArgumentType, setter: embind__requireFunction(setterSignature, setter), setterContext }); + } + function __embind_register_value_object(rawType, name2, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { + structRegistrations[rawType] = { name: readLatin1String(name2), rawConstructor: embind__requireFunction(constructorSignature, rawConstructor), rawDestructor: embind__requireFunction(destructorSignature, rawDestructor), fields: [] }; + } + function __embind_register_value_object_field(structType, fieldName, getterReturnType, getterSignature, getter, getterContext, setterArgumentType, setterSignature, setter, setterContext) { + structRegistrations[structType].fields.push({ fieldName: readLatin1String(fieldName), getterReturnType, getter: embind__requireFunction(getterSignature, getter), getterContext, setterArgumentType, setter: embind__requireFunction(setterSignature, setter), setterContext }); + } + function __embind_register_void(rawType, name2) { + name2 = readLatin1String(name2); + registerType(rawType, { isVoid: true, name: name2, "argPackAdvance": 0, "fromWireType": function() { + return void 0; + }, "toWireType": function(destructors, o) { + return void 0; + } }); + } + function requireHandle(handle) { + if (!handle) { + throwBindingError("Cannot use deleted val. handle = " + handle); + } + return emval_handle_array[handle].value; + } + function __emval_as(handle, returnType, destructorsRef) { + handle = requireHandle(handle); + returnType = requireRegisteredType(returnType, "emval::as"); + var destructors = []; + var rd = __emval_register(destructors); + HEAP32[destructorsRef >>> 2] = rd; + return returnType["toWireType"](destructors, handle); + } + function __emval_lookupTypes(argCount, argTypes) { + var a = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + a[i] = requireRegisteredType(HEAP32[(argTypes >> 2) + i >>> 0], "parameter " + i); + } + return a; + } + function __emval_call(handle, argCount, argTypes, argv) { + handle = requireHandle(handle); + var types = __emval_lookupTypes(argCount, argTypes); + var args = new Array(argCount); + for (var i = 0; i < argCount; ++i) { + var type = types[i]; + args[i] = type["readValueFromPointer"](argv); + argv += type["argPackAdvance"]; + } + var rv = handle.apply(void 0, args); + return __emval_register(rv); + } + var emval_symbols = {}; + function getStringOrSymbol(address) { + var symbol = emval_symbols[address]; + if (symbol === void 0) { + return readLatin1String(address); + } else { + return symbol; + } + } + function emval_get_global() { + if (typeof globalThis === "object") { + return globalThis; + } + return function() { + return Function; + }()("return this")(); + } + function __emval_get_global(name2) { + if (name2 === 0) { + return __emval_register(emval_get_global()); + } else { + name2 = getStringOrSymbol(name2); + return __emval_register(emval_get_global()[name2]); + } + } + function __emval_get_property(handle, key2) { + handle = requireHandle(handle); + key2 = requireHandle(key2); + return __emval_register(handle[key2]); + } + function __emval_incref(handle) { + if (handle > 4) { + emval_handle_array[handle].refcount += 1; + } + } + function __emval_instanceof(object, constructor) { + object = requireHandle(object); + constructor = requireHandle(constructor); + return object instanceof constructor; } - } - - /** - * Gets custom mappings of keys to {@link CameraControl} actions. - * - * @returns {{Number:Number}} Current key mappings. - */ - get keyMap() { - return this._keyMap; - } - - /** - * Returns true if any keys configured for the given action are down. - * @param action - * @param keyDownMap - * @private - */ - _isKeyDownForAction(action, keyDownMap) { - const keys = this._keyMap[action]; - if (!keys) { - return false; + function __emval_is_number(handle) { + handle = requireHandle(handle); + return typeof handle === "number"; } - if (!keyDownMap) { - keyDownMap = this.scene.input.keyDown; + function __emval_new_array() { + return __emval_register([]); } - for (let i = 0, len = keys.length; i < len; i++) { - const key = keys[i]; - if (keyDownMap[key]) { - return true; - } + function __emval_new_cstring(v) { + return __emval_register(getStringOrSymbol(v)); } - return false; - } - - /** - * Sets the HTMl element to represent the pivot point when {@link CameraControl#followPointer} is true. - * - * See class comments for an example. - * - * @param {HTMLElement} element HTML element representing the pivot point. - */ - set pivotElement(element) { - this._controllers.pivotController.setPivotElement(element); - } - - /** - * Sets if this ````CameraControl```` is active or not. - * - * When inactive, the ````CameraControl```` will not react to input. - * - * Default is ````true````. - * - * @param {Boolean} value Set ````true```` to activate this ````CameraControl````. - */ - set active(value) { - this._configs.active = value !== false; - } - - /** - * Gets if this ````CameraControl```` is active or not. - * - * When inactive, the ````CameraControl```` will not react to input. - * - * Default is ````true````. - * - * @returns {Boolean} Returns ````true```` if this ````CameraControl```` is active. - */ - get active() { - return this._configs.active; - } - - /** - * Sets the current navigation mode. - * - * Accepted values are: - * - * * "orbit" - rotation orbits about the current target or pivot point, - * * "firstPerson" - rotation is about the current eye position, - * * "planView" - rotation is disabled. - * - * See class comments for more info. - * - * @param {String} navMode The navigation mode: "orbit", "firstPerson" or "planView". - */ - set navMode(navMode) { - navMode = navMode || "orbit"; - if (navMode !== "firstPerson" && navMode !== "orbit" && navMode !== "planView") { - this.error("Unsupported value for navMode: " + navMode + " - supported values are 'orbit', 'firstPerson' and 'planView' - defaulting to 'orbit'"); - navMode = "orbit"; + function __emval_new_object() { + return __emval_register({}); } - this._configs.firstPerson = (navMode === "firstPerson"); - this._configs.planView = (navMode === "planView"); - if (this._configs.firstPerson || this._configs.planView) { - this._controllers.pivotController.hidePivot(); - this._controllers.pivotController.endPivot(); + function __emval_run_destructors(handle) { + var destructors = emval_handle_array[handle].value; + runDestructors(destructors); + __emval_decref(handle); } - this._configs.navMode = navMode; - } - - /** - * Gets the current navigation mode. - * - * @returns {String} The navigation mode: "orbit", "firstPerson" or "planView". - */ - get navMode() { - return this._configs.navMode; - } - - /** - * Sets whether mouse and touch input is enabled. - * - * Default is ````true````. - * - * Disabling mouse and touch input on ````CameraControl```` is useful when we want to temporarily use mouse or - * touch input to interact with some other 3D control, without disturbing the {@link Camera}. - * - * @param {Boolean} value Set ````true```` to enable mouse and touch input. - */ - set pointerEnabled(value) { - this._reset(); - this._configs.pointerEnabled = !!value; - } - - _reset() { - for (let i = 0, len = this._handlers.length; i < len; i++) { - const handler = this._handlers[i]; - if (handler.reset) { - handler.reset(); - } + function __emval_set_property(handle, key2, value) { + handle = requireHandle(handle); + key2 = requireHandle(key2); + value = requireHandle(value); + handle[key2] = value; } - - this._updates.panDeltaX = 0; - this._updates.panDeltaY = 0; - this._updates.rotateDeltaX = 0; - this._updates.rotateDeltaY = 0; - this._updates.dolyDelta = 0; - } - - /** - * Gets whether mouse and touch input is enabled. - * - * Default is ````true````. - * - * Disabling mouse and touch input on ````CameraControl```` is desirable when we want to temporarily use mouse or - * touch input to interact with some other 3D control, without interfering with the {@link Camera}. - * - * @returns {Boolean} Returns ````true```` if mouse and touch input is enabled. - */ - get pointerEnabled() { - return this._configs.pointerEnabled; - } - - /** - * Sets whether the {@link Camera} follows the mouse/touch pointer. - * - * In orbiting mode, the Camera will orbit about the pointer, and will dolly to and from the pointer. - * - * In fly-to mode, the Camera will dolly to and from the pointer, however the World will always rotate about the Camera position. - * - * In plan-view mode, the Camera will dolly to and from the pointer, however the Camera will not rotate. - * - * Default is ````true````. - * - * See class comments for more info. - * - * @param {Boolean} value Set ````true```` to enable the Camera to follow the pointer. - */ - set followPointer(value) { - this._configs.followPointer = (value !== false); - } - - /** - * Sets whether the {@link Camera} follows the mouse/touch pointer. - * - * In orbiting mode, the Camera will orbit about the pointer, and will dolly to and from the pointer. - * - * In fly-to mode, the Camera will dolly to and from the pointer, however the World will always rotate about the Camera position. - * - * In plan-view mode, the Camera will dolly to and from the pointer, however the Camera will not rotate. - * - * Default is ````true````. - * - * See class comments for more info. - * - * @returns {Boolean} Returns ````true```` if the Camera follows the pointer. - */ - get followPointer() { - return this._configs.followPointer; - } - - /** - * Sets the current World-space 3D target position. - * - * Only applies when {@link CameraControl#followPointer} is ````true````. - * - * @param {Number[]} worldPos The new World-space 3D target position. - */ - set pivotPos(worldPos) { - this._controllers.pivotController.setPivotPos(worldPos); - } - - /** - * Gets the current World-space 3D pivot position. - * - * Only applies when {@link CameraControl#followPointer} is ````true````. - * - * @return {Number[]} worldPos The current World-space 3D pivot position. - */ - get pivotPos() { - return this._controllers.pivotController.getPivotPos(); - } - - /** - * @deprecated - * @param {Boolean} value Set ````true```` to enable dolly-to-pointer behaviour. - */ - set dollyToPointer(value) { - this.warn("dollyToPointer property is deprecated - replaced with followPointer"); - this.followPointer = value; - } - - /** - * @deprecated - * @returns {Boolean} Returns ````true```` if dolly-to-pointer behaviour is enabled. - */ - get dollyToPointer() { - this.warn("dollyToPointer property is deprecated - replaced with followPointer"); - return this.followPointer; - } - - /** - * @deprecated - * @param {Boolean} value Set ````true```` to enable dolly-to-pointer behaviour. - */ - set panToPointer(value) { - this.warn("panToPointer property is deprecated - replaced with followPointer"); - } - - /** - * @deprecated - * @returns {Boolean} Returns ````true```` if dolly-to-pointer behaviour is enabled. - */ - get panToPointer() { - this.warn("panToPointer property is deprecated - replaced with followPointer"); - return false; - } - - /** - * Sets whether this ````CameraControl```` is in plan-view mode. - * - * When in plan-view mode, rotation is disabled. - * - * Default is ````false````. - * - * Deprecated - use {@link CameraControl#navMode} instead. - * - * @param {Boolean} value Set ````true```` to enable plan-view mode. - * @deprecated - */ - set planView(value) { - this._configs.planView = !!value; - this._configs.firstPerson = false; - if (this._configs.planView) { - this._controllers.pivotController.hidePivot(); - this._controllers.pivotController.endPivot(); + function __emval_take_value(type, argv) { + type = requireRegisteredType(type, "_emval_take_value"); + var v = type["readValueFromPointer"](argv); + return __emval_register(v); } - this.warn("planView property is deprecated - replaced with navMode"); - } - - /** - * Gets whether this ````CameraControl```` is in plan-view mode. - * - * When in plan-view mode, rotation is disabled. - * - * Default is ````false````. - * - * Deprecated - use {@link CameraControl#navMode} instead. - * - * @returns {Boolean} Returns ````true```` if plan-view mode is enabled. - * @deprecated - */ - get planView() { - this.warn("planView property is deprecated - replaced with navMode"); - return this._configs.planView; - } - - /** - * Sets whether this ````CameraControl```` is in first-person mode. - * - * In "first person" mode (disabled by default) the look position rotates about the eye position. Otherwise, {@link Camera#eye} rotates about {@link Camera#look}. - * - * Default is ````false````. - * - * Deprecated - use {@link CameraControl#navMode} instead. - * - * @param {Boolean} value Set ````true```` to enable first-person mode. - * @deprecated - */ - set firstPerson(value) { - this.warn("firstPerson property is deprecated - replaced with navMode"); - this._configs.firstPerson = !!value; - this._configs.planView = false; - if (this._configs.firstPerson) { - this._controllers.pivotController.hidePivot(); - this._controllers.pivotController.endPivot(); + function _abort() { + abort(); } - } - - /** - * Gets whether this ````CameraControl```` is in first-person mode. - * - * In "first person" mode (disabled by default) the look position rotates about the eye position. Otherwise, {@link Camera#eye} rotates about {@link Camera#look}. - * - * Default is ````false````. - * - * Deprecated - use {@link CameraControl#navMode} instead. - * - * @returns {Boolean} Returns ````true```` if first-person mode is enabled. - * @deprecated - */ - get firstPerson() { - this.warn("firstPerson property is deprecated - replaced with navMode"); - return this._configs.firstPerson; - } - - /** - * Sets whether to vertically constrain the {@link Camera} position for first-person navigation. - * - * When set ````true````, this constrains {@link Camera#eye} to its current vertical position. - * - * Only applies when {@link CameraControl#navMode} is ````"firstPerson"````. - * - * Default is ````false````. - * - * @param {Boolean} value Set ````true```` to vertically constrain the Camera. - */ - set constrainVertical(value) { - this._configs.constrainVertical = !!value; - } - - /** - * Gets whether to vertically constrain the {@link Camera} position for first-person navigation. - * - * When set ````true````, this constrains {@link Camera#eye} to its current vertical position. - * - * Only applies when {@link CameraControl#navMode} is ````"firstPerson"````. - * - * Default is ````false````. - * - * @returns {Boolean} ````true```` when Camera is vertically constrained. - */ - get constrainVertical() { - return this._configs.constrainVertical; - } - - /** - * Sets whether double-picking an {@link Entity} causes the {@link Camera} to fly to its boundary. - * - * Default is ````false````. - * - * @param {Boolean} value Set ````true```` to enable double-pick-fly-to mode. - */ - set doublePickFlyTo(value) { - this._configs.doublePickFlyTo = value !== false; - } - - /** - * Gets whether double-picking an {@link Entity} causes the {@link Camera} to fly to its boundary. - * - * Default is ````false````. - * - * @returns {Boolean} Returns ````true```` when double-pick-fly-to mode is enabled. - */ - get doublePickFlyTo() { - return this._configs.doublePickFlyTo; - } - - /** - * Sets whether either right-clicking (true) or middle-clicking (false) pans the {@link Camera}. - * - * Default is ````true````. - * - * @param {Boolean} value Set ````false```` to disable pan on right-click. - */ - set panRightClick(value) { - this._configs.panRightClick = value !== false; - } - - /** - * Gets whether right-clicking pans the {@link Camera}. - * - * Default is ````true````. - * - * @returns {Boolean} Returns ````false```` when pan on right-click is disabled. - */ - get panRightClick() { - return this._configs.panRightClick; - } - - /** - * Sets a factor in range ````[0..1]```` indicating how much the {@link Camera} keeps moving after you finish rotating it. - * - * A value of ````0.0```` causes it to immediately stop, ````0.5```` causes its movement to decay 50% on each tick, - * while ````1.0```` causes no decay, allowing it continue moving, by the current rate of rotation. - * - * You may choose an inertia of zero when you want be able to precisely rotate the Camera, - * without interference from inertia. Zero inertia can also mean that less frames are rendered while - * you are rotating the Camera. - * - * Default is ````0.0````. - * - * Does not apply when {@link CameraControl#navMode} is ````"planView"````, which disallows rotation. - * - * @param {Number} rotationInertia New inertial factor. - */ - set rotationInertia(rotationInertia) { - this._configs.rotationInertia = (rotationInertia !== undefined && rotationInertia !== null) ? rotationInertia : 0.0; - } - - /** - * Gets the rotation inertia factor. - * - * Default is ````0.0````. - * - * Does not apply when {@link CameraControl#navMode} is ````"planView"````, which disallows rotation. - * - * @returns {Number} The inertia factor. - */ - get rotationInertia() { - return this._configs.rotationInertia; - } - - /** - * Sets how much the {@link Camera} pans each second with keyboard input. - * - * Default is ````5.0````, to pan the Camera ````5.0```` World-space units every second that - * a panning key is depressed. See the ````CameraControl```` class documentation for which keys control - * panning. - * - * Panning direction is aligned to our Camera's orientation. When we pan horizontally, we pan - * to our left and right, when we pan vertically, we pan upwards and downwards, and when we pan forwards - * and backwards, we pan along the direction the Camera is pointing. - * - * Unlike dollying when {@link followPointer} is ````true````, panning does not follow the pointer. - * - * @param {Number} keyboardPanRate The new keyboard pan rate. - */ - set keyboardPanRate(keyboardPanRate) { - this._configs.keyboardPanRate = (keyboardPanRate !== null && keyboardPanRate !== undefined) ? keyboardPanRate : 5.0; - } - - - /** - * Sets how fast the camera pans on touch panning - * - * @param {Number} touchPanRate The new touch pan rate. - */ - set touchPanRate(touchPanRate) { - this._configs.touchPanRate = (touchPanRate !== null && touchPanRate !== undefined) ? touchPanRate : 1.0; - } - - /** - * Gets how fast the {@link Camera} pans on touch panning - * - * Default is ````1.0````. - * - * @returns {Number} The current touch pan rate. - */ - get touchPanRate() { - return this._configs.touchPanRate; - } - - /** - * Gets how much the {@link Camera} pans each second with keyboard input. - * - * Default is ````5.0````. - * - * @returns {Number} The current keyboard pan rate. - */ - get keyboardPanRate() { - return this._configs.keyboardPanRate; - } - - /** - * Sets how many degrees per second the {@link Camera} rotates/orbits with keyboard input. - * - * Default is ````90.0````, to rotate/orbit the Camera ````90.0```` degrees every second that - * a rotation key is depressed. See the ````CameraControl```` class documentation for which keys control - * rotation/orbit. - * - * @param {Number} keyboardRotationRate The new keyboard rotation rate. - */ - set keyboardRotationRate(keyboardRotationRate) { - this._configs.keyboardRotationRate = (keyboardRotationRate !== null && keyboardRotationRate !== undefined) ? keyboardRotationRate : 90.0; - } - - /** - * Sets how many degrees per second the {@link Camera} rotates/orbits with keyboard input. - * - * Default is ````90.0````. - * - * @returns {Number} The current keyboard rotation rate. - */ - get keyboardRotationRate() { - return this._configs.keyboardRotationRate; - } - - /** - * Sets the current drag rotation rate. - * - * This configures how many degrees the {@link Camera} rotates/orbits for a full sweep of the canvas by mouse or touch dragging. - * - * For example, a value of ````360.0```` indicates that the ````Camera```` rotates/orbits ````360.0```` degrees horizontally - * when we sweep the entire width of the canvas. - * - * ````CameraControl```` makes vertical rotation half as sensitive as horizontal rotation, so that we don't tend to - * flip upside-down. Therefore, a value of ````360.0```` rotates/orbits the ````Camera```` through ````180.0```` degrees - * vertically when we sweep the entire height of the canvas. - * - * Default is ````360.0````. - * - * @param {Number} dragRotationRate The new drag rotation rate. - */ - set dragRotationRate(dragRotationRate) { - this._configs.dragRotationRate = (dragRotationRate !== null && dragRotationRate !== undefined) ? dragRotationRate : 360.0; - } - - /** - * Gets the current drag rotation rate. - * - * Default is ````360.0````. - * - * @returns {Number} The current drag rotation rate. - */ - get dragRotationRate() { - return this._configs.dragRotationRate; - } - - /** - * Sets how much the {@link Camera} dollys each second with keyboard input. - * - * Default is ````15.0````, to dolly the {@link Camera} ````15.0```` World-space units per second while we hold down - * the ````+```` and ````-```` keys. - * - * @param {Number} keyboardDollyRate The new keyboard dolly rate. - */ - set keyboardDollyRate(keyboardDollyRate) { - this._configs.keyboardDollyRate = (keyboardDollyRate !== null && keyboardDollyRate !== undefined) ? keyboardDollyRate : 15.0; - } - - /** - * Gets how much the {@link Camera} dollys each second with keyboard input. - * - * Default is ````15.0````. - * - * @returns {Number} The current keyboard dolly rate. - */ - get keyboardDollyRate() { - return this._configs.keyboardDollyRate; - } - - /** - * Sets how much the {@link Camera} dollys with touch input. - * - * Default is ````0.2```` - * - * @param {Number} touchDollyRate The new touch dolly rate. - */ - set touchDollyRate(touchDollyRate) { - this._configs.touchDollyRate = (touchDollyRate !== null && touchDollyRate !== undefined) ? touchDollyRate : 0.2; - } - - /** - * Gets how much the {@link Camera} dollys each second with touch input. - * - * Default is ````0.2````. - * - * @returns {Number} The current touch dolly rate. - */ - get touchDollyRate() { - return this._configs.touchDollyRate; - } - - /** - * Sets how much the {@link Camera} dollys each second while the mouse wheel is spinning. - * - * Default is ````100.0````, to dolly the {@link Camera} ````10.0```` World-space units per second as we spin - * the mouse wheel. - * - * @param {Number} mouseWheelDollyRate The new mouse wheel dolly rate. - */ - set mouseWheelDollyRate(mouseWheelDollyRate) { - this._configs.mouseWheelDollyRate = (mouseWheelDollyRate !== null && mouseWheelDollyRate !== undefined) ? mouseWheelDollyRate : 100.0; - } - - /** - * Gets how much the {@link Camera} dollys each second while the mouse wheel is spinning. - * - * Default is ````100.0````. - * - * @returns {Number} The current mouseWheel dolly rate. - */ - get mouseWheelDollyRate() { - return this._configs.mouseWheelDollyRate; - } - - /** - * Sets the dolly inertia factor. - * - * This factor configures how much the {@link Camera} keeps moving after you finish dollying it. - * - * This factor is a value in range ````[0..1]````. A value of ````0.0```` causes dollying to immediately stop, - * ````0.5```` causes dollying to decay 50% on each animation frame, while ````1.0```` causes no decay, which allows dollying - * to continue until further input stops it. - * - * You might set ````dollyInertia```` to zero when you want be able to precisely position or rotate the Camera, - * without interference from inertia. This also means that xeokit renders less frames while dollying the Camera, - * which can improve rendering performance. - * - * Default is ````0````. - * - * @param {Number} dollyInertia New dolly inertia factor. - */ - set dollyInertia(dollyInertia) { - this._configs.dollyInertia = (dollyInertia !== undefined && dollyInertia !== null) ? dollyInertia : 0; - } - - /** - * Gets the dolly inertia factor. - * - * Default is ````0````. - * - * @returns {Number} The current dolly inertia factor. - */ - get dollyInertia() { - return this._configs.dollyInertia; - } - - /** - * Sets the proximity to the closest object below which dolly speed decreases, and above which dolly speed increases. - * - * Default is ````35.0````. - * - * @param {Number} dollyProximityThreshold New dolly proximity threshold. - */ - set dollyProximityThreshold(dollyProximityThreshold) { - this._configs.dollyProximityThreshold = (dollyProximityThreshold !== undefined && dollyProximityThreshold !== null) ? dollyProximityThreshold : 35.0; - } - - /** - * Gets the proximity to the closest object below which dolly speed decreases, and above which dolly speed increases. - * - * Default is ````35.0````. - * - * @returns {Number} The current dolly proximity threshold. - */ - get dollyProximityThreshold() { - return this._configs.dollyProximityThreshold; - } - - /** - * Sets the minimum dolly speed. - * - * Default is ````0.04````. - * - * @param {Number} dollyMinSpeed New dolly minimum speed. - */ - set dollyMinSpeed(dollyMinSpeed) { - this._configs.dollyMinSpeed = (dollyMinSpeed !== undefined && dollyMinSpeed !== null) ? dollyMinSpeed : 0.04; - } - - /** - * Gets the minimum dolly speed. - * - * Default is ````0.04````. - * - * @returns {Number} The current minimum dolly speed. - */ - get dollyMinSpeed() { - return this._configs.dollyMinSpeed; - } - - /** - * Sets the pan inertia factor. - * - * This factor configures how much the {@link Camera} keeps moving after you finish panning it. - * - * This factor is a value in range ````[0..1]````. A value of ````0.0```` causes panning to immediately stop, - * ````0.5```` causes panning to decay 50% on each animation frame, while ````1.0```` causes no decay, which allows panning - * to continue until further input stops it. - * - * You might set ````panInertia```` to zero when you want be able to precisely position or rotate the Camera, - * without interference from inertia. This also means that xeokit renders less frames while panning the Camera, - * wich can improve rendering performance. - * - * Default is ````0.5````. - * - * @param {Number} panInertia New pan inertia factor. - */ - set panInertia(panInertia) { - this._configs.panInertia = (panInertia !== undefined && panInertia !== null) ? panInertia : 0.5; - } - - /** - * Gets the pan inertia factor. - * - * Default is ````0.5````. - * - * @returns {Number} The current pan inertia factor. - */ - get panInertia() { - return this._configs.panInertia; - } - - /** - * Sets the keyboard layout. - * - * Supported layouts are: - * - * * ````"qwerty"```` (default) - * * ````"azerty"```` - * - * @deprecated - * @param {String} value Selects the keyboard layout. - */ - set keyboardLayout(value) { - // this.warn("keyboardLayout property is deprecated - use keyMap property instead"); - value = value || "qwerty"; - if (value !== "qwerty" && value !== "azerty") { - this.error("Unsupported value for keyboardLayout - defaulting to 'qwerty'"); - value = "qwerty"; + var _emscripten_get_now; + if (ENVIRONMENT_IS_NODE) { + _emscripten_get_now = function() { + var t = process["hrtime"](); + return t[0] * 1e3 + t[1] / 1e6; + }; + } else + _emscripten_get_now = function() { + return performance.now(); + }; + var _emscripten_get_now_is_monotonic = true; + function _clock_gettime(clk_id, tp) { + var now; + if (clk_id === 0) { + now = Date.now(); + } else if ((clk_id === 1 || clk_id === 4) && _emscripten_get_now_is_monotonic) { + now = _emscripten_get_now(); + } else { + setErrNo(28); + return -1; + } + HEAP32[tp >>> 2] = now / 1e3 | 0; + HEAP32[tp + 4 >>> 2] = now % 1e3 * 1e3 * 1e3 | 0; + return 0; } - this._configs.keyboardLayout = value; - this.keyMap = this._configs.keyboardLayout; - } - - /** - * Gets the keyboard layout. - * - * Supported layouts are: - * - * * ````"qwerty"```` (default) - * * ````"azerty"```` - * - * @deprecated - * @returns {String} The current keyboard layout. - */ - get keyboardLayout() { - return this._configs.keyboardLayout; - } - - /** - * Sets whether smart default pivoting is enabled. - * - * When ````true````, we'll pivot by default about the 3D position of the mouse/touch pointer on an - * imaginary sphere that's centered at {@link Camera#eye} and sized to the {@link Scene} boundary. - * - * When ````false````, we'll pivot by default about {@link Camera#look}. - * - * Default is ````false````. - * - * @param {Boolean} enabled Set ````true```` to pivot by default about the selected point on the virtual sphere, or ````false```` to pivot by default about {@link Camera#look}. - */ - set smartPivot(enabled) { - this._configs.smartPivot = (enabled !== false); - } - - /** - * Gets whether smart default pivoting is enabled. - * - * When ````true````, we'll pivot by default about the 3D position of the mouse/touch pointer on an - * imaginary sphere that's centered at {@link Camera#eye} and sized to the {@link Scene} boundary. - * - * When ````false````, we'll pivot by default about {@link Camera#look}. - * - * Default is ````false````. - * - * @returns {Boolean} Returns ````true```` when pivoting by default about the selected point on the virtual sphere, or ````false```` when pivoting by default about {@link Camera#look}. - */ - get smartPivot() { - return this._configs.smartPivot; - } - - /** - * Sets the double click time frame length in milliseconds. - * - * If two mouse click events occur within this time frame, it is considered a double click. - * - * Default is ````250```` - * - * @param {Number} value New double click time frame. - */ - set doubleClickTimeFrame(value) { - this._configs.doubleClickTimeFrame = (value !== undefined && value !== null) ? value : 250; - } - - /** - * Gets the double click time frame length in milliseconds. - * - * Default is ````250```` - * - * @param {Number} value Current double click time frame. - */ - get doubleClickTimeFrame() { - return this._configs.doubleClickTimeFrame; - } - - /** - * Destroys this ````CameraControl````. - * @private - */ - destroy() { - this._destroyHandlers(); - this._destroyControllers(); - this._cameraUpdater.destroy(); - super.destroy(); - } - - _destroyHandlers() { - for (let i = 0, len = this._handlers.length; i < len; i++) { - const handler = this._handlers[i]; - if (handler.destroy) { - handler.destroy(); - } + function _emscripten_memcpy_big(dest, src, num) { + HEAPU8.copyWithin(dest >>> 0, src >>> 0, src + num >>> 0); } - } - - _destroyControllers() { - for (let i = 0, len = this._controllers.length; i < len; i++) { - const controller = this._controllers[i]; - if (controller.destroy) { - controller.destroy(); - } + function emscripten_realloc_buffer(size) { + try { + wasmMemory.grow(size - buffer.byteLength + 65535 >>> 16); + updateGlobalBufferAndViews(wasmMemory.buffer); + return 1; + } catch (e) { + } } - } -} - -/** - * @desc Metadata corresponding to an {@link Entity} that represents a model. - * - * An {@link Entity} represents a model when {@link Entity#isModel} is ````true```` - * - * A MetaModel corresponds to an {@link Entity} by having the same {@link MetaModel#id} as the {@link Entity#id}. - * - * A MetaModel is created by {@link MetaScene#createMetaModel} and belongs to a {@link MetaScene}. - * - * Each MetaModel is registered by {@link MetaModel#id} in {@link MetaScene#metaModels}. - * - * A {@link MetaModel} represents its object structure with a tree of {@link MetaObject}s, with {@link MetaModel#rootMetaObject} referencing the root {@link MetaObject}. - * - * @class MetaModel - */ -class MetaModel { - - /** - * @private - */ - constructor(metaScene, id, projectId, revisionId, author, createdAt, creatingApplication, schema, propertySets, rootMetaObject) { - - /** - * Globally-unique ID. - * - * MetaModels are registered by ID in {@link MetaScene#metaModels}. - * - * When this MetaModel corresponds to an {@link Entity} then this ID will match the {@link Entity#id}. - * - * @property id - * @type {String|Number} - */ - this.id = id; - - /** - * The project ID - * @property projectId - * @type {String|Number} - */ - this.projectId = projectId; - - /** - * The revision ID, if available. - * - * Will be undefined if not available. - * - * @property revisionId - * @type {String|Number} - */ - this.revisionId = revisionId; - - /** - * The model author, if available. - * - * Will be undefined if not available. - * - * @property author - * @type {String} - */ - this.author = author; - - /** - * The date the model was created, if available. - * - * Will be undefined if not available. - * - * @property createdAt - * @type {String} - */ - this.createdAt = createdAt; - - /** - * The application that created the model, if available. - * - * Will be undefined if not available. - * - * @property creatingApplication - * @type {String} - */ - this.creatingApplication = creatingApplication; - - /** - * The model schema version, if available. - * - * Will be undefined if not available. - * - * @property schema - * @type {String} - */ - this.schema = schema; - - /** - * Metadata on the {@link Scene}. - * - * @property metaScene - * @type {MetaScene} - */ - this.metaScene = metaScene; - - /** - * The {@link PropertySet}s in this MetaModel. - * - * @property propertySets - * @type {{String:PropertySet}} - */ - this.propertySets = propertySets; - - /** - * The root {@link MetaObject} in this MetaModel's composition structure hierarchy. - * - * @property rootMetaObject - * @type {MetaObject} - */ - this.rootMetaObject = rootMetaObject; - } - - getJSON() { - - const metaObjects = []; - - function visit(metaObject) { - const metaObjectCfg = { - id: metaObject.id, - extId: metaObject.extId, - type: metaObject.type, - name: metaObject.name - }; - if (metaObject.parent) { - metaObjectCfg.parent = metaObject.parent.id; + function _emscripten_resize_heap(requestedSize) { + var oldSize = HEAPU8.length; + requestedSize = requestedSize >>> 0; + var maxHeapSize = 4294901760; + if (requestedSize > maxHeapSize) { + return false; + } + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296); + var newSize = Math.min(maxHeapSize, alignUp(Math.max(requestedSize, overGrownHeapSize), 65536)); + var replacement = emscripten_realloc_buffer(newSize); + if (replacement) { + return true; } - metaObjects.push(metaObjectCfg); - const children = metaObject.children; - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - visit(children[i]); - } + } + return false; + } + var ENV = {}; + function getExecutableName() { + return thisProgram || "./this.program"; + } + function getEnvStrings() { + if (!getEnvStrings.strings) { + var lang = (typeof navigator === "object" && navigator.languages && navigator.languages[0] || "C").replace("-", "_") + ".UTF-8"; + var env = { "USER": "web_user", "LOGNAME": "web_user", "PATH": "/", "PWD": "/", "HOME": "/home/web_user", "LANG": lang, "_": getExecutableName() }; + for (var x in ENV) { + if (ENV[x] === void 0) + delete env[x]; + else + env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(x + "=" + env[x]); } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; } - - visit(this.rootMetaObject); - - const json = { - id: this.id, - projectId: this.projectId, - revisionId: this.revisionId, - metaObjects: metaObjects - }; - return json; - } -} - -/** - * @desc Metadata corresponding to an {@link Entity} that represents an object. - * - * An {@link Entity} represents an object when {@link Entity#isObject} is ````true```` - * - * A MetaObject corresponds to an {@link Entity} by having the same {@link MetaObject#id} as the {@link Entity#id}. - * - * A MetaObject is created within {@link MetaScene#createMetaModel} and belongs to a {@link MetaModel}. - * - * Each MetaObject is registered by {@link MetaObject#id} in {@link MetaScene#metaObjects}. - * - * A {@link MetaModel} represents its object structure with a tree of MetaObjects, with {@link MetaModel#rootMetaObject} referencing - * the root MetaObject. - * - * @class MetaObject - */ -class MetaObject { - - /** - * @private - */ - constructor(metaModel, id, originalSystemId, name, type, propertySets, parent, children, external) { - - /** - * Model metadata. - * - * @property metaModel - * @type {MetaModel} - */ - this.metaModel = metaModel; - - /** - * Globally-unique ID. - * - * MetaObject instances are registered by this ID in {@link MetaScene#metaObjects}. - * - * @property id - * @type {String|Number} - */ - this.id = id; - - /** - * ID of the corresponding object within the originating system, if any. - * - * @type {String} - * @abstract - */ - this.originalSystemId = originalSystemId; - - /** - * Human-readable name. - * - * @property name - * @type {String} - */ - this.name = name; - - /** - * Type - often an IFC product type. - * - * @property type - * @type {String} - */ - this.type = type; - - /** - * Optional {@link PropertySet}s used by this MetaObject. - * - * @property propertySets - * @type {PropertySet[]} - */ - this.propertySets = propertySets; - - if (parent !== undefined && parent !== null) { - - /** - * The parent MetaObject within the structure hierarchy. - * - * Undefined when this is the root of its structure. - * - * @property parent - * @type {MetaObject} - */ - this.parent = parent; + function _environ_get(__environ, environ_buf) { + try { + var bufSize = 0; + getEnvStrings().forEach(function(string, i) { + var ptr = environ_buf + bufSize; + HEAP32[__environ + i * 4 >>> 2] = ptr; + writeAsciiToMemory(string, ptr); + bufSize += string.length + 1; + }); + return 0; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return e.errno; + } } - - if (children !== undefined && children !== null) { - - /** - * Child ObjectMeta instances within the structure hierarchy. - * - * Undefined when there are no children. - * - * @property children - * @type {Array} - */ - this.children = children; + function _environ_sizes_get(penviron_count, penviron_buf_size) { + try { + var strings = getEnvStrings(); + HEAP32[penviron_count >>> 2] = strings.length; + var bufSize = 0; + strings.forEach(function(string) { + bufSize += string.length + 1; + }); + HEAP32[penviron_buf_size >>> 2] = bufSize; + return 0; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return e.errno; + } } - - if (external !== undefined && external !== null) { - - /** - * External application-specific metadata - * - * Undefined when there are is no external application-specific metadata. - * - * @property external - * @type {*} - */ - this.external = external; + function _fd_close(fd) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return e.errno; + } } - } - - /** - * Gets the {@link MetaObject#id}s of the {@link MetaObject}s within the subtree. - * - * @returns {String[]} Array of {@link MetaObject#id}s. - */ - getObjectIDsInSubtree() { - const objectIds = []; - - function visit(metaObject) { - if (!metaObject) { - return; + function _fd_read(fd, iov, iovcnt, pnum) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = SYSCALLS.doReadv(stream, iov, iovcnt); + HEAP32[pnum >>> 2] = num; + return 0; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return e.errno; + } + } + function _fd_seek(fd, offset_low, offset_high, whence, newOffset) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var HIGH_OFFSET = 4294967296; + var offset = offset_high * HIGH_OFFSET + (offset_low >>> 0); + var DOUBLE_LIMIT = 9007199254740992; + if (offset <= -DOUBLE_LIMIT || offset >= DOUBLE_LIMIT) { + return -61; } - objectIds.push(metaObject.id); - const children = metaObject.children; - if (children) { - for (var i = 0, len = children.length; i < len; i++) { - visit(children[i]); - } + FS.llseek(stream, offset, whence); + tempI64 = [stream.position >>> 0, (tempDouble = stream.position, +Math.abs(tempDouble) >= 1 ? tempDouble > 0 ? (Math.min(+Math.floor(tempDouble / 4294967296), 4294967295) | 0) >>> 0 : ~~+Math.ceil((tempDouble - +(~~tempDouble >>> 0)) / 4294967296) >>> 0 : 0)], HEAP32[newOffset >>> 2] = tempI64[0], HEAP32[newOffset + 4 >>> 2] = tempI64[1]; + if (stream.getdents && offset === 0 && whence === 0) + stream.getdents = null; + return 0; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return e.errno; + } + } + function _fd_write(fd, iov, iovcnt, pnum) { + try { + var stream = SYSCALLS.getStreamFromFD(fd); + var num = SYSCALLS.doWritev(stream, iov, iovcnt); + HEAP32[pnum >>> 2] = num; + return 0; + } catch (e) { + if (typeof FS === "undefined" || !(e instanceof FS.ErrnoError)) + abort(e); + return e.errno; + } + } + function _setTempRet0(val) { + } + function __isLeapYear(year) { + return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + } + function __arraySum(array, index) { + var sum = 0; + for (var i = 0; i <= index; sum += array[i++]) { + } + return sum; + } + var __MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + var __MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + function __addDays(date, days) { + var newDate = new Date(date.getTime()); + while (days > 0) { + var leap = __isLeapYear(newDate.getFullYear()); + var currentMonth = newDate.getMonth(); + var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth]; + if (days > daysInCurrentMonth - newDate.getDate()) { + days -= daysInCurrentMonth - newDate.getDate() + 1; + newDate.setDate(1); + if (currentMonth < 11) { + newDate.setMonth(currentMonth + 1); + } else { + newDate.setMonth(0); + newDate.setFullYear(newDate.getFullYear() + 1); + } + } else { + newDate.setDate(newDate.getDate() + days); + return newDate; } + } + return newDate; } - - visit(this); - return objectIds; - } - - - /** - * Iterates over the {@link MetaObject}s within the subtree. - * - * @param {Function} callback Callback fired at each {@link MetaObject}. - */ - withMetaObjectsInSubtree(callback) { - - function visit(metaObject) { - if (!metaObject) { - return; + function _strftime(s, maxsize, format, tm) { + var tm_zone = HEAP32[tm + 40 >>> 2]; + var date = { tm_sec: HEAP32[tm >>> 2], tm_min: HEAP32[tm + 4 >>> 2], tm_hour: HEAP32[tm + 8 >>> 2], tm_mday: HEAP32[tm + 12 >>> 2], tm_mon: HEAP32[tm + 16 >>> 2], tm_year: HEAP32[tm + 20 >>> 2], tm_wday: HEAP32[tm + 24 >>> 2], tm_yday: HEAP32[tm + 28 >>> 2], tm_isdst: HEAP32[tm + 32 >>> 2], tm_gmtoff: HEAP32[tm + 36 >>> 2], tm_zone: tm_zone ? UTF8ToString(tm_zone) : "" }; + var pattern = UTF8ToString(format); + var EXPANSION_RULES_1 = { "%c": "%a %b %d %H:%M:%S %Y", "%D": "%m/%d/%y", "%F": "%Y-%m-%d", "%h": "%b", "%r": "%I:%M:%S %p", "%R": "%H:%M", "%T": "%H:%M:%S", "%x": "%m/%d/%y", "%X": "%H:%M:%S", "%Ec": "%c", "%EC": "%C", "%Ex": "%m/%d/%y", "%EX": "%H:%M:%S", "%Ey": "%y", "%EY": "%Y", "%Od": "%d", "%Oe": "%e", "%OH": "%H", "%OI": "%I", "%Om": "%m", "%OM": "%M", "%OS": "%S", "%Ou": "%u", "%OU": "%U", "%OV": "%V", "%Ow": "%w", "%OW": "%W", "%Oy": "%y" }; + for (var rule in EXPANSION_RULES_1) { + pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_1[rule]); + } + var WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + function leadingSomething(value, digits, character) { + var str = typeof value === "number" ? value.toString() : value || ""; + while (str.length < digits) { + str = character[0] + str; } - callback(metaObject); - const children = metaObject.children; - if (children) { - for (var i = 0, len = children.length; i < len; i++) { - visit(children[i]); - } + return str; + } + function leadingNulls(value, digits) { + return leadingSomething(value, digits, "0"); + } + function compareByDay(date1, date2) { + function sgn(value) { + return value < 0 ? -1 : value > 0 ? 1 : 0; } - } - - visit(this); - } - - /** - * Gets the {@link MetaObject#id}s of the {@link MetaObject}s within the subtree that have the given {@link MetaObject#type}s. - * - * @param {String[]} types {@link MetaObject#type} values. - * @returns {String[]} Array of {@link MetaObject#id}s. - */ - getObjectIDsInSubtreeByType(types) { - const mask = {}; - for (var i = 0, len = types.length; i < len; i++) { - mask[types[i]] = types[i]; - } - const objectIds = []; - - function visit(metaObject) { - if (!metaObject) { - return; + var compare; + if ((compare = sgn(date1.getFullYear() - date2.getFullYear())) === 0) { + if ((compare = sgn(date1.getMonth() - date2.getMonth())) === 0) { + compare = sgn(date1.getDate() - date2.getDate()); + } } - if (mask[metaObject.type]) { - objectIds.push(metaObject.id); + return compare; + } + function getFirstWeekStartDate(janFourth) { + switch (janFourth.getDay()) { + case 0: + return new Date(janFourth.getFullYear() - 1, 11, 29); + case 1: + return janFourth; + case 2: + return new Date(janFourth.getFullYear(), 0, 3); + case 3: + return new Date(janFourth.getFullYear(), 0, 2); + case 4: + return new Date(janFourth.getFullYear(), 0, 1); + case 5: + return new Date(janFourth.getFullYear() - 1, 11, 31); + case 6: + return new Date(janFourth.getFullYear() - 1, 11, 30); } - const children = metaObject.children; - if (children) { - for (var i = 0, len = children.length; i < len; i++) { - visit(children[i]); - } + } + function getWeekBasedYear(date2) { + var thisDate = __addDays(new Date(date2.tm_year + 1900, 0, 1), date2.tm_yday); + var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4); + var janFourthNextYear = new Date(thisDate.getFullYear() + 1, 0, 4); + var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear); + var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear); + if (compareByDay(firstWeekStartThisYear, thisDate) <= 0) { + if (compareByDay(firstWeekStartNextYear, thisDate) <= 0) { + return thisDate.getFullYear() + 1; + } else { + return thisDate.getFullYear(); + } + } else { + return thisDate.getFullYear() - 1; + } + } + var EXPANSION_RULES_2 = { "%a": function(date2) { + return WEEKDAYS[date2.tm_wday].substring(0, 3); + }, "%A": function(date2) { + return WEEKDAYS[date2.tm_wday]; + }, "%b": function(date2) { + return MONTHS[date2.tm_mon].substring(0, 3); + }, "%B": function(date2) { + return MONTHS[date2.tm_mon]; + }, "%C": function(date2) { + var year = date2.tm_year + 1900; + return leadingNulls(year / 100 | 0, 2); + }, "%d": function(date2) { + return leadingNulls(date2.tm_mday, 2); + }, "%e": function(date2) { + return leadingSomething(date2.tm_mday, 2, " "); + }, "%g": function(date2) { + return getWeekBasedYear(date2).toString().substring(2); + }, "%G": function(date2) { + return getWeekBasedYear(date2); + }, "%H": function(date2) { + return leadingNulls(date2.tm_hour, 2); + }, "%I": function(date2) { + var twelveHour = date2.tm_hour; + if (twelveHour == 0) + twelveHour = 12; + else if (twelveHour > 12) + twelveHour -= 12; + return leadingNulls(twelveHour, 2); + }, "%j": function(date2) { + return leadingNulls(date2.tm_mday + __arraySum(__isLeapYear(date2.tm_year + 1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date2.tm_mon - 1), 3); + }, "%m": function(date2) { + return leadingNulls(date2.tm_mon + 1, 2); + }, "%M": function(date2) { + return leadingNulls(date2.tm_min, 2); + }, "%n": function() { + return "\n"; + }, "%p": function(date2) { + if (date2.tm_hour >= 0 && date2.tm_hour < 12) { + return "AM"; + } else { + return "PM"; + } + }, "%S": function(date2) { + return leadingNulls(date2.tm_sec, 2); + }, "%t": function() { + return " "; + }, "%u": function(date2) { + return date2.tm_wday || 7; + }, "%U": function(date2) { + var janFirst = new Date(date2.tm_year + 1900, 0, 1); + var firstSunday = janFirst.getDay() === 0 ? janFirst : __addDays(janFirst, 7 - janFirst.getDay()); + var endDate = new Date(date2.tm_year + 1900, date2.tm_mon, date2.tm_mday); + if (compareByDay(firstSunday, endDate) < 0) { + var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth() - 1) - 31; + var firstSundayUntilEndJanuary = 31 - firstSunday.getDate(); + var days = firstSundayUntilEndJanuary + februaryFirstUntilEndMonth + endDate.getDate(); + return leadingNulls(Math.ceil(days / 7), 2); + } + return compareByDay(firstSunday, janFirst) === 0 ? "01" : "00"; + }, "%V": function(date2) { + var janFourthThisYear = new Date(date2.tm_year + 1900, 0, 4); + var janFourthNextYear = new Date(date2.tm_year + 1901, 0, 4); + var firstWeekStartThisYear = getFirstWeekStartDate(janFourthThisYear); + var firstWeekStartNextYear = getFirstWeekStartDate(janFourthNextYear); + var endDate = __addDays(new Date(date2.tm_year + 1900, 0, 1), date2.tm_yday); + if (compareByDay(endDate, firstWeekStartThisYear) < 0) { + return "53"; + } + if (compareByDay(firstWeekStartNextYear, endDate) <= 0) { + return "01"; + } + var daysDifference; + if (firstWeekStartThisYear.getFullYear() < date2.tm_year + 1900) { + daysDifference = date2.tm_yday + 32 - firstWeekStartThisYear.getDate(); + } else { + daysDifference = date2.tm_yday + 1 - firstWeekStartThisYear.getDate(); + } + return leadingNulls(Math.ceil(daysDifference / 7), 2); + }, "%w": function(date2) { + return date2.tm_wday; + }, "%W": function(date2) { + var janFirst = new Date(date2.tm_year, 0, 1); + var firstMonday = janFirst.getDay() === 1 ? janFirst : __addDays(janFirst, janFirst.getDay() === 0 ? 1 : 7 - janFirst.getDay() + 1); + var endDate = new Date(date2.tm_year + 1900, date2.tm_mon, date2.tm_mday); + if (compareByDay(firstMonday, endDate) < 0) { + var februaryFirstUntilEndMonth = __arraySum(__isLeapYear(endDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, endDate.getMonth() - 1) - 31; + var firstMondayUntilEndJanuary = 31 - firstMonday.getDate(); + var days = firstMondayUntilEndJanuary + februaryFirstUntilEndMonth + endDate.getDate(); + return leadingNulls(Math.ceil(days / 7), 2); + } + return compareByDay(firstMonday, janFirst) === 0 ? "01" : "00"; + }, "%y": function(date2) { + return (date2.tm_year + 1900).toString().substring(2); + }, "%Y": function(date2) { + return date2.tm_year + 1900; + }, "%z": function(date2) { + var off = date2.tm_gmtoff; + var ahead = off >= 0; + off = Math.abs(off) / 60; + off = off / 60 * 100 + off % 60; + return (ahead ? "+" : "-") + String("0000" + off).slice(-4); + }, "%Z": function(date2) { + return date2.tm_zone; + }, "%%": function() { + return "%"; + } }; + for (var rule in EXPANSION_RULES_2) { + if (pattern.includes(rule)) { + pattern = pattern.replace(new RegExp(rule, "g"), EXPANSION_RULES_2[rule](date)); } + } + var bytes = intArrayFromString(pattern, false); + if (bytes.length > maxsize) { + return 0; + } + writeArrayToMemory(bytes, s); + return bytes.length - 1; } - - visit(this); - return objectIds; - } - - /** - * Returns properties of this MeteObject as JSON. - * - * @returns {{id: (String|Number), type: String, name: String, parent: (String|Number|Undefined)}} - */ - getJSON() { - var json = { - id: this.id, - type: this.type, - name: this.name - }; - if (this.parent) { - json.parent = this.parent.id; + function _strftime_l(s, maxsize, format, tm) { + return _strftime(s, maxsize, format, tm); } - return json; - } -} - -/** - * @desc A property within a {@link PropertySet}. - * - * @class Property - */ -class Property { - - /** - * @private - */ - constructor(name, value, type, valueType, description) { - - /** - * The name of this property. - * - * @property name - * @type {String} - */ - this.name = name; - - /** - * The type of this property. - * - * @property type - * @type {Number|String} - */ - this.type = type; - - /** - * The value of this property. - * - * @property value - * @type {*} - */ - this.value = value; - - /** - * The type of this property's value. - * - * @property valueType - * @type {Number|String} - */ - this.valueType = valueType; - - /** - * Informative text to explain the property. - * - * @property name - * @type {String} - */ - this.description = description; - } -} - -/** - * @desc A set of properties associated with one or more {@link MetaObject}s. - * - * A PropertySet is created within {@link MetaScene#createMetaModel} and belongs to a {@link MetaModel}. - * - * Each PropertySet is registered by {@link PropertySet#id} in {@link MetaScene#propertySets} and {@link MetaModel#propertySets}. - * - * @class PropertySet - */ -class PropertySet { - - /** - * @private - */ - constructor(id, originalSystemId, name, type, properties) { - - /** - * Globally-unique ID for this PropertySet. - * - * PropertySet instances are registered by this ID in {@link MetaScene#propertySets} and {@link MetaModel#propertySets}. - * - * @property id - * @type {String} - */ - this.id = id; - - /** - * ID of the corresponding object within the originating system, if any. - * - * @type {String} - * @abstract - */ - this.originalSystemId = originalSystemId; - - /** - * Human-readable name of this PropertySet. - * - * @property name - * @type {String} - */ - this.name = name; - - /** - * Type of this PropertySet. - * - * @property type - * @type {String} - */ - this.type = type; - - /** - * Properties within this PropertySet. - * - * @property properties - * @type {Property[]} - */ - this.properties = []; - - if (properties) { - for (let i = 0, len = properties.length; i < len; i++) { - const property = properties[i]; - this.properties.push(new Property(property.name, property.value, property.type, property.valueType, property.description)); - } + var FSNode = function(parent, name2, mode, rdev) { + if (!parent) { + parent = this; + } + this.parent = parent; + this.mount = parent.mount; + this.mounted = null; + this.id = FS.nextInode++; + this.name = name2; + this.mode = mode; + this.node_ops = {}; + this.stream_ops = {}; + this.rdev = rdev; + }; + var readMode = 292 | 73; + var writeMode = 146; + Object.defineProperties(FSNode.prototype, { read: { get: function() { + return (this.mode & readMode) === readMode; + }, set: function(val) { + val ? this.mode |= readMode : this.mode &= ~readMode; + } }, write: { get: function() { + return (this.mode & writeMode) === writeMode; + }, set: function(val) { + val ? this.mode |= writeMode : this.mode &= ~writeMode; + } }, isFolder: { get: function() { + return FS.isDir(this.mode); + } }, isDevice: { get: function() { + return FS.isChrdev(this.mode); + } } }); + FS.FSNode = FSNode; + FS.staticInit(); + Module["FS_createPath"] = FS.createPath; + Module["FS_createDataFile"] = FS.createDataFile; + Module["FS_createPreloadedFile"] = FS.createPreloadedFile; + Module["FS_createLazyFile"] = FS.createLazyFile; + Module["FS_createDevice"] = FS.createDevice; + Module["FS_unlink"] = FS.unlink; + InternalError = Module["InternalError"] = extendError(Error, "InternalError"); + embind_init_charCodes(); + BindingError = Module["BindingError"] = extendError(Error, "BindingError"); + init_ClassHandle(); + init_RegisteredPointer(); + init_embind(); + UnboundTypeError = Module["UnboundTypeError"] = extendError(Error, "UnboundTypeError"); + init_emval(); + function intArrayFromString(stringy, dontAddNull, length) { + var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) + u8array.length = numBytesWritten; + return u8array; } - } -} - -/** - * @desc Metadata corresponding to a {@link Scene}. - * - * * Located in {@link Viewer#metaScene}. - * * Contains {@link MetaModel}s and {@link MetaObject}s. - * * [Scene Graphs user guide](https://github.com/xeokit/xeokit-sdk/wiki/Scene-Graphs) - * * [Scene graph example with metadata](http://xeokit.github.io/xeokit-sdk/examples/#sceneRepresentation_SceneGraph_metadata) - */ -class MetaScene { - - /** - * @private - */ - constructor(viewer, scene) { - - /** - * The {@link Viewer}. - * @property viewer - * @type {Viewer} - */ - this.viewer = viewer; - - /** - * The {@link Scene}. - * @property scene - * @type {Scene} - */ - this.scene = scene; - - /** - * The {@link MetaModel}s belonging to this MetaScene, each mapped to its {@link MetaModel#modelId}. - * - * @type {{String:MetaModel}} - */ - this.metaModels = {}; - - /** - * The {@link PropertySet}s belonging to this MetaScene, each mapped to its {@link PropertySet#id}. - * - * @type {{String:PropertySet}} - */ - this.propertySets = {}; - - /** - * The {@link MetaObject}s belonging to this MetaScene, each mapped to its {@link MetaObject#id}. - * - * @type {{String:MetaObject}} - */ - this.metaObjects = {}; - - /** - * The {@link MetaObject}s belonging to this MetaScene, each mapped to its {@link MetaObject#type}. - * - * @type {{String:MetaObject}} - */ - this.metaObjectsByType = {}; - - /** - * Tracks number of MetaObjects of each type. - * @private - */ - this._typeCounts = {}; - - /** - * Subscriptions to events sent with {@link fire}. - * @private - */ - this._eventSubs = {}; - } - - /** - * Subscribes to an event fired at this Viewer. - * - * @param {String} event The event - * @param {Function} callback Callback fired on the event - */ - on(event, callback) { - let subs = this._eventSubs[event]; - if (!subs) { - subs = []; - this._eventSubs[event] = subs; + var asmLibraryArg = { "y": ___assert_fail, "x": ___cxa_allocate_exception, "w": ___cxa_throw, "A": ___sys_fcntl64, "O": ___sys_ioctl, "P": ___sys_open, "Z": __embind_finalize_value_array, "o": __embind_finalize_value_object, "J": __embind_register_bigint, "W": __embind_register_bool, "r": __embind_register_class, "q": __embind_register_class_constructor, "b": __embind_register_class_function, "V": __embind_register_emval, "Y": __embind_register_enum, "t": __embind_register_enum_value, "D": __embind_register_float, "e": __embind_register_function, "n": __embind_register_integer, "j": __embind_register_memory_view, "E": __embind_register_std_string, "v": __embind_register_std_wstring, "_": __embind_register_value_array, "g": __embind_register_value_array_element, "p": __embind_register_value_object, "d": __embind_register_value_object_field, "X": __embind_register_void, "l": __emval_as, "F": __emval_call, "a": __emval_decref, "H": __emval_get_global, "m": __emval_get_property, "i": __emval_incref, "L": __emval_instanceof, "G": __emval_is_number, "z": __emval_new_array, "f": __emval_new_cstring, "s": __emval_new_object, "k": __emval_run_destructors, "h": __emval_set_property, "c": __emval_take_value, "C": _abort, "N": _clock_gettime, "M": _emscripten_memcpy_big, "u": _emscripten_resize_heap, "R": _environ_get, "S": _environ_sizes_get, "B": _fd_close, "U": _fd_read, "I": _fd_seek, "T": _fd_write, "K": _setTempRet0, "Q": _strftime_l }; + createWasm(); + Module["___wasm_call_ctors"] = function() { + return (Module["___wasm_call_ctors"] = Module["asm"]["aa"]).apply(null, arguments); + }; + Module["_main"] = function() { + return (Module["_main"] = Module["asm"]["ba"]).apply(null, arguments); + }; + var _malloc = Module["_malloc"] = function() { + return (_malloc = Module["_malloc"] = Module["asm"]["ca"]).apply(null, arguments); + }; + var _free = Module["_free"] = function() { + return (_free = Module["_free"] = Module["asm"]["da"]).apply(null, arguments); + }; + var ___getTypeName = Module["___getTypeName"] = function() { + return (___getTypeName = Module["___getTypeName"] = Module["asm"]["ea"]).apply(null, arguments); + }; + Module["___embind_register_native_and_builtin_types"] = function() { + return (Module["___embind_register_native_and_builtin_types"] = Module["asm"]["fa"]).apply(null, arguments); + }; + var ___errno_location = Module["___errno_location"] = function() { + return (___errno_location = Module["___errno_location"] = Module["asm"]["ga"]).apply(null, arguments); + }; + Module["dynCall_jiji"] = function() { + return (Module["dynCall_jiji"] = Module["asm"]["ia"]).apply(null, arguments); + }; + Module["dynCall_viijii"] = function() { + return (Module["dynCall_viijii"] = Module["asm"]["ja"]).apply(null, arguments); + }; + Module["dynCall_iiiiij"] = function() { + return (Module["dynCall_iiiiij"] = Module["asm"]["ka"]).apply(null, arguments); + }; + Module["dynCall_iiiiijj"] = function() { + return (Module["dynCall_iiiiijj"] = Module["asm"]["la"]).apply(null, arguments); + }; + Module["dynCall_iiiiiijj"] = function() { + return (Module["dynCall_iiiiiijj"] = Module["asm"]["ma"]).apply(null, arguments); + }; + Module["addRunDependency"] = addRunDependency; + Module["removeRunDependency"] = removeRunDependency; + Module["FS_createPath"] = FS.createPath; + Module["FS_createDataFile"] = FS.createDataFile; + Module["FS_createPreloadedFile"] = FS.createPreloadedFile; + Module["FS_createLazyFile"] = FS.createLazyFile; + Module["FS_createDevice"] = FS.createDevice; + Module["FS_unlink"] = FS.unlink; + Module["FS"] = FS; + var calledRun; + function ExitStatus(status) { + this.name = "ExitStatus"; + this.message = "Program terminated with exit(" + status + ")"; + this.status = status; } - subs.push(callback); - } - - /** - * Fires an event at this Viewer. - * - * @param {String} event Event name - * @param {Object} value Event parameters - */ - fire(event, value) { - const subs = this._eventSubs[event]; - if (subs) { - for (let i = 0, len = subs.length; i < len; i++) { - subs[i](value); + dependenciesFulfilled = function runCaller() { + if (!calledRun) + run(); + if (!calledRun) + dependenciesFulfilled = runCaller; + }; + function callMain(args) { + var entryFunction = Module["_main"]; + var argc = 0; + var argv = 0; + try { + var ret = entryFunction(argc, argv); + exit(ret, true); + } catch (e) { + if (e instanceof ExitStatus || e == "unwind") { + return; + } + var toLog = e; + if (e && typeof e === "object" && e.stack) { + toLog = [e, e.stack]; } + err("exception thrown: " + toLog); + quit_(1, e); + } finally { + } } - } - - /** - * Unsubscribes from an event fired at this Viewer. - * @param event - */ - off(event) { // TODO - - } - - /** - * Creates a {@link MetaModel} in this MetaScene. - * - * The MetaModel will contain a hierarchy of {@link MetaObject}s, created from the - * meta objects in ````metaModelData````. - * - * The meta object hierarchy in ````metaModelData```` is expected to be non-cyclic, with a single root. If the meta - * objects are cyclic, then this method will log an error and attempt to recover by creating a dummy root MetaObject - * of type "Model" and connecting all other MetaObjects as its direct children. If the meta objects contain multiple - * roots, then this method similarly attempts to recover by creating a dummy root MetaObject of type "Model" and - * connecting all the root MetaObjects as its children. - * - * @param {String} modelId ID for the new {@link MetaModel}, which will have {@link MetaModel#id} set to this value. - * @param {Object} metaModelData Data for the {@link MetaModel}. - * @param {Object} [options] Options for creating the {@link MetaModel}. - * @param {Object} [options.includeTypes] When provided, only create {@link MetaObject}s with types in this list. - * @param {Object} [options.excludeTypes] When provided, never create {@link MetaObject}s with types in this list. - * @param {Boolean} [options.globalizeObjectIds=false] Whether to globalize each {@link MetaObject#id}. Set this ````true```` when you need to load multiple instances of the same meta model, to avoid ID clashes between the meta objects in the different instances. - * @returns {MetaModel} The new MetaModel. - */ - createMetaModel(modelId, metaModelData, options = {}) { - - const projectId = metaModelData.projectId || "none"; - const revisionId = metaModelData.revisionId || "none"; - const newPropertySets = metaModelData.propertySets || []; - const newObjects = metaModelData.metaObjects || []; - const author = metaModelData.author; - const createdAt = metaModelData.createdAt; - const creatingApplication = metaModelData.creatingApplication; - const schema = metaModelData.schema; - // if (options.excludeTypes) { - // excludeTypes = {}; - // for (let i = 0, len = options.excludeTypes.length; i < len; i++) { - // includeTypes[options.excludeTypes[i]] = true; - // } - // } - - const metaModel = new MetaModel(this, modelId, projectId, revisionId, author, createdAt, creatingApplication, schema, [], null); - - this.metaModels[modelId] = metaModel; - - for (let i = 0, len = newPropertySets.length; i < len; i++) { - const propertySetCfg = newPropertySets[i]; - const propertySetId = propertySetCfg.id; - const propertySet = new PropertySet(propertySetId, propertySetCfg.originalSystemId, propertySetCfg.name, propertySetCfg.type, propertySetCfg.properties); - metaModel.propertySets[propertySetId] = propertySet; - this.propertySets[propertySetId] = propertySet; + function run(args) { + if (runDependencies > 0) { + return; + } + preRun(); + if (runDependencies > 0) { + return; + } + function doRun() { + if (calledRun) + return; + calledRun = true; + Module["calledRun"] = true; + if (ABORT) + return; + initRuntime(); + preMain(); + readyPromiseResolve(Module); + if (Module["onRuntimeInitialized"]) + Module["onRuntimeInitialized"](); + if (shouldRunNow) + callMain(); + postRun(); + } + if (Module["setStatus"]) { + Module["setStatus"]("Running..."); + setTimeout(function() { + setTimeout(function() { + Module["setStatus"](""); + }, 1); + doRun(); + }, 1); + } else { + doRun(); + } } - - const rootMetaObjects = []; - - for (let i = 0, len = newObjects.length; i < len; i++) { - const newObject = newObjects[i]; - if (newObject.parent === undefined || newObject.parent === null) { - rootMetaObjects.push(newObject); - } + Module["run"] = run; + function exit(status, implicit) { + if (keepRuntimeAlive()) ; else { + if (Module["onExit"]) + Module["onExit"](status); + ABORT = true; + } + quit_(status, new ExitStatus(status)); } - - if (rootMetaObjects.length === 0) { - this.scene.error("Cyclic containment hierarchy found in metamodel - will flatten the hierarchy and insert fake 'Model' root"); - const fakeRoot = { - "id": modelId + ".fakeRoot", - "name": modelId, - "type": "Model", - "parent": null - }; - for (let i = 0, len = newObjects.length; i < len; i++) { - newObjects[i].parent = fakeRoot.id; - } - newObjects.push(fakeRoot); + if (Module["preInit"]) { + if (typeof Module["preInit"] == "function") + Module["preInit"] = [Module["preInit"]]; + while (Module["preInit"].length > 0) { + Module["preInit"].pop()(); + } } + var shouldRunNow = true; + if (Module["noInitialRun"]) + shouldRunNow = false; + run(); + return WebIFCWasm3.ready; + }; + }(); + if (typeof exports === "object" && typeof module === "object") + module.exports = WebIFCWasm2; + else if (typeof define === "function" && define["amd"]) + define([], function() { + return WebIFCWasm2; + }); + else if (typeof exports === "object") + exports["WebIFCWasm"] = WebIFCWasm2; + } +}); + +// dist/ifc2x4.ts +var IFCACTIONREQUEST = 3821786052; +var IFCACTOR = 2296667514; +var IFCACTORROLE = 3630933823; +var IFCACTUATOR = 4288193352; +var IFCACTUATORTYPE = 2874132201; +var IFCADDRESS = 618182010; +var IFCADVANCEDBREP = 1635779807; +var IFCADVANCEDBREPWITHVOIDS = 2603310189; +var IFCADVANCEDFACE = 3406155212; +var IFCAIRTERMINAL = 1634111441; +var IFCAIRTERMINALBOX = 177149247; +var IFCAIRTERMINALBOXTYPE = 1411407467; +var IFCAIRTERMINALTYPE = 3352864051; +var IFCAIRTOAIRHEATRECOVERY = 2056796094; +var IFCAIRTOAIRHEATRECOVERYTYPE = 1871374353; +var IFCALARM = 3087945054; +var IFCALARMTYPE = 3001207471; +var IFCALIGNMENT = 325726236; +var IFCALIGNMENT2DHORIZONTAL = 749761778; +var IFCALIGNMENT2DHORIZONTALSEGMENT = 3199563722; +var IFCALIGNMENT2DSEGMENT = 2483840362; +var IFCALIGNMENT2DVERSEGCIRCULARARC = 3379348081; +var IFCALIGNMENT2DVERSEGLINE = 3239324667; +var IFCALIGNMENT2DVERSEGPARABOLICARC = 4263986512; +var IFCALIGNMENT2DVERTICAL = 53199957; +var IFCALIGNMENT2DVERTICALSEGMENT = 2029264950; +var IFCALIGNMENTCURVE = 3512275521; +var IFCANNOTATION = 1674181508; +var IFCANNOTATIONFILLAREA = 669184980; +var IFCAPPLICATION = 639542469; +var IFCAPPLIEDVALUE = 411424972; +var IFCAPPROVAL = 130549933; +var IFCAPPROVALRELATIONSHIP = 3869604511; +var IFCARBITRARYCLOSEDPROFILEDEF = 3798115385; +var IFCARBITRARYOPENPROFILEDEF = 1310608509; +var IFCARBITRARYPROFILEDEFWITHVOIDS = 2705031697; +var IFCASSET = 3460190687; +var IFCASYMMETRICISHAPEPROFILEDEF = 3207858831; +var IFCAUDIOVISUALAPPLIANCE = 277319702; +var IFCAUDIOVISUALAPPLIANCETYPE = 1532957894; +var IFCAXIS1PLACEMENT = 4261334040; +var IFCAXIS2PLACEMENT2D = 3125803723; +var IFCAXIS2PLACEMENT3D = 2740243338; +var IFCBSPLINECURVE = 1967976161; +var IFCBSPLINECURVEWITHKNOTS = 2461110595; +var IFCBSPLINESURFACE = 2887950389; +var IFCBSPLINESURFACEWITHKNOTS = 167062518; +var IFCBEAM = 753842376; +var IFCBEAMSTANDARDCASE = 2906023776; +var IFCBEAMTYPE = 819618141; +var IFCBEARING = 4196446775; +var IFCBEARINGTYPE = 3649138523; +var IFCBLOBTEXTURE = 616511568; +var IFCBLOCK = 1334484129; +var IFCBOILER = 32344328; +var IFCBOILERTYPE = 231477066; +var IFCBOOLEANCLIPPINGRESULT = 3649129432; +var IFCBOOLEANRESULT = 2736907675; +var IFCBOUNDARYCONDITION = 4037036970; +var IFCBOUNDARYCURVE = 1136057603; +var IFCBOUNDARYEDGECONDITION = 1560379544; +var IFCBOUNDARYFACECONDITION = 3367102660; +var IFCBOUNDARYNODECONDITION = 1387855156; +var IFCBOUNDARYNODECONDITIONWARPING = 2069777674; +var IFCBOUNDEDCURVE = 1260505505; +var IFCBOUNDEDSURFACE = 4182860854; +var IFCBOUNDINGBOX = 2581212453; +var IFCBOXEDHALFSPACE = 2713105998; +var IFCBRIDGE = 644574406; +var IFCBRIDGEPART = 963979645; +var IFCBUILDING = 4031249490; +var IFCBUILDINGELEMENT = 3299480353; +var IFCBUILDINGELEMENTPART = 2979338954; +var IFCBUILDINGELEMENTPARTTYPE = 39481116; +var IFCBUILDINGELEMENTPROXY = 1095909175; +var IFCBUILDINGELEMENTPROXYTYPE = 1909888760; +var IFCBUILDINGELEMENTTYPE = 1950629157; +var IFCBUILDINGSTOREY = 3124254112; +var IFCBUILDINGSYSTEM = 1177604601; +var IFCBURNER = 2938176219; +var IFCBURNERTYPE = 2188180465; +var IFCCSHAPEPROFILEDEF = 2898889636; +var IFCCABLECARRIERFITTING = 635142910; +var IFCCABLECARRIERFITTINGTYPE = 395041908; +var IFCCABLECARRIERSEGMENT = 3758799889; +var IFCCABLECARRIERSEGMENTTYPE = 3293546465; +var IFCCABLEFITTING = 1051757585; +var IFCCABLEFITTINGTYPE = 2674252688; +var IFCCABLESEGMENT = 4217484030; +var IFCCABLESEGMENTTYPE = 1285652485; +var IFCCAISSONFOUNDATION = 3999819293; +var IFCCAISSONFOUNDATIONTYPE = 3203706013; +var IFCCARTESIANPOINT = 1123145078; +var IFCCARTESIANPOINTLIST = 574549367; +var IFCCARTESIANPOINTLIST2D = 1675464909; +var IFCCARTESIANPOINTLIST3D = 2059837836; +var IFCCARTESIANTRANSFORMATIONOPERATOR = 59481748; +var IFCCARTESIANTRANSFORMATIONOPERATOR2D = 3749851601; +var IFCCARTESIANTRANSFORMATIONOPERATOR2DNONUNIFORM = 3486308946; +var IFCCARTESIANTRANSFORMATIONOPERATOR3D = 3331915920; +var IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM = 1416205885; +var IFCCENTERLINEPROFILEDEF = 3150382593; +var IFCCHILLER = 3902619387; +var IFCCHILLERTYPE = 2951183804; +var IFCCHIMNEY = 3296154744; +var IFCCHIMNEYTYPE = 2197970202; +var IFCCIRCLE = 2611217952; +var IFCCIRCLEHOLLOWPROFILEDEF = 2937912522; +var IFCCIRCLEPROFILEDEF = 1383045692; +var IFCCIRCULARARCSEGMENT2D = 1062206242; +var IFCCIVILELEMENT = 1677625105; +var IFCCIVILELEMENTTYPE = 3893394355; +var IFCCLASSIFICATION = 747523909; +var IFCCLASSIFICATIONREFERENCE = 647927063; +var IFCCLOSEDSHELL = 2205249479; +var IFCCOIL = 639361253; +var IFCCOILTYPE = 2301859152; +var IFCCOLOURRGB = 776857604; +var IFCCOLOURRGBLIST = 3285139300; +var IFCCOLOURSPECIFICATION = 3264961684; +var IFCCOLUMN = 843113511; +var IFCCOLUMNSTANDARDCASE = 905975707; +var IFCCOLUMNTYPE = 300633059; +var IFCCOMMUNICATIONSAPPLIANCE = 3221913625; +var IFCCOMMUNICATIONSAPPLIANCETYPE = 400855858; +var IFCCOMPLEXPROPERTY = 2542286263; +var IFCCOMPLEXPROPERTYTEMPLATE = 3875453745; +var IFCCOMPOSITECURVE = 3732776249; +var IFCCOMPOSITECURVEONSURFACE = 15328376; +var IFCCOMPOSITECURVESEGMENT = 2485617015; +var IFCCOMPOSITEPROFILEDEF = 1485152156; +var IFCCOMPRESSOR = 3571504051; +var IFCCOMPRESSORTYPE = 3850581409; +var IFCCONDENSER = 2272882330; +var IFCCONDENSERTYPE = 2816379211; +var IFCCONIC = 2510884976; +var IFCCONNECTEDFACESET = 370225590; +var IFCCONNECTIONCURVEGEOMETRY = 1981873012; +var IFCCONNECTIONGEOMETRY = 2859738748; +var IFCCONNECTIONPOINTECCENTRICITY = 45288368; +var IFCCONNECTIONPOINTGEOMETRY = 2614616156; +var IFCCONNECTIONSURFACEGEOMETRY = 2732653382; +var IFCCONNECTIONVOLUMEGEOMETRY = 775493141; +var IFCCONSTRAINT = 1959218052; +var IFCCONSTRUCTIONEQUIPMENTRESOURCE = 3898045240; +var IFCCONSTRUCTIONEQUIPMENTRESOURCETYPE = 2185764099; +var IFCCONSTRUCTIONMATERIALRESOURCE = 1060000209; +var IFCCONSTRUCTIONMATERIALRESOURCETYPE = 4105962743; +var IFCCONSTRUCTIONPRODUCTRESOURCE = 488727124; +var IFCCONSTRUCTIONPRODUCTRESOURCETYPE = 1525564444; +var IFCCONSTRUCTIONRESOURCE = 2559216714; +var IFCCONSTRUCTIONRESOURCETYPE = 2574617495; +var IFCCONTEXT = 3419103109; +var IFCCONTEXTDEPENDENTUNIT = 3050246964; +var IFCCONTROL = 3293443760; +var IFCCONTROLLER = 25142252; +var IFCCONTROLLERTYPE = 578613899; +var IFCCONVERSIONBASEDUNIT = 2889183280; +var IFCCONVERSIONBASEDUNITWITHOFFSET = 2713554722; +var IFCCOOLEDBEAM = 4136498852; +var IFCCOOLEDBEAMTYPE = 335055490; +var IFCCOOLINGTOWER = 3640358203; +var IFCCOOLINGTOWERTYPE = 2954562838; +var IFCCOORDINATEOPERATION = 1785450214; +var IFCCOORDINATEREFERENCESYSTEM = 1466758467; +var IFCCOSTITEM = 3895139033; +var IFCCOSTSCHEDULE = 1419761937; +var IFCCOSTVALUE = 602808272; +var IFCCOVERING = 1973544240; +var IFCCOVERINGTYPE = 1916426348; +var IFCCREWRESOURCE = 3295246426; +var IFCCREWRESOURCETYPE = 1815067380; +var IFCCSGPRIMITIVE3D = 2506170314; +var IFCCSGSOLID = 2147822146; +var IFCCURRENCYRELATIONSHIP = 539742890; +var IFCCURTAINWALL = 3495092785; +var IFCCURTAINWALLTYPE = 1457835157; +var IFCCURVE = 2601014836; +var IFCCURVEBOUNDEDPLANE = 2827736869; +var IFCCURVEBOUNDEDSURFACE = 2629017746; +var IFCCURVESEGMENT2D = 1186437898; +var IFCCURVESTYLE = 3800577675; +var IFCCURVESTYLEFONT = 1105321065; +var IFCCURVESTYLEFONTANDSCALING = 2367409068; +var IFCCURVESTYLEFONTPATTERN = 3510044353; +var IFCCYLINDRICALSURFACE = 1213902940; +var IFCDAMPER = 4074379575; +var IFCDAMPERTYPE = 3961806047; +var IFCDEEPFOUNDATION = 3426335179; +var IFCDEEPFOUNDATIONTYPE = 1306400036; +var IFCDERIVEDPROFILEDEF = 3632507154; +var IFCDERIVEDUNIT = 1765591967; +var IFCDERIVEDUNITELEMENT = 1045800335; +var IFCDIMENSIONALEXPONENTS = 2949456006; +var IFCDIRECTION = 32440307; +var IFCDISCRETEACCESSORY = 1335981549; +var IFCDISCRETEACCESSORYTYPE = 2635815018; +var IFCDISTANCEEXPRESSION = 1945343521; +var IFCDISTRIBUTIONCHAMBERELEMENT = 1052013943; +var IFCDISTRIBUTIONCHAMBERELEMENTTYPE = 1599208980; +var IFCDISTRIBUTIONCIRCUIT = 562808652; +var IFCDISTRIBUTIONCONTROLELEMENT = 1062813311; +var IFCDISTRIBUTIONCONTROLELEMENTTYPE = 2063403501; +var IFCDISTRIBUTIONELEMENT = 1945004755; +var IFCDISTRIBUTIONELEMENTTYPE = 3256556792; +var IFCDISTRIBUTIONFLOWELEMENT = 3040386961; +var IFCDISTRIBUTIONFLOWELEMENTTYPE = 3849074793; +var IFCDISTRIBUTIONPORT = 3041715199; +var IFCDISTRIBUTIONSYSTEM = 3205830791; +var IFCDOCUMENTINFORMATION = 1154170062; +var IFCDOCUMENTINFORMATIONRELATIONSHIP = 770865208; +var IFCDOCUMENTREFERENCE = 3732053477; +var IFCDOOR = 395920057; +var IFCDOORLININGPROPERTIES = 2963535650; +var IFCDOORPANELPROPERTIES = 1714330368; +var IFCDOORSTANDARDCASE = 3242481149; +var IFCDOORSTYLE = 526551008; +var IFCDOORTYPE = 2323601079; +var IFCDRAUGHTINGPREDEFINEDCOLOUR = 445594917; +var IFCDRAUGHTINGPREDEFINEDCURVEFONT = 4006246654; +var IFCDUCTFITTING = 342316401; +var IFCDUCTFITTINGTYPE = 869906466; +var IFCDUCTSEGMENT = 3518393246; +var IFCDUCTSEGMENTTYPE = 3760055223; +var IFCDUCTSILENCER = 1360408905; +var IFCDUCTSILENCERTYPE = 2030761528; +var IFCEDGE = 3900360178; +var IFCEDGECURVE = 476780140; +var IFCEDGELOOP = 1472233963; +var IFCELECTRICAPPLIANCE = 1904799276; +var IFCELECTRICAPPLIANCETYPE = 663422040; +var IFCELECTRICDISTRIBUTIONBOARD = 862014818; +var IFCELECTRICDISTRIBUTIONBOARDTYPE = 2417008758; +var IFCELECTRICFLOWSTORAGEDEVICE = 3310460725; +var IFCELECTRICFLOWSTORAGEDEVICETYPE = 3277789161; +var IFCELECTRICGENERATOR = 264262732; +var IFCELECTRICGENERATORTYPE = 1534661035; +var IFCELECTRICMOTOR = 402227799; +var IFCELECTRICMOTORTYPE = 1217240411; +var IFCELECTRICTIMECONTROL = 1003880860; +var IFCELECTRICTIMECONTROLTYPE = 712377611; +var IFCELEMENT = 1758889154; +var IFCELEMENTASSEMBLY = 4123344466; +var IFCELEMENTASSEMBLYTYPE = 2397081782; +var IFCELEMENTCOMPONENT = 1623761950; +var IFCELEMENTCOMPONENTTYPE = 2590856083; +var IFCELEMENTQUANTITY = 1883228015; +var IFCELEMENTTYPE = 339256511; +var IFCELEMENTARYSURFACE = 2777663545; +var IFCELLIPSE = 1704287377; +var IFCELLIPSEPROFILEDEF = 2835456948; +var IFCENERGYCONVERSIONDEVICE = 1658829314; +var IFCENERGYCONVERSIONDEVICETYPE = 2107101300; +var IFCENGINE = 2814081492; +var IFCENGINETYPE = 132023988; +var IFCEVAPORATIVECOOLER = 3747195512; +var IFCEVAPORATIVECOOLERTYPE = 3174744832; +var IFCEVAPORATOR = 484807127; +var IFCEVAPORATORTYPE = 3390157468; +var IFCEVENT = 4148101412; +var IFCEVENTTIME = 211053100; +var IFCEVENTTYPE = 4024345920; +var IFCEXTENDEDPROPERTIES = 297599258; +var IFCEXTERNALINFORMATION = 4294318154; +var IFCEXTERNALREFERENCE = 3200245327; +var IFCEXTERNALREFERENCERELATIONSHIP = 1437805879; +var IFCEXTERNALSPATIALELEMENT = 1209101575; +var IFCEXTERNALSPATIALSTRUCTUREELEMENT = 2853485674; +var IFCEXTERNALLYDEFINEDHATCHSTYLE = 2242383968; +var IFCEXTERNALLYDEFINEDSURFACESTYLE = 1040185647; +var IFCEXTERNALLYDEFINEDTEXTFONT = 3548104201; +var IFCEXTRUDEDAREASOLID = 477187591; +var IFCEXTRUDEDAREASOLIDTAPERED = 2804161546; +var IFCFACE = 2556980723; +var IFCFACEBASEDSURFACEMODEL = 2047409740; +var IFCFACEBOUND = 1809719519; +var IFCFACEOUTERBOUND = 803316827; +var IFCFACESURFACE = 3008276851; +var IFCFACETEDBREP = 807026263; +var IFCFACETEDBREPWITHVOIDS = 3737207727; +var IFCFACILITY = 24185140; +var IFCFACILITYPART = 1310830890; +var IFCFAILURECONNECTIONCONDITION = 4219587988; +var IFCFAN = 3415622556; +var IFCFANTYPE = 346874300; +var IFCFASTENER = 647756555; +var IFCFASTENERTYPE = 2489546625; +var IFCFEATUREELEMENT = 2827207264; +var IFCFEATUREELEMENTADDITION = 2143335405; +var IFCFEATUREELEMENTSUBTRACTION = 1287392070; +var IFCFILLAREASTYLE = 738692330; +var IFCFILLAREASTYLEHATCHING = 374418227; +var IFCFILLAREASTYLETILES = 315944413; +var IFCFILTER = 819412036; +var IFCFILTERTYPE = 1810631287; +var IFCFIRESUPPRESSIONTERMINAL = 1426591983; +var IFCFIRESUPPRESSIONTERMINALTYPE = 4222183408; +var IFCFIXEDREFERENCESWEPTAREASOLID = 2652556860; +var IFCFLOWCONTROLLER = 2058353004; +var IFCFLOWCONTROLLERTYPE = 3907093117; +var IFCFLOWFITTING = 4278956645; +var IFCFLOWFITTINGTYPE = 3198132628; +var IFCFLOWINSTRUMENT = 182646315; +var IFCFLOWINSTRUMENTTYPE = 4037862832; +var IFCFLOWMETER = 2188021234; +var IFCFLOWMETERTYPE = 3815607619; +var IFCFLOWMOVINGDEVICE = 3132237377; +var IFCFLOWMOVINGDEVICETYPE = 1482959167; +var IFCFLOWSEGMENT = 987401354; +var IFCFLOWSEGMENTTYPE = 1834744321; +var IFCFLOWSTORAGEDEVICE = 707683696; +var IFCFLOWSTORAGEDEVICETYPE = 1339347760; +var IFCFLOWTERMINAL = 2223149337; +var IFCFLOWTERMINALTYPE = 2297155007; +var IFCFLOWTREATMENTDEVICE = 3508470533; +var IFCFLOWTREATMENTDEVICETYPE = 3009222698; +var IFCFOOTING = 900683007; +var IFCFOOTINGTYPE = 1893162501; +var IFCFURNISHINGELEMENT = 263784265; +var IFCFURNISHINGELEMENTTYPE = 4238390223; +var IFCFURNITURE = 1509553395; +var IFCFURNITURETYPE = 1268542332; +var IFCGEOGRAPHICELEMENT = 3493046030; +var IFCGEOGRAPHICELEMENTTYPE = 4095422895; +var IFCGEOMETRICCURVESET = 987898635; +var IFCGEOMETRICREPRESENTATIONCONTEXT = 3448662350; +var IFCGEOMETRICREPRESENTATIONITEM = 2453401579; +var IFCGEOMETRICREPRESENTATIONSUBCONTEXT = 4142052618; +var IFCGEOMETRICSET = 3590301190; +var IFCGRID = 3009204131; +var IFCGRIDAXIS = 852622518; +var IFCGRIDPLACEMENT = 178086475; +var IFCGROUP = 2706460486; +var IFCHALFSPACESOLID = 812098782; +var IFCHEATEXCHANGER = 3319311131; +var IFCHEATEXCHANGERTYPE = 1251058090; +var IFCHUMIDIFIER = 2068733104; +var IFCHUMIDIFIERTYPE = 1806887404; +var IFCISHAPEPROFILEDEF = 1484403080; +var IFCIMAGETEXTURE = 3905492369; +var IFCINDEXEDCOLOURMAP = 3570813810; +var IFCINDEXEDPOLYCURVE = 2571569899; +var IFCINDEXEDPOLYGONALFACE = 178912537; +var IFCINDEXEDPOLYGONALFACEWITHVOIDS = 2294589976; +var IFCINDEXEDTEXTUREMAP = 1437953363; +var IFCINDEXEDTRIANGLETEXTUREMAP = 2133299955; +var IFCINTERCEPTOR = 4175244083; +var IFCINTERCEPTORTYPE = 3946677679; +var IFCINTERSECTIONCURVE = 3113134337; +var IFCINVENTORY = 2391368822; +var IFCIRREGULARTIMESERIES = 3741457305; +var IFCIRREGULARTIMESERIESVALUE = 3020489413; +var IFCJUNCTIONBOX = 2176052936; +var IFCJUNCTIONBOXTYPE = 4288270099; +var IFCLSHAPEPROFILEDEF = 572779678; +var IFCLABORRESOURCE = 3827777499; +var IFCLABORRESOURCETYPE = 428585644; +var IFCLAGTIME = 1585845231; +var IFCLAMP = 76236018; +var IFCLAMPTYPE = 1051575348; +var IFCLIBRARYINFORMATION = 2655187982; +var IFCLIBRARYREFERENCE = 3452421091; +var IFCLIGHTDISTRIBUTIONDATA = 4162380809; +var IFCLIGHTFIXTURE = 629592764; +var IFCLIGHTFIXTURETYPE = 1161773419; +var IFCLIGHTINTENSITYDISTRIBUTION = 1566485204; +var IFCLIGHTSOURCE = 1402838566; +var IFCLIGHTSOURCEAMBIENT = 125510826; +var IFCLIGHTSOURCEDIRECTIONAL = 2604431987; +var IFCLIGHTSOURCEGONIOMETRIC = 4266656042; +var IFCLIGHTSOURCEPOSITIONAL = 1520743889; +var IFCLIGHTSOURCESPOT = 3422422726; +var IFCLINE = 1281925730; +var IFCLINESEGMENT2D = 3092502836; +var IFCLINEARPLACEMENT = 388784114; +var IFCLINEARPOSITIONINGELEMENT = 1154579445; +var IFCLOCALPLACEMENT = 2624227202; +var IFCLOOP = 1008929658; +var IFCMANIFOLDSOLIDBREP = 1425443689; +var IFCMAPCONVERSION = 3057273783; +var IFCMAPPEDITEM = 2347385850; +var IFCMATERIAL = 1838606355; +var IFCMATERIALCLASSIFICATIONRELATIONSHIP = 1847130766; +var IFCMATERIALCONSTITUENT = 3708119e3; +var IFCMATERIALCONSTITUENTSET = 2852063980; +var IFCMATERIALDEFINITION = 760658860; +var IFCMATERIALDEFINITIONREPRESENTATION = 2022407955; +var IFCMATERIALLAYER = 248100487; +var IFCMATERIALLAYERSET = 3303938423; +var IFCMATERIALLAYERSETUSAGE = 1303795690; +var IFCMATERIALLAYERWITHOFFSETS = 1847252529; +var IFCMATERIALLIST = 2199411900; +var IFCMATERIALPROFILE = 2235152071; +var IFCMATERIALPROFILESET = 164193824; +var IFCMATERIALPROFILESETUSAGE = 3079605661; +var IFCMATERIALPROFILESETUSAGETAPERING = 3404854881; +var IFCMATERIALPROFILEWITHOFFSETS = 552965576; +var IFCMATERIALPROPERTIES = 3265635763; +var IFCMATERIALRELATIONSHIP = 853536259; +var IFCMATERIALUSAGEDEFINITION = 1507914824; +var IFCMEASUREWITHUNIT = 2597039031; +var IFCMECHANICALFASTENER = 377706215; +var IFCMECHANICALFASTENERTYPE = 2108223431; +var IFCMEDICALDEVICE = 1437502449; +var IFCMEDICALDEVICETYPE = 1114901282; +var IFCMEMBER = 1073191201; +var IFCMEMBERSTANDARDCASE = 1911478936; +var IFCMEMBERTYPE = 3181161470; +var IFCMETRIC = 3368373690; +var IFCMIRROREDPROFILEDEF = 2998442950; +var IFCMONETARYUNIT = 2706619895; +var IFCMOTORCONNECTION = 2474470126; +var IFCMOTORCONNECTIONTYPE = 977012517; +var IFCNAMEDUNIT = 1918398963; +var IFCOBJECT = 3888040117; +var IFCOBJECTDEFINITION = 219451334; +var IFCOBJECTPLACEMENT = 3701648758; +var IFCOBJECTIVE = 2251480897; +var IFCOCCUPANT = 4143007308; +var IFCOFFSETCURVE = 590820931; +var IFCOFFSETCURVE2D = 3388369263; +var IFCOFFSETCURVE3D = 3505215534; +var IFCOFFSETCURVEBYDISTANCES = 2485787929; +var IFCOPENSHELL = 2665983363; +var IFCOPENINGELEMENT = 3588315303; +var IFCOPENINGSTANDARDCASE = 3079942009; +var IFCORGANIZATION = 4251960020; +var IFCORGANIZATIONRELATIONSHIP = 1411181986; +var IFCORIENTATIONEXPRESSION = 643959842; +var IFCORIENTEDEDGE = 1029017970; +var IFCOUTERBOUNDARYCURVE = 144952367; +var IFCOUTLET = 3694346114; +var IFCOUTLETTYPE = 2837617999; +var IFCOWNERHISTORY = 1207048766; +var IFCPARAMETERIZEDPROFILEDEF = 2529465313; +var IFCPATH = 2519244187; +var IFCPCURVE = 1682466193; +var IFCPERFORMANCEHISTORY = 2382730787; +var IFCPERMEABLECOVERINGPROPERTIES = 3566463478; +var IFCPERMIT = 3327091369; +var IFCPERSON = 2077209135; +var IFCPERSONANDORGANIZATION = 101040310; +var IFCPHYSICALCOMPLEXQUANTITY = 3021840470; +var IFCPHYSICALQUANTITY = 2483315170; +var IFCPHYSICALSIMPLEQUANTITY = 2226359599; +var IFCPILE = 1687234759; +var IFCPILETYPE = 1158309216; +var IFCPIPEFITTING = 310824031; +var IFCPIPEFITTINGTYPE = 804291784; +var IFCPIPESEGMENT = 3612865200; +var IFCPIPESEGMENTTYPE = 4231323485; +var IFCPIXELTEXTURE = 597895409; +var IFCPLACEMENT = 2004835150; +var IFCPLANARBOX = 603570806; +var IFCPLANAREXTENT = 1663979128; +var IFCPLANE = 220341763; +var IFCPLATE = 3171933400; +var IFCPLATESTANDARDCASE = 1156407060; +var IFCPLATETYPE = 4017108033; +var IFCPOINT = 2067069095; +var IFCPOINTONCURVE = 4022376103; +var IFCPOINTONSURFACE = 1423911732; +var IFCPOLYLOOP = 2924175390; +var IFCPOLYGONALBOUNDEDHALFSPACE = 2775532180; +var IFCPOLYGONALFACESET = 2839578677; +var IFCPOLYLINE = 3724593414; +var IFCPORT = 3740093272; +var IFCPOSITIONINGELEMENT = 1946335990; +var IFCPOSTALADDRESS = 3355820592; +var IFCPREDEFINEDCOLOUR = 759155922; +var IFCPREDEFINEDCURVEFONT = 2559016684; +var IFCPREDEFINEDITEM = 3727388367; +var IFCPREDEFINEDPROPERTIES = 3778827333; +var IFCPREDEFINEDPROPERTYSET = 3967405729; +var IFCPREDEFINEDTEXTFONT = 1775413392; +var IFCPRESENTATIONITEM = 677532197; +var IFCPRESENTATIONLAYERASSIGNMENT = 2022622350; +var IFCPRESENTATIONLAYERWITHSTYLE = 1304840413; +var IFCPRESENTATIONSTYLE = 3119450353; +var IFCPRESENTATIONSTYLEASSIGNMENT = 2417041796; +var IFCPROCEDURE = 2744685151; +var IFCPROCEDURETYPE = 569719735; +var IFCPROCESS = 2945172077; +var IFCPRODUCT = 4208778838; +var IFCPRODUCTDEFINITIONSHAPE = 673634403; +var IFCPRODUCTREPRESENTATION = 2095639259; +var IFCPROFILEDEF = 3958567839; +var IFCPROFILEPROPERTIES = 2802850158; +var IFCPROJECT = 103090709; +var IFCPROJECTLIBRARY = 653396225; +var IFCPROJECTORDER = 2904328755; +var IFCPROJECTEDCRS = 3843373140; +var IFCPROJECTIONELEMENT = 3651124850; +var IFCPROPERTY = 2598011224; +var IFCPROPERTYABSTRACTION = 986844984; +var IFCPROPERTYBOUNDEDVALUE = 871118103; +var IFCPROPERTYDEFINITION = 1680319473; +var IFCPROPERTYDEPENDENCYRELATIONSHIP = 148025276; +var IFCPROPERTYENUMERATEDVALUE = 4166981789; +var IFCPROPERTYENUMERATION = 3710013099; +var IFCPROPERTYLISTVALUE = 2752243245; +var IFCPROPERTYREFERENCEVALUE = 941946838; +var IFCPROPERTYSET = 1451395588; +var IFCPROPERTYSETDEFINITION = 3357820518; +var IFCPROPERTYSETTEMPLATE = 492091185; +var IFCPROPERTYSINGLEVALUE = 3650150729; +var IFCPROPERTYTABLEVALUE = 110355661; +var IFCPROPERTYTEMPLATE = 3521284610; +var IFCPROPERTYTEMPLATEDEFINITION = 1482703590; +var IFCPROTECTIVEDEVICE = 738039164; +var IFCPROTECTIVEDEVICETRIPPINGUNIT = 2295281155; +var IFCPROTECTIVEDEVICETRIPPINGUNITTYPE = 655969474; +var IFCPROTECTIVEDEVICETYPE = 1842657554; +var IFCPROXY = 3219374653; +var IFCPUMP = 90941305; +var IFCPUMPTYPE = 2250791053; +var IFCQUANTITYAREA = 2044713172; +var IFCQUANTITYCOUNT = 2093928680; +var IFCQUANTITYLENGTH = 931644368; +var IFCQUANTITYSET = 2090586900; +var IFCQUANTITYTIME = 3252649465; +var IFCQUANTITYVOLUME = 2405470396; +var IFCQUANTITYWEIGHT = 825690147; +var IFCRAILING = 2262370178; +var IFCRAILINGTYPE = 2893384427; +var IFCRAMP = 3024970846; +var IFCRAMPFLIGHT = 3283111854; +var IFCRAMPFLIGHTTYPE = 2324767716; +var IFCRAMPTYPE = 1469900589; +var IFCRATIONALBSPLINECURVEWITHKNOTS = 1232101972; +var IFCRATIONALBSPLINESURFACEWITHKNOTS = 683857671; +var IFCRECTANGLEHOLLOWPROFILEDEF = 2770003689; +var IFCRECTANGLEPROFILEDEF = 3615266464; +var IFCRECTANGULARPYRAMID = 2798486643; +var IFCRECTANGULARTRIMMEDSURFACE = 3454111270; +var IFCRECURRENCEPATTERN = 3915482550; +var IFCREFERENCE = 2433181523; +var IFCREFERENT = 4021432810; +var IFCREGULARTIMESERIES = 3413951693; +var IFCREINFORCEMENTBARPROPERTIES = 1580146022; +var IFCREINFORCEMENTDEFINITIONPROPERTIES = 3765753017; +var IFCREINFORCINGBAR = 979691226; +var IFCREINFORCINGBARTYPE = 2572171363; +var IFCREINFORCINGELEMENT = 3027567501; +var IFCREINFORCINGELEMENTTYPE = 964333572; +var IFCREINFORCINGMESH = 2320036040; +var IFCREINFORCINGMESHTYPE = 2310774935; +var IFCRELAGGREGATES = 160246688; +var IFCRELASSIGNS = 3939117080; +var IFCRELASSIGNSTOACTOR = 1683148259; +var IFCRELASSIGNSTOCONTROL = 2495723537; +var IFCRELASSIGNSTOGROUP = 1307041759; +var IFCRELASSIGNSTOGROUPBYFACTOR = 1027710054; +var IFCRELASSIGNSTOPROCESS = 4278684876; +var IFCRELASSIGNSTOPRODUCT = 2857406711; +var IFCRELASSIGNSTORESOURCE = 205026976; +var IFCRELASSOCIATES = 1865459582; +var IFCRELASSOCIATESAPPROVAL = 4095574036; +var IFCRELASSOCIATESCLASSIFICATION = 919958153; +var IFCRELASSOCIATESCONSTRAINT = 2728634034; +var IFCRELASSOCIATESDOCUMENT = 982818633; +var IFCRELASSOCIATESLIBRARY = 3840914261; +var IFCRELASSOCIATESMATERIAL = 2655215786; +var IFCRELCONNECTS = 826625072; +var IFCRELCONNECTSELEMENTS = 1204542856; +var IFCRELCONNECTSPATHELEMENTS = 3945020480; +var IFCRELCONNECTSPORTTOELEMENT = 4201705270; +var IFCRELCONNECTSPORTS = 3190031847; +var IFCRELCONNECTSSTRUCTURALACTIVITY = 2127690289; +var IFCRELCONNECTSSTRUCTURALMEMBER = 1638771189; +var IFCRELCONNECTSWITHECCENTRICITY = 504942748; +var IFCRELCONNECTSWITHREALIZINGELEMENTS = 3678494232; +var IFCRELCONTAINEDINSPATIALSTRUCTURE = 3242617779; +var IFCRELCOVERSBLDGELEMENTS = 886880790; +var IFCRELCOVERSSPACES = 2802773753; +var IFCRELDECLARES = 2565941209; +var IFCRELDECOMPOSES = 2551354335; +var IFCRELDEFINES = 693640335; +var IFCRELDEFINESBYOBJECT = 1462361463; +var IFCRELDEFINESBYPROPERTIES = 4186316022; +var IFCRELDEFINESBYTEMPLATE = 307848117; +var IFCRELDEFINESBYTYPE = 781010003; +var IFCRELFILLSELEMENT = 3940055652; +var IFCRELFLOWCONTROLELEMENTS = 279856033; +var IFCRELINTERFERESELEMENTS = 427948657; +var IFCRELNESTS = 3268803585; +var IFCRELPOSITIONS = 1441486842; +var IFCRELPROJECTSELEMENT = 750771296; +var IFCRELREFERENCEDINSPATIALSTRUCTURE = 1245217292; +var IFCRELSEQUENCE = 4122056220; +var IFCRELSERVICESBUILDINGS = 366585022; +var IFCRELSPACEBOUNDARY = 3451746338; +var IFCRELSPACEBOUNDARY1STLEVEL = 3523091289; +var IFCRELSPACEBOUNDARY2NDLEVEL = 1521410863; +var IFCRELVOIDSELEMENT = 1401173127; +var IFCRELATIONSHIP = 478536968; +var IFCREPARAMETRISEDCOMPOSITECURVESEGMENT = 816062949; +var IFCREPRESENTATION = 1076942058; +var IFCREPRESENTATIONCONTEXT = 3377609919; +var IFCREPRESENTATIONITEM = 3008791417; +var IFCREPRESENTATIONMAP = 1660063152; +var IFCRESOURCE = 2914609552; +var IFCRESOURCEAPPROVALRELATIONSHIP = 2943643501; +var IFCRESOURCECONSTRAINTRELATIONSHIP = 1608871552; +var IFCRESOURCELEVELRELATIONSHIP = 2439245199; +var IFCRESOURCETIME = 1042787934; +var IFCREVOLVEDAREASOLID = 1856042241; +var IFCREVOLVEDAREASOLIDTAPERED = 3243963512; +var IFCRIGHTCIRCULARCONE = 4158566097; +var IFCRIGHTCIRCULARCYLINDER = 3626867408; +var IFCROOF = 2016517767; +var IFCROOFTYPE = 2781568857; +var IFCROOT = 2341007311; +var IFCROUNDEDRECTANGLEPROFILEDEF = 2778083089; +var IFCSIUNIT = 448429030; +var IFCSANITARYTERMINAL = 3053780830; +var IFCSANITARYTERMINALTYPE = 1768891740; +var IFCSCHEDULINGTIME = 1054537805; +var IFCSEAMCURVE = 2157484638; +var IFCSECTIONPROPERTIES = 2042790032; +var IFCSECTIONREINFORCEMENTPROPERTIES = 4165799628; +var IFCSECTIONEDSOLID = 1862484736; +var IFCSECTIONEDSOLIDHORIZONTAL = 1290935644; +var IFCSECTIONEDSPINE = 1509187699; +var IFCSENSOR = 4086658281; +var IFCSENSORTYPE = 1783015770; +var IFCSHADINGDEVICE = 1329646415; +var IFCSHADINGDEVICETYPE = 4074543187; +var IFCSHAPEASPECT = 867548509; +var IFCSHAPEMODEL = 3982875396; +var IFCSHAPEREPRESENTATION = 4240577450; +var IFCSHELLBASEDSURFACEMODEL = 4124623270; +var IFCSIMPLEPROPERTY = 3692461612; +var IFCSIMPLEPROPERTYTEMPLATE = 3663146110; +var IFCSITE = 4097777520; +var IFCSLAB = 1529196076; +var IFCSLABELEMENTEDCASE = 3127900445; +var IFCSLABSTANDARDCASE = 3027962421; +var IFCSLABTYPE = 2533589738; +var IFCSLIPPAGECONNECTIONCONDITION = 2609359061; +var IFCSOLARDEVICE = 3420628829; +var IFCSOLARDEVICETYPE = 1072016465; +var IFCSOLIDMODEL = 723233188; +var IFCSPACE = 3856911033; +var IFCSPACEHEATER = 1999602285; +var IFCSPACEHEATERTYPE = 1305183839; +var IFCSPACETYPE = 3812236995; +var IFCSPATIALELEMENT = 1412071761; +var IFCSPATIALELEMENTTYPE = 710998568; +var IFCSPATIALSTRUCTUREELEMENT = 2706606064; +var IFCSPATIALSTRUCTUREELEMENTTYPE = 3893378262; +var IFCSPATIALZONE = 463610769; +var IFCSPATIALZONETYPE = 2481509218; +var IFCSPHERE = 451544542; +var IFCSPHERICALSURFACE = 4015995234; +var IFCSTACKTERMINAL = 1404847402; +var IFCSTACKTERMINALTYPE = 3112655638; +var IFCSTAIR = 331165859; +var IFCSTAIRFLIGHT = 4252922144; +var IFCSTAIRFLIGHTTYPE = 1039846685; +var IFCSTAIRTYPE = 338393293; +var IFCSTRUCTURALACTION = 682877961; +var IFCSTRUCTURALACTIVITY = 3544373492; +var IFCSTRUCTURALANALYSISMODEL = 2515109513; +var IFCSTRUCTURALCONNECTION = 1179482911; +var IFCSTRUCTURALCONNECTIONCONDITION = 2273995522; +var IFCSTRUCTURALCURVEACTION = 1004757350; +var IFCSTRUCTURALCURVECONNECTION = 4243806635; +var IFCSTRUCTURALCURVEMEMBER = 214636428; +var IFCSTRUCTURALCURVEMEMBERVARYING = 2445595289; +var IFCSTRUCTURALCURVEREACTION = 2757150158; +var IFCSTRUCTURALITEM = 3136571912; +var IFCSTRUCTURALLINEARACTION = 1807405624; +var IFCSTRUCTURALLOAD = 2162789131; +var IFCSTRUCTURALLOADCASE = 385403989; +var IFCSTRUCTURALLOADCONFIGURATION = 3478079324; +var IFCSTRUCTURALLOADGROUP = 1252848954; +var IFCSTRUCTURALLOADLINEARFORCE = 1595516126; +var IFCSTRUCTURALLOADORRESULT = 609421318; +var IFCSTRUCTURALLOADPLANARFORCE = 2668620305; +var IFCSTRUCTURALLOADSINGLEDISPLACEMENT = 2473145415; +var IFCSTRUCTURALLOADSINGLEDISPLACEMENTDISTORTION = 1973038258; +var IFCSTRUCTURALLOADSINGLEFORCE = 1597423693; +var IFCSTRUCTURALLOADSINGLEFORCEWARPING = 1190533807; +var IFCSTRUCTURALLOADSTATIC = 2525727697; +var IFCSTRUCTURALLOADTEMPERATURE = 3408363356; +var IFCSTRUCTURALMEMBER = 530289379; +var IFCSTRUCTURALPLANARACTION = 1621171031; +var IFCSTRUCTURALPOINTACTION = 2082059205; +var IFCSTRUCTURALPOINTCONNECTION = 734778138; +var IFCSTRUCTURALPOINTREACTION = 1235345126; +var IFCSTRUCTURALREACTION = 3689010777; +var IFCSTRUCTURALRESULTGROUP = 2986769608; +var IFCSTRUCTURALSURFACEACTION = 3657597509; +var IFCSTRUCTURALSURFACECONNECTION = 1975003073; +var IFCSTRUCTURALSURFACEMEMBER = 3979015343; +var IFCSTRUCTURALSURFACEMEMBERVARYING = 2218152070; +var IFCSTRUCTURALSURFACEREACTION = 603775116; +var IFCSTYLEMODEL = 2830218821; +var IFCSTYLEDITEM = 3958052878; +var IFCSTYLEDREPRESENTATION = 3049322572; +var IFCSUBCONTRACTRESOURCE = 148013059; +var IFCSUBCONTRACTRESOURCETYPE = 4095615324; +var IFCSUBEDGE = 2233826070; +var IFCSURFACE = 2513912981; +var IFCSURFACECURVE = 699246055; +var IFCSURFACECURVESWEPTAREASOLID = 2028607225; +var IFCSURFACEFEATURE = 3101698114; +var IFCSURFACEOFLINEAREXTRUSION = 2809605785; +var IFCSURFACEOFREVOLUTION = 4124788165; +var IFCSURFACEREINFORCEMENTAREA = 2934153892; +var IFCSURFACESTYLE = 1300840506; +var IFCSURFACESTYLELIGHTING = 3303107099; +var IFCSURFACESTYLEREFRACTION = 1607154358; +var IFCSURFACESTYLERENDERING = 1878645084; +var IFCSURFACESTYLESHADING = 846575682; +var IFCSURFACESTYLEWITHTEXTURES = 1351298697; +var IFCSURFACETEXTURE = 626085974; +var IFCSWEPTAREASOLID = 2247615214; +var IFCSWEPTDISKSOLID = 1260650574; +var IFCSWEPTDISKSOLIDPOLYGONAL = 1096409881; +var IFCSWEPTSURFACE = 230924584; +var IFCSWITCHINGDEVICE = 1162798199; +var IFCSWITCHINGDEVICETYPE = 2315554128; +var IFCSYSTEM = 2254336722; +var IFCSYSTEMFURNITUREELEMENT = 413509423; +var IFCSYSTEMFURNITUREELEMENTTYPE = 1580310250; +var IFCTSHAPEPROFILEDEF = 3071757647; +var IFCTABLE = 985171141; +var IFCTABLECOLUMN = 2043862942; +var IFCTABLEROW = 531007025; +var IFCTANK = 812556717; +var IFCTANKTYPE = 5716631; +var IFCTASK = 3473067441; +var IFCTASKTIME = 1549132990; +var IFCTASKTIMERECURRING = 2771591690; +var IFCTASKTYPE = 3206491090; +var IFCTELECOMADDRESS = 912023232; +var IFCTENDON = 3824725483; +var IFCTENDONANCHOR = 2347447852; +var IFCTENDONANCHORTYPE = 3081323446; +var IFCTENDONCONDUIT = 3663046924; +var IFCTENDONCONDUITTYPE = 2281632017; +var IFCTENDONTYPE = 2415094496; +var IFCTESSELLATEDFACESET = 2387106220; +var IFCTESSELLATEDITEM = 901063453; +var IFCTEXTLITERAL = 4282788508; +var IFCTEXTLITERALWITHEXTENT = 3124975700; +var IFCTEXTSTYLE = 1447204868; +var IFCTEXTSTYLEFONTMODEL = 1983826977; +var IFCTEXTSTYLEFORDEFINEDFONT = 2636378356; +var IFCTEXTSTYLETEXTMODEL = 1640371178; +var IFCTEXTURECOORDINATE = 280115917; +var IFCTEXTURECOORDINATEGENERATOR = 1742049831; +var IFCTEXTUREMAP = 2552916305; +var IFCTEXTUREVERTEX = 1210645708; +var IFCTEXTUREVERTEXLIST = 3611470254; +var IFCTIMEPERIOD = 1199560280; +var IFCTIMESERIES = 3101149627; +var IFCTIMESERIESVALUE = 581633288; +var IFCTOPOLOGICALREPRESENTATIONITEM = 1377556343; +var IFCTOPOLOGYREPRESENTATION = 1735638870; +var IFCTOROIDALSURFACE = 1935646853; +var IFCTRANSFORMER = 3825984169; +var IFCTRANSFORMERTYPE = 1692211062; +var IFCTRANSITIONCURVESEGMENT2D = 2595432518; +var IFCTRANSPORTELEMENT = 1620046519; +var IFCTRANSPORTELEMENTTYPE = 2097647324; +var IFCTRAPEZIUMPROFILEDEF = 2715220739; +var IFCTRIANGULATEDFACESET = 2916149573; +var IFCTRIANGULATEDIRREGULARNETWORK = 1229763772; +var IFCTRIMMEDCURVE = 3593883385; +var IFCTUBEBUNDLE = 3026737570; +var IFCTUBEBUNDLETYPE = 1600972822; +var IFCTYPEOBJECT = 1628702193; +var IFCTYPEPROCESS = 3736923433; +var IFCTYPEPRODUCT = 2347495698; +var IFCTYPERESOURCE = 3698973494; +var IFCUSHAPEPROFILEDEF = 427810014; +var IFCUNITASSIGNMENT = 180925521; +var IFCUNITARYCONTROLELEMENT = 630975310; +var IFCUNITARYCONTROLELEMENTTYPE = 3179687236; +var IFCUNITARYEQUIPMENT = 4292641817; +var IFCUNITARYEQUIPMENTTYPE = 1911125066; +var IFCVALVE = 4207607924; +var IFCVALVETYPE = 728799441; +var IFCVECTOR = 1417489154; +var IFCVERTEX = 2799835756; +var IFCVERTEXLOOP = 2759199220; +var IFCVERTEXPOINT = 1907098498; +var IFCVIBRATIONDAMPER = 1530820697; +var IFCVIBRATIONDAMPERTYPE = 3956297820; +var IFCVIBRATIONISOLATOR = 2391383451; +var IFCVIBRATIONISOLATORTYPE = 3313531582; +var IFCVIRTUALELEMENT = 2769231204; +var IFCVIRTUALGRIDINTERSECTION = 891718957; +var IFCVOIDINGFEATURE = 926996030; +var IFCWALL = 2391406946; +var IFCWALLELEMENTEDCASE = 4156078855; +var IFCWALLSTANDARDCASE = 3512223829; +var IFCWALLTYPE = 1898987631; +var IFCWASTETERMINAL = 4237592921; +var IFCWASTETERMINALTYPE = 1133259667; +var IFCWINDOW = 3304561284; +var IFCWINDOWLININGPROPERTIES = 336235671; +var IFCWINDOWPANELPROPERTIES = 512836454; +var IFCWINDOWSTANDARDCASE = 486154966; +var IFCWINDOWSTYLE = 1299126871; +var IFCWINDOWTYPE = 4009809668; +var IFCWORKCALENDAR = 4088093105; +var IFCWORKCONTROL = 1028945134; +var IFCWORKPLAN = 4218914973; +var IFCWORKSCHEDULE = 3342526732; +var IFCWORKTIME = 1236880293; +var IFCZSHAPEPROFILEDEF = 2543172580; +var IFCZONE = 1033361043; +var IfcElements = [ + IFCACTUATOR, + IFCAIRTERMINAL, + IFCAIRTERMINALBOX, + IFCAIRTOAIRHEATRECOVERY, + IFCALARM, + IFCALIGNMENT, + IFCANNOTATION, + IFCAUDIOVISUALAPPLIANCE, + IFCBEAM, + IFCBEAMSTANDARDCASE, + IFCBEARING, + IFCBOILER, + IFCBRIDGE, + IFCBRIDGEPART, + IFCBUILDING, + IFCBUILDINGELEMENT, + IFCBUILDINGELEMENTPART, + IFCBUILDINGELEMENTPROXY, + IFCBUILDINGSTOREY, + IFCBURNER, + IFCCABLECARRIERFITTING, + IFCCABLECARRIERSEGMENT, + IFCCABLEFITTING, + IFCCABLESEGMENT, + IFCCAISSONFOUNDATION, + IFCCHILLER, + IFCCHIMNEY, + IFCCIVILELEMENT, + IFCCOIL, + IFCCOLUMN, + IFCCOLUMNSTANDARDCASE, + IFCCOMMUNICATIONSAPPLIANCE, + IFCCOMPRESSOR, + IFCCONDENSER, + IFCCONTROLLER, + IFCCOOLEDBEAM, + IFCCOOLINGTOWER, + IFCCOVERING, + IFCCURTAINWALL, + IFCDAMPER, + IFCDEEPFOUNDATION, + IFCDISCRETEACCESSORY, + IFCDISTRIBUTIONCHAMBERELEMENT, + IFCDISTRIBUTIONCONTROLELEMENT, + IFCDISTRIBUTIONELEMENT, + IFCDISTRIBUTIONFLOWELEMENT, + IFCDISTRIBUTIONPORT, + IFCDOOR, + IFCDOORSTANDARDCASE, + IFCDUCTFITTING, + IFCDUCTSEGMENT, + IFCDUCTSILENCER, + IFCELECTRICAPPLIANCE, + IFCELECTRICDISTRIBUTIONBOARD, + IFCELECTRICFLOWSTORAGEDEVICE, + IFCELECTRICGENERATOR, + IFCELECTRICMOTOR, + IFCELECTRICTIMECONTROL, + IFCELEMENT, + IFCELEMENTASSEMBLY, + IFCELEMENTCOMPONENT, + IFCENERGYCONVERSIONDEVICE, + IFCENGINE, + IFCEVAPORATIVECOOLER, + IFCEVAPORATOR, + IFCEXTERNALSPATIALELEMENT, + IFCEXTERNALSPATIALSTRUCTUREELEMENT, + IFCFACILITY, + IFCFACILITYPART, + IFCFAN, + IFCFASTENER, + IFCFEATUREELEMENT, + IFCFEATUREELEMENTADDITION, + IFCFEATUREELEMENTSUBTRACTION, + IFCFILTER, + IFCFIRESUPPRESSIONTERMINAL, + IFCFLOWCONTROLLER, + IFCFLOWFITTING, + IFCFLOWINSTRUMENT, + IFCFLOWMETER, + IFCFLOWMOVINGDEVICE, + IFCFLOWSEGMENT, + IFCFLOWSTORAGEDEVICE, + IFCFLOWTERMINAL, + IFCFLOWTREATMENTDEVICE, + IFCFOOTING, + IFCFURNISHINGELEMENT, + IFCFURNITURE, + IFCGEOGRAPHICELEMENT, + IFCGRID, + IFCHEATEXCHANGER, + IFCHUMIDIFIER, + IFCINTERCEPTOR, + IFCJUNCTIONBOX, + IFCLAMP, + IFCLIGHTFIXTURE, + IFCLINEARPOSITIONINGELEMENT, + IFCMECHANICALFASTENER, + IFCMEDICALDEVICE, + IFCMEMBER, + IFCMEMBERSTANDARDCASE, + IFCMOTORCONNECTION, + IFCOPENINGELEMENT, + IFCOPENINGSTANDARDCASE, + IFCOUTLET, + IFCPILE, + IFCPIPEFITTING, + IFCPIPESEGMENT, + IFCPLATE, + IFCPLATESTANDARDCASE, + IFCPORT, + IFCPOSITIONINGELEMENT, + IFCPROJECTIONELEMENT, + IFCPROTECTIVEDEVICE, + IFCPROTECTIVEDEVICETRIPPINGUNIT, + IFCPROXY, + IFCPUMP, + IFCRAILING, + IFCRAMP, + IFCRAMPFLIGHT, + IFCREFERENT, + IFCREINFORCINGBAR, + IFCREINFORCINGELEMENT, + IFCREINFORCINGMESH, + IFCROOF, + IFCSANITARYTERMINAL, + IFCSENSOR, + IFCSHADINGDEVICE, + IFCSITE, + IFCSLAB, + IFCSLABELEMENTEDCASE, + IFCSLABSTANDARDCASE, + IFCSOLARDEVICE, + IFCSPACE, + IFCSPACEHEATER, + IFCSPATIALELEMENT, + IFCSPATIALSTRUCTUREELEMENT, + IFCSPATIALZONE, + IFCSTACKTERMINAL, + IFCSTAIR, + IFCSTAIRFLIGHT, + IFCSTRUCTURALACTION, + IFCSTRUCTURALACTIVITY, + IFCSTRUCTURALCONNECTION, + IFCSTRUCTURALCURVEACTION, + IFCSTRUCTURALCURVECONNECTION, + IFCSTRUCTURALCURVEMEMBER, + IFCSTRUCTURALCURVEMEMBERVARYING, + IFCSTRUCTURALCURVEREACTION, + IFCSTRUCTURALITEM, + IFCSTRUCTURALLINEARACTION, + IFCSTRUCTURALMEMBER, + IFCSTRUCTURALPLANARACTION, + IFCSTRUCTURALPOINTACTION, + IFCSTRUCTURALPOINTCONNECTION, + IFCSTRUCTURALPOINTREACTION, + IFCSTRUCTURALREACTION, + IFCSTRUCTURALSURFACEACTION, + IFCSTRUCTURALSURFACECONNECTION, + IFCSTRUCTURALSURFACEMEMBER, + IFCSTRUCTURALSURFACEMEMBERVARYING, + IFCSTRUCTURALSURFACEREACTION, + IFCSURFACEFEATURE, + IFCSWITCHINGDEVICE, + IFCSYSTEMFURNITUREELEMENT, + IFCTANK, + IFCTENDON, + IFCTENDONANCHOR, + IFCTENDONCONDUIT, + IFCTRANSFORMER, + IFCTRANSPORTELEMENT, + IFCTUBEBUNDLE, + IFCUNITARYCONTROLELEMENT, + IFCUNITARYEQUIPMENT, + IFCVALVE, + IFCVIBRATIONDAMPER, + IFCVIBRATIONISOLATOR, + IFCVIRTUALELEMENT, + IFCVOIDINGFEATURE, + IFCWALL, + IFCWALLELEMENTEDCASE, + IFCWALLSTANDARDCASE, + IFCWASTETERMINAL, + IFCWINDOW, + IFCWINDOWSTANDARDCASE +]; - if (rootMetaObjects.length > 1) { - this.scene.error("Multiple containment hierarchy root found in metamodel - will insert fake 'Model' root"); - const fakeRoot = { - "id": modelId + ".fakeRoot", - "name": modelId, - "type": "Model", - "parent": null - }; - newObjects.push(fakeRoot); - for (let i = 0, len = rootMetaObjects.length; i < len; i++) { - rootMetaObjects[i].parent = fakeRoot.id; - } - } +// dist/ifc2x4_helper.ts +var FromRawLineData = {}; +FromRawLineData[IFCACTIONREQUEST] = (d) => { + return IfcActionRequest.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCACTOR] = (d) => { + return IfcActor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCACTORROLE] = (d) => { + return IfcActorRole.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCACTUATOR] = (d) => { + return IfcActuator.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCACTUATORTYPE] = (d) => { + return IfcActuatorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCADDRESS] = (d) => { + return IfcAddress.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCADVANCEDBREP] = (d) => { + return IfcAdvancedBrep.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCADVANCEDBREPWITHVOIDS] = (d) => { + return IfcAdvancedBrepWithVoids.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCADVANCEDFACE] = (d) => { + return IfcAdvancedFace.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAIRTERMINAL] = (d) => { + return IfcAirTerminal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAIRTERMINALBOX] = (d) => { + return IfcAirTerminalBox.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAIRTERMINALBOXTYPE] = (d) => { + return IfcAirTerminalBoxType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAIRTERMINALTYPE] = (d) => { + return IfcAirTerminalType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAIRTOAIRHEATRECOVERY] = (d) => { + return IfcAirToAirHeatRecovery.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAIRTOAIRHEATRECOVERYTYPE] = (d) => { + return IfcAirToAirHeatRecoveryType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALARM] = (d) => { + return IfcAlarm.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALARMTYPE] = (d) => { + return IfcAlarmType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT] = (d) => { + return IfcAlignment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DHORIZONTAL] = (d) => { + return IfcAlignment2DHorizontal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DHORIZONTALSEGMENT] = (d) => { + return IfcAlignment2DHorizontalSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DSEGMENT] = (d) => { + return IfcAlignment2DSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DVERSEGCIRCULARARC] = (d) => { + return IfcAlignment2DVerSegCircularArc.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DVERSEGLINE] = (d) => { + return IfcAlignment2DVerSegLine.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DVERSEGPARABOLICARC] = (d) => { + return IfcAlignment2DVerSegParabolicArc.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DVERTICAL] = (d) => { + return IfcAlignment2DVertical.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENT2DVERTICALSEGMENT] = (d) => { + return IfcAlignment2DVerticalSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCALIGNMENTCURVE] = (d) => { + return IfcAlignmentCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCANNOTATION] = (d) => { + return IfcAnnotation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCANNOTATIONFILLAREA] = (d) => { + return IfcAnnotationFillArea.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAPPLICATION] = (d) => { + return IfcApplication.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAPPLIEDVALUE] = (d) => { + return IfcAppliedValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAPPROVAL] = (d) => { + return IfcApproval.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAPPROVALRELATIONSHIP] = (d) => { + return IfcApprovalRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCARBITRARYCLOSEDPROFILEDEF] = (d) => { + return IfcArbitraryClosedProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCARBITRARYOPENPROFILEDEF] = (d) => { + return IfcArbitraryOpenProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCARBITRARYPROFILEDEFWITHVOIDS] = (d) => { + return IfcArbitraryProfileDefWithVoids.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCASSET] = (d) => { + return IfcAsset.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCASYMMETRICISHAPEPROFILEDEF] = (d) => { + return IfcAsymmetricIShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAUDIOVISUALAPPLIANCE] = (d) => { + return IfcAudioVisualAppliance.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAUDIOVISUALAPPLIANCETYPE] = (d) => { + return IfcAudioVisualApplianceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAXIS1PLACEMENT] = (d) => { + return IfcAxis1Placement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAXIS2PLACEMENT2D] = (d) => { + return IfcAxis2Placement2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCAXIS2PLACEMENT3D] = (d) => { + return IfcAxis2Placement3D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBSPLINECURVE] = (d) => { + return IfcBSplineCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBSPLINECURVEWITHKNOTS] = (d) => { + return IfcBSplineCurveWithKnots.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBSPLINESURFACE] = (d) => { + return IfcBSplineSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBSPLINESURFACEWITHKNOTS] = (d) => { + return IfcBSplineSurfaceWithKnots.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBEAM] = (d) => { + return IfcBeam.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBEAMSTANDARDCASE] = (d) => { + return IfcBeamStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBEAMTYPE] = (d) => { + return IfcBeamType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBEARING] = (d) => { + return IfcBearing.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBEARINGTYPE] = (d) => { + return IfcBearingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBLOBTEXTURE] = (d) => { + return IfcBlobTexture.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBLOCK] = (d) => { + return IfcBlock.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOILER] = (d) => { + return IfcBoiler.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOILERTYPE] = (d) => { + return IfcBoilerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOOLEANCLIPPINGRESULT] = (d) => { + return IfcBooleanClippingResult.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOOLEANRESULT] = (d) => { + return IfcBooleanResult.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDARYCONDITION] = (d) => { + return IfcBoundaryCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDARYCURVE] = (d) => { + return IfcBoundaryCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDARYEDGECONDITION] = (d) => { + return IfcBoundaryEdgeCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDARYFACECONDITION] = (d) => { + return IfcBoundaryFaceCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDARYNODECONDITION] = (d) => { + return IfcBoundaryNodeCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDARYNODECONDITIONWARPING] = (d) => { + return IfcBoundaryNodeConditionWarping.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDEDCURVE] = (d) => { + return IfcBoundedCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDEDSURFACE] = (d) => { + return IfcBoundedSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOUNDINGBOX] = (d) => { + return IfcBoundingBox.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBOXEDHALFSPACE] = (d) => { + return IfcBoxedHalfSpace.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBRIDGE] = (d) => { + return IfcBridge.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBRIDGEPART] = (d) => { + return IfcBridgePart.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDING] = (d) => { + return IfcBuilding.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGELEMENT] = (d) => { + return IfcBuildingElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGELEMENTPART] = (d) => { + return IfcBuildingElementPart.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGELEMENTPARTTYPE] = (d) => { + return IfcBuildingElementPartType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGELEMENTPROXY] = (d) => { + return IfcBuildingElementProxy.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGELEMENTPROXYTYPE] = (d) => { + return IfcBuildingElementProxyType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGELEMENTTYPE] = (d) => { + return IfcBuildingElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGSTOREY] = (d) => { + return IfcBuildingStorey.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBUILDINGSYSTEM] = (d) => { + return IfcBuildingSystem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBURNER] = (d) => { + return IfcBurner.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCBURNERTYPE] = (d) => { + return IfcBurnerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCSHAPEPROFILEDEF] = (d) => { + return IfcCShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLECARRIERFITTING] = (d) => { + return IfcCableCarrierFitting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLECARRIERFITTINGTYPE] = (d) => { + return IfcCableCarrierFittingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLECARRIERSEGMENT] = (d) => { + return IfcCableCarrierSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLECARRIERSEGMENTTYPE] = (d) => { + return IfcCableCarrierSegmentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLEFITTING] = (d) => { + return IfcCableFitting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLEFITTINGTYPE] = (d) => { + return IfcCableFittingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLESEGMENT] = (d) => { + return IfcCableSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCABLESEGMENTTYPE] = (d) => { + return IfcCableSegmentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCAISSONFOUNDATION] = (d) => { + return IfcCaissonFoundation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCAISSONFOUNDATIONTYPE] = (d) => { + return IfcCaissonFoundationType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANPOINT] = (d) => { + return IfcCartesianPoint.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANPOINTLIST] = (d) => { + return IfcCartesianPointList.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANPOINTLIST2D] = (d) => { + return IfcCartesianPointList2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANPOINTLIST3D] = (d) => { + return IfcCartesianPointList3D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR] = (d) => { + return IfcCartesianTransformationOperator.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR2D] = (d) => { + return IfcCartesianTransformationOperator2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR2DNONUNIFORM] = (d) => { + return IfcCartesianTransformationOperator2DnonUniform.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR3D] = (d) => { + return IfcCartesianTransformationOperator3D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM] = (d) => { + return IfcCartesianTransformationOperator3DnonUniform.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCENTERLINEPROFILEDEF] = (d) => { + return IfcCenterLineProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCHILLER] = (d) => { + return IfcChiller.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCHILLERTYPE] = (d) => { + return IfcChillerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCHIMNEY] = (d) => { + return IfcChimney.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCHIMNEYTYPE] = (d) => { + return IfcChimneyType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCIRCLE] = (d) => { + return IfcCircle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCIRCLEHOLLOWPROFILEDEF] = (d) => { + return IfcCircleHollowProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCIRCLEPROFILEDEF] = (d) => { + return IfcCircleProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCIRCULARARCSEGMENT2D] = (d) => { + return IfcCircularArcSegment2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCIVILELEMENT] = (d) => { + return IfcCivilElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCIVILELEMENTTYPE] = (d) => { + return IfcCivilElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCLASSIFICATION] = (d) => { + return IfcClassification.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCLASSIFICATIONREFERENCE] = (d) => { + return IfcClassificationReference.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCLOSEDSHELL] = (d) => { + return IfcClosedShell.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOIL] = (d) => { + return IfcCoil.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOILTYPE] = (d) => { + return IfcCoilType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOLOURRGB] = (d) => { + return IfcColourRgb.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOLOURRGBLIST] = (d) => { + return IfcColourRgbList.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOLOURSPECIFICATION] = (d) => { + return IfcColourSpecification.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOLUMN] = (d) => { + return IfcColumn.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOLUMNSTANDARDCASE] = (d) => { + return IfcColumnStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOLUMNTYPE] = (d) => { + return IfcColumnType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMMUNICATIONSAPPLIANCE] = (d) => { + return IfcCommunicationsAppliance.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMMUNICATIONSAPPLIANCETYPE] = (d) => { + return IfcCommunicationsApplianceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPLEXPROPERTY] = (d) => { + return IfcComplexProperty.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPLEXPROPERTYTEMPLATE] = (d) => { + return IfcComplexPropertyTemplate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPOSITECURVE] = (d) => { + return IfcCompositeCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPOSITECURVEONSURFACE] = (d) => { + return IfcCompositeCurveOnSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPOSITECURVESEGMENT] = (d) => { + return IfcCompositeCurveSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPOSITEPROFILEDEF] = (d) => { + return IfcCompositeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPRESSOR] = (d) => { + return IfcCompressor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOMPRESSORTYPE] = (d) => { + return IfcCompressorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONDENSER] = (d) => { + return IfcCondenser.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONDENSERTYPE] = (d) => { + return IfcCondenserType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONIC] = (d) => { + return IfcConic.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTEDFACESET] = (d) => { + return IfcConnectedFaceSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTIONCURVEGEOMETRY] = (d) => { + return IfcConnectionCurveGeometry.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTIONGEOMETRY] = (d) => { + return IfcConnectionGeometry.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTIONPOINTECCENTRICITY] = (d) => { + return IfcConnectionPointEccentricity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTIONPOINTGEOMETRY] = (d) => { + return IfcConnectionPointGeometry.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTIONSURFACEGEOMETRY] = (d) => { + return IfcConnectionSurfaceGeometry.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONNECTIONVOLUMEGEOMETRY] = (d) => { + return IfcConnectionVolumeGeometry.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRAINT] = (d) => { + return IfcConstraint.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONEQUIPMENTRESOURCE] = (d) => { + return IfcConstructionEquipmentResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONEQUIPMENTRESOURCETYPE] = (d) => { + return IfcConstructionEquipmentResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONMATERIALRESOURCE] = (d) => { + return IfcConstructionMaterialResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONMATERIALRESOURCETYPE] = (d) => { + return IfcConstructionMaterialResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONPRODUCTRESOURCE] = (d) => { + return IfcConstructionProductResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONPRODUCTRESOURCETYPE] = (d) => { + return IfcConstructionProductResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONRESOURCE] = (d) => { + return IfcConstructionResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONSTRUCTIONRESOURCETYPE] = (d) => { + return IfcConstructionResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONTEXT] = (d) => { + return IfcContext.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONTEXTDEPENDENTUNIT] = (d) => { + return IfcContextDependentUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONTROL] = (d) => { + return IfcControl.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONTROLLER] = (d) => { + return IfcController.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONTROLLERTYPE] = (d) => { + return IfcControllerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONVERSIONBASEDUNIT] = (d) => { + return IfcConversionBasedUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCONVERSIONBASEDUNITWITHOFFSET] = (d) => { + return IfcConversionBasedUnitWithOffset.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOOLEDBEAM] = (d) => { + return IfcCooledBeam.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOOLEDBEAMTYPE] = (d) => { + return IfcCooledBeamType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOOLINGTOWER] = (d) => { + return IfcCoolingTower.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOOLINGTOWERTYPE] = (d) => { + return IfcCoolingTowerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOORDINATEOPERATION] = (d) => { + return IfcCoordinateOperation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOORDINATEREFERENCESYSTEM] = (d) => { + return IfcCoordinateReferenceSystem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOSTITEM] = (d) => { + return IfcCostItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOSTSCHEDULE] = (d) => { + return IfcCostSchedule.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOSTVALUE] = (d) => { + return IfcCostValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOVERING] = (d) => { + return IfcCovering.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCOVERINGTYPE] = (d) => { + return IfcCoveringType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCREWRESOURCE] = (d) => { + return IfcCrewResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCREWRESOURCETYPE] = (d) => { + return IfcCrewResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCSGPRIMITIVE3D] = (d) => { + return IfcCsgPrimitive3D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCSGSOLID] = (d) => { + return IfcCsgSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURRENCYRELATIONSHIP] = (d) => { + return IfcCurrencyRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURTAINWALL] = (d) => { + return IfcCurtainWall.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURTAINWALLTYPE] = (d) => { + return IfcCurtainWallType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVE] = (d) => { + return IfcCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVEBOUNDEDPLANE] = (d) => { + return IfcCurveBoundedPlane.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVEBOUNDEDSURFACE] = (d) => { + return IfcCurveBoundedSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVESEGMENT2D] = (d) => { + return IfcCurveSegment2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVESTYLE] = (d) => { + return IfcCurveStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVESTYLEFONT] = (d) => { + return IfcCurveStyleFont.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVESTYLEFONTANDSCALING] = (d) => { + return IfcCurveStyleFontAndScaling.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCURVESTYLEFONTPATTERN] = (d) => { + return IfcCurveStyleFontPattern.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCCYLINDRICALSURFACE] = (d) => { + return IfcCylindricalSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDAMPER] = (d) => { + return IfcDamper.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDAMPERTYPE] = (d) => { + return IfcDamperType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDEEPFOUNDATION] = (d) => { + return IfcDeepFoundation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDEEPFOUNDATIONTYPE] = (d) => { + return IfcDeepFoundationType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDERIVEDPROFILEDEF] = (d) => { + return IfcDerivedProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDERIVEDUNIT] = (d) => { + return IfcDerivedUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDERIVEDUNITELEMENT] = (d) => { + return IfcDerivedUnitElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDIMENSIONALEXPONENTS] = (d) => { + return IfcDimensionalExponents.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDIRECTION] = (d) => { + return IfcDirection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISCRETEACCESSORY] = (d) => { + return IfcDiscreteAccessory.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISCRETEACCESSORYTYPE] = (d) => { + return IfcDiscreteAccessoryType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTANCEEXPRESSION] = (d) => { + return IfcDistanceExpression.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONCHAMBERELEMENT] = (d) => { + return IfcDistributionChamberElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONCHAMBERELEMENTTYPE] = (d) => { + return IfcDistributionChamberElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONCIRCUIT] = (d) => { + return IfcDistributionCircuit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONCONTROLELEMENT] = (d) => { + return IfcDistributionControlElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONCONTROLELEMENTTYPE] = (d) => { + return IfcDistributionControlElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONELEMENT] = (d) => { + return IfcDistributionElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONELEMENTTYPE] = (d) => { + return IfcDistributionElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONFLOWELEMENT] = (d) => { + return IfcDistributionFlowElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONFLOWELEMENTTYPE] = (d) => { + return IfcDistributionFlowElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONPORT] = (d) => { + return IfcDistributionPort.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDISTRIBUTIONSYSTEM] = (d) => { + return IfcDistributionSystem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOCUMENTINFORMATION] = (d) => { + return IfcDocumentInformation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOCUMENTINFORMATIONRELATIONSHIP] = (d) => { + return IfcDocumentInformationRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOCUMENTREFERENCE] = (d) => { + return IfcDocumentReference.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOOR] = (d) => { + return IfcDoor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOORLININGPROPERTIES] = (d) => { + return IfcDoorLiningProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOORPANELPROPERTIES] = (d) => { + return IfcDoorPanelProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOORSTANDARDCASE] = (d) => { + return IfcDoorStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOORSTYLE] = (d) => { + return IfcDoorStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDOORTYPE] = (d) => { + return IfcDoorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDRAUGHTINGPREDEFINEDCOLOUR] = (d) => { + return IfcDraughtingPreDefinedColour.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDRAUGHTINGPREDEFINEDCURVEFONT] = (d) => { + return IfcDraughtingPreDefinedCurveFont.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDUCTFITTING] = (d) => { + return IfcDuctFitting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDUCTFITTINGTYPE] = (d) => { + return IfcDuctFittingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDUCTSEGMENT] = (d) => { + return IfcDuctSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDUCTSEGMENTTYPE] = (d) => { + return IfcDuctSegmentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDUCTSILENCER] = (d) => { + return IfcDuctSilencer.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCDUCTSILENCERTYPE] = (d) => { + return IfcDuctSilencerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEDGE] = (d) => { + return IfcEdge.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEDGECURVE] = (d) => { + return IfcEdgeCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEDGELOOP] = (d) => { + return IfcEdgeLoop.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICAPPLIANCE] = (d) => { + return IfcElectricAppliance.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICAPPLIANCETYPE] = (d) => { + return IfcElectricApplianceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICDISTRIBUTIONBOARD] = (d) => { + return IfcElectricDistributionBoard.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICDISTRIBUTIONBOARDTYPE] = (d) => { + return IfcElectricDistributionBoardType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICFLOWSTORAGEDEVICE] = (d) => { + return IfcElectricFlowStorageDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICFLOWSTORAGEDEVICETYPE] = (d) => { + return IfcElectricFlowStorageDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICGENERATOR] = (d) => { + return IfcElectricGenerator.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICGENERATORTYPE] = (d) => { + return IfcElectricGeneratorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICMOTOR] = (d) => { + return IfcElectricMotor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICMOTORTYPE] = (d) => { + return IfcElectricMotorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICTIMECONTROL] = (d) => { + return IfcElectricTimeControl.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELECTRICTIMECONTROLTYPE] = (d) => { + return IfcElectricTimeControlType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENT] = (d) => { + return IfcElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTASSEMBLY] = (d) => { + return IfcElementAssembly.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTASSEMBLYTYPE] = (d) => { + return IfcElementAssemblyType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTCOMPONENT] = (d) => { + return IfcElementComponent.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTCOMPONENTTYPE] = (d) => { + return IfcElementComponentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTQUANTITY] = (d) => { + return IfcElementQuantity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTTYPE] = (d) => { + return IfcElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELEMENTARYSURFACE] = (d) => { + return IfcElementarySurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELLIPSE] = (d) => { + return IfcEllipse.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCELLIPSEPROFILEDEF] = (d) => { + return IfcEllipseProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCENERGYCONVERSIONDEVICE] = (d) => { + return IfcEnergyConversionDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCENERGYCONVERSIONDEVICETYPE] = (d) => { + return IfcEnergyConversionDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCENGINE] = (d) => { + return IfcEngine.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCENGINETYPE] = (d) => { + return IfcEngineType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVAPORATIVECOOLER] = (d) => { + return IfcEvaporativeCooler.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVAPORATIVECOOLERTYPE] = (d) => { + return IfcEvaporativeCoolerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVAPORATOR] = (d) => { + return IfcEvaporator.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVAPORATORTYPE] = (d) => { + return IfcEvaporatorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVENT] = (d) => { + return IfcEvent.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVENTTIME] = (d) => { + return IfcEventTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEVENTTYPE] = (d) => { + return IfcEventType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTENDEDPROPERTIES] = (d) => { + return IfcExtendedProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALINFORMATION] = (d) => { + return IfcExternalInformation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALREFERENCE] = (d) => { + return IfcExternalReference.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALREFERENCERELATIONSHIP] = (d) => { + return IfcExternalReferenceRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALSPATIALELEMENT] = (d) => { + return IfcExternalSpatialElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALSPATIALSTRUCTUREELEMENT] = (d) => { + return IfcExternalSpatialStructureElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALLYDEFINEDHATCHSTYLE] = (d) => { + return IfcExternallyDefinedHatchStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALLYDEFINEDSURFACESTYLE] = (d) => { + return IfcExternallyDefinedSurfaceStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTERNALLYDEFINEDTEXTFONT] = (d) => { + return IfcExternallyDefinedTextFont.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTRUDEDAREASOLID] = (d) => { + return IfcExtrudedAreaSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCEXTRUDEDAREASOLIDTAPERED] = (d) => { + return IfcExtrudedAreaSolidTapered.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACE] = (d) => { + return IfcFace.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACEBASEDSURFACEMODEL] = (d) => { + return IfcFaceBasedSurfaceModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACEBOUND] = (d) => { + return IfcFaceBound.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACEOUTERBOUND] = (d) => { + return IfcFaceOuterBound.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACESURFACE] = (d) => { + return IfcFaceSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACETEDBREP] = (d) => { + return IfcFacetedBrep.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACETEDBREPWITHVOIDS] = (d) => { + return IfcFacetedBrepWithVoids.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACILITY] = (d) => { + return IfcFacility.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFACILITYPART] = (d) => { + return IfcFacilityPart.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFAILURECONNECTIONCONDITION] = (d) => { + return IfcFailureConnectionCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFAN] = (d) => { + return IfcFan.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFANTYPE] = (d) => { + return IfcFanType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFASTENER] = (d) => { + return IfcFastener.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFASTENERTYPE] = (d) => { + return IfcFastenerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFEATUREELEMENT] = (d) => { + return IfcFeatureElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFEATUREELEMENTADDITION] = (d) => { + return IfcFeatureElementAddition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFEATUREELEMENTSUBTRACTION] = (d) => { + return IfcFeatureElementSubtraction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFILLAREASTYLE] = (d) => { + return IfcFillAreaStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFILLAREASTYLEHATCHING] = (d) => { + return IfcFillAreaStyleHatching.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFILLAREASTYLETILES] = (d) => { + return IfcFillAreaStyleTiles.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFILTER] = (d) => { + return IfcFilter.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFILTERTYPE] = (d) => { + return IfcFilterType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFIRESUPPRESSIONTERMINAL] = (d) => { + return IfcFireSuppressionTerminal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFIRESUPPRESSIONTERMINALTYPE] = (d) => { + return IfcFireSuppressionTerminalType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFIXEDREFERENCESWEPTAREASOLID] = (d) => { + return IfcFixedReferenceSweptAreaSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWCONTROLLER] = (d) => { + return IfcFlowController.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWCONTROLLERTYPE] = (d) => { + return IfcFlowControllerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWFITTING] = (d) => { + return IfcFlowFitting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWFITTINGTYPE] = (d) => { + return IfcFlowFittingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWINSTRUMENT] = (d) => { + return IfcFlowInstrument.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWINSTRUMENTTYPE] = (d) => { + return IfcFlowInstrumentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWMETER] = (d) => { + return IfcFlowMeter.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWMETERTYPE] = (d) => { + return IfcFlowMeterType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWMOVINGDEVICE] = (d) => { + return IfcFlowMovingDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWMOVINGDEVICETYPE] = (d) => { + return IfcFlowMovingDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWSEGMENT] = (d) => { + return IfcFlowSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWSEGMENTTYPE] = (d) => { + return IfcFlowSegmentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWSTORAGEDEVICE] = (d) => { + return IfcFlowStorageDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWSTORAGEDEVICETYPE] = (d) => { + return IfcFlowStorageDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWTERMINAL] = (d) => { + return IfcFlowTerminal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWTERMINALTYPE] = (d) => { + return IfcFlowTerminalType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWTREATMENTDEVICE] = (d) => { + return IfcFlowTreatmentDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFLOWTREATMENTDEVICETYPE] = (d) => { + return IfcFlowTreatmentDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFOOTING] = (d) => { + return IfcFooting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFOOTINGTYPE] = (d) => { + return IfcFootingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFURNISHINGELEMENT] = (d) => { + return IfcFurnishingElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFURNISHINGELEMENTTYPE] = (d) => { + return IfcFurnishingElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFURNITURE] = (d) => { + return IfcFurniture.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCFURNITURETYPE] = (d) => { + return IfcFurnitureType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOGRAPHICELEMENT] = (d) => { + return IfcGeographicElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOGRAPHICELEMENTTYPE] = (d) => { + return IfcGeographicElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOMETRICCURVESET] = (d) => { + return IfcGeometricCurveSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOMETRICREPRESENTATIONCONTEXT] = (d) => { + return IfcGeometricRepresentationContext.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOMETRICREPRESENTATIONITEM] = (d) => { + return IfcGeometricRepresentationItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOMETRICREPRESENTATIONSUBCONTEXT] = (d) => { + return IfcGeometricRepresentationSubContext.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGEOMETRICSET] = (d) => { + return IfcGeometricSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGRID] = (d) => { + return IfcGrid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGRIDAXIS] = (d) => { + return IfcGridAxis.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGRIDPLACEMENT] = (d) => { + return IfcGridPlacement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCGROUP] = (d) => { + return IfcGroup.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCHALFSPACESOLID] = (d) => { + return IfcHalfSpaceSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCHEATEXCHANGER] = (d) => { + return IfcHeatExchanger.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCHEATEXCHANGERTYPE] = (d) => { + return IfcHeatExchangerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCHUMIDIFIER] = (d) => { + return IfcHumidifier.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCHUMIDIFIERTYPE] = (d) => { + return IfcHumidifierType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCISHAPEPROFILEDEF] = (d) => { + return IfcIShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCIMAGETEXTURE] = (d) => { + return IfcImageTexture.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINDEXEDCOLOURMAP] = (d) => { + return IfcIndexedColourMap.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINDEXEDPOLYCURVE] = (d) => { + return IfcIndexedPolyCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINDEXEDPOLYGONALFACE] = (d) => { + return IfcIndexedPolygonalFace.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINDEXEDPOLYGONALFACEWITHVOIDS] = (d) => { + return IfcIndexedPolygonalFaceWithVoids.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINDEXEDTEXTUREMAP] = (d) => { + return IfcIndexedTextureMap.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINDEXEDTRIANGLETEXTUREMAP] = (d) => { + return IfcIndexedTriangleTextureMap.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINTERCEPTOR] = (d) => { + return IfcInterceptor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINTERCEPTORTYPE] = (d) => { + return IfcInterceptorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINTERSECTIONCURVE] = (d) => { + return IfcIntersectionCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCINVENTORY] = (d) => { + return IfcInventory.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCIRREGULARTIMESERIES] = (d) => { + return IfcIrregularTimeSeries.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCIRREGULARTIMESERIESVALUE] = (d) => { + return IfcIrregularTimeSeriesValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCJUNCTIONBOX] = (d) => { + return IfcJunctionBox.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCJUNCTIONBOXTYPE] = (d) => { + return IfcJunctionBoxType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLSHAPEPROFILEDEF] = (d) => { + return IfcLShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLABORRESOURCE] = (d) => { + return IfcLaborResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLABORRESOURCETYPE] = (d) => { + return IfcLaborResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLAGTIME] = (d) => { + return IfcLagTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLAMP] = (d) => { + return IfcLamp.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLAMPTYPE] = (d) => { + return IfcLampType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIBRARYINFORMATION] = (d) => { + return IfcLibraryInformation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIBRARYREFERENCE] = (d) => { + return IfcLibraryReference.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTDISTRIBUTIONDATA] = (d) => { + return IfcLightDistributionData.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTFIXTURE] = (d) => { + return IfcLightFixture.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTFIXTURETYPE] = (d) => { + return IfcLightFixtureType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTINTENSITYDISTRIBUTION] = (d) => { + return IfcLightIntensityDistribution.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTSOURCE] = (d) => { + return IfcLightSource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTSOURCEAMBIENT] = (d) => { + return IfcLightSourceAmbient.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTSOURCEDIRECTIONAL] = (d) => { + return IfcLightSourceDirectional.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTSOURCEGONIOMETRIC] = (d) => { + return IfcLightSourceGoniometric.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTSOURCEPOSITIONAL] = (d) => { + return IfcLightSourcePositional.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLIGHTSOURCESPOT] = (d) => { + return IfcLightSourceSpot.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLINE] = (d) => { + return IfcLine.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLINESEGMENT2D] = (d) => { + return IfcLineSegment2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLINEARPLACEMENT] = (d) => { + return IfcLinearPlacement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLINEARPOSITIONINGELEMENT] = (d) => { + return IfcLinearPositioningElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLOCALPLACEMENT] = (d) => { + return IfcLocalPlacement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCLOOP] = (d) => { + return IfcLoop.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMANIFOLDSOLIDBREP] = (d) => { + return IfcManifoldSolidBrep.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMAPCONVERSION] = (d) => { + return IfcMapConversion.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMAPPEDITEM] = (d) => { + return IfcMappedItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIAL] = (d) => { + return IfcMaterial.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALCLASSIFICATIONRELATIONSHIP] = (d) => { + return IfcMaterialClassificationRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALCONSTITUENT] = (d) => { + return IfcMaterialConstituent.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALCONSTITUENTSET] = (d) => { + return IfcMaterialConstituentSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALDEFINITION] = (d) => { + return IfcMaterialDefinition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALDEFINITIONREPRESENTATION] = (d) => { + return IfcMaterialDefinitionRepresentation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALLAYER] = (d) => { + return IfcMaterialLayer.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALLAYERSET] = (d) => { + return IfcMaterialLayerSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALLAYERSETUSAGE] = (d) => { + return IfcMaterialLayerSetUsage.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALLAYERWITHOFFSETS] = (d) => { + return IfcMaterialLayerWithOffsets.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALLIST] = (d) => { + return IfcMaterialList.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALPROFILE] = (d) => { + return IfcMaterialProfile.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALPROFILESET] = (d) => { + return IfcMaterialProfileSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALPROFILESETUSAGE] = (d) => { + return IfcMaterialProfileSetUsage.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALPROFILESETUSAGETAPERING] = (d) => { + return IfcMaterialProfileSetUsageTapering.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALPROFILEWITHOFFSETS] = (d) => { + return IfcMaterialProfileWithOffsets.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALPROPERTIES] = (d) => { + return IfcMaterialProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALRELATIONSHIP] = (d) => { + return IfcMaterialRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMATERIALUSAGEDEFINITION] = (d) => { + return IfcMaterialUsageDefinition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMEASUREWITHUNIT] = (d) => { + return IfcMeasureWithUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMECHANICALFASTENER] = (d) => { + return IfcMechanicalFastener.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMECHANICALFASTENERTYPE] = (d) => { + return IfcMechanicalFastenerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMEDICALDEVICE] = (d) => { + return IfcMedicalDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMEDICALDEVICETYPE] = (d) => { + return IfcMedicalDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMEMBER] = (d) => { + return IfcMember.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMEMBERSTANDARDCASE] = (d) => { + return IfcMemberStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMEMBERTYPE] = (d) => { + return IfcMemberType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMETRIC] = (d) => { + return IfcMetric.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMIRROREDPROFILEDEF] = (d) => { + return IfcMirroredProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMONETARYUNIT] = (d) => { + return IfcMonetaryUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMOTORCONNECTION] = (d) => { + return IfcMotorConnection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCMOTORCONNECTIONTYPE] = (d) => { + return IfcMotorConnectionType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCNAMEDUNIT] = (d) => { + return IfcNamedUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOBJECT] = (d) => { + return IfcObject.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOBJECTDEFINITION] = (d) => { + return IfcObjectDefinition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOBJECTPLACEMENT] = (d) => { + return IfcObjectPlacement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOBJECTIVE] = (d) => { + return IfcObjective.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOCCUPANT] = (d) => { + return IfcOccupant.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOFFSETCURVE] = (d) => { + return IfcOffsetCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOFFSETCURVE2D] = (d) => { + return IfcOffsetCurve2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOFFSETCURVE3D] = (d) => { + return IfcOffsetCurve3D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOFFSETCURVEBYDISTANCES] = (d) => { + return IfcOffsetCurveByDistances.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOPENSHELL] = (d) => { + return IfcOpenShell.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOPENINGELEMENT] = (d) => { + return IfcOpeningElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOPENINGSTANDARDCASE] = (d) => { + return IfcOpeningStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCORGANIZATION] = (d) => { + return IfcOrganization.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCORGANIZATIONRELATIONSHIP] = (d) => { + return IfcOrganizationRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCORIENTATIONEXPRESSION] = (d) => { + return IfcOrientationExpression.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCORIENTEDEDGE] = (d) => { + return IfcOrientedEdge.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOUTERBOUNDARYCURVE] = (d) => { + return IfcOuterBoundaryCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOUTLET] = (d) => { + return IfcOutlet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOUTLETTYPE] = (d) => { + return IfcOutletType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCOWNERHISTORY] = (d) => { + return IfcOwnerHistory.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPARAMETERIZEDPROFILEDEF] = (d) => { + return IfcParameterizedProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPATH] = (d) => { + return IfcPath.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPCURVE] = (d) => { + return IfcPcurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPERFORMANCEHISTORY] = (d) => { + return IfcPerformanceHistory.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPERMEABLECOVERINGPROPERTIES] = (d) => { + return IfcPermeableCoveringProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPERMIT] = (d) => { + return IfcPermit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPERSON] = (d) => { + return IfcPerson.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPERSONANDORGANIZATION] = (d) => { + return IfcPersonAndOrganization.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPHYSICALCOMPLEXQUANTITY] = (d) => { + return IfcPhysicalComplexQuantity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPHYSICALQUANTITY] = (d) => { + return IfcPhysicalQuantity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPHYSICALSIMPLEQUANTITY] = (d) => { + return IfcPhysicalSimpleQuantity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPILE] = (d) => { + return IfcPile.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPILETYPE] = (d) => { + return IfcPileType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPIPEFITTING] = (d) => { + return IfcPipeFitting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPIPEFITTINGTYPE] = (d) => { + return IfcPipeFittingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPIPESEGMENT] = (d) => { + return IfcPipeSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPIPESEGMENTTYPE] = (d) => { + return IfcPipeSegmentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPIXELTEXTURE] = (d) => { + return IfcPixelTexture.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLACEMENT] = (d) => { + return IfcPlacement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLANARBOX] = (d) => { + return IfcPlanarBox.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLANAREXTENT] = (d) => { + return IfcPlanarExtent.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLANE] = (d) => { + return IfcPlane.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLATE] = (d) => { + return IfcPlate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLATESTANDARDCASE] = (d) => { + return IfcPlateStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPLATETYPE] = (d) => { + return IfcPlateType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOINT] = (d) => { + return IfcPoint.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOINTONCURVE] = (d) => { + return IfcPointOnCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOINTONSURFACE] = (d) => { + return IfcPointOnSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOLYLOOP] = (d) => { + return IfcPolyLoop.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOLYGONALBOUNDEDHALFSPACE] = (d) => { + return IfcPolygonalBoundedHalfSpace.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOLYGONALFACESET] = (d) => { + return IfcPolygonalFaceSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOLYLINE] = (d) => { + return IfcPolyline.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPORT] = (d) => { + return IfcPort.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOSITIONINGELEMENT] = (d) => { + return IfcPositioningElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPOSTALADDRESS] = (d) => { + return IfcPostalAddress.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPREDEFINEDCOLOUR] = (d) => { + return IfcPreDefinedColour.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPREDEFINEDCURVEFONT] = (d) => { + return IfcPreDefinedCurveFont.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPREDEFINEDITEM] = (d) => { + return IfcPreDefinedItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPREDEFINEDPROPERTIES] = (d) => { + return IfcPreDefinedProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPREDEFINEDPROPERTYSET] = (d) => { + return IfcPreDefinedPropertySet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPREDEFINEDTEXTFONT] = (d) => { + return IfcPreDefinedTextFont.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRESENTATIONITEM] = (d) => { + return IfcPresentationItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRESENTATIONLAYERASSIGNMENT] = (d) => { + return IfcPresentationLayerAssignment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRESENTATIONLAYERWITHSTYLE] = (d) => { + return IfcPresentationLayerWithStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRESENTATIONSTYLE] = (d) => { + return IfcPresentationStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRESENTATIONSTYLEASSIGNMENT] = (d) => { + return IfcPresentationStyleAssignment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROCEDURE] = (d) => { + return IfcProcedure.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROCEDURETYPE] = (d) => { + return IfcProcedureType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROCESS] = (d) => { + return IfcProcess.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRODUCT] = (d) => { + return IfcProduct.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRODUCTDEFINITIONSHAPE] = (d) => { + return IfcProductDefinitionShape.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPRODUCTREPRESENTATION] = (d) => { + return IfcProductRepresentation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROFILEDEF] = (d) => { + return IfcProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROFILEPROPERTIES] = (d) => { + return IfcProfileProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROJECT] = (d) => { + return IfcProject.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROJECTLIBRARY] = (d) => { + return IfcProjectLibrary.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROJECTORDER] = (d) => { + return IfcProjectOrder.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROJECTEDCRS] = (d) => { + return IfcProjectedCRS.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROJECTIONELEMENT] = (d) => { + return IfcProjectionElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTY] = (d) => { + return IfcProperty.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYABSTRACTION] = (d) => { + return IfcPropertyAbstraction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYBOUNDEDVALUE] = (d) => { + return IfcPropertyBoundedValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYDEFINITION] = (d) => { + return IfcPropertyDefinition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYDEPENDENCYRELATIONSHIP] = (d) => { + return IfcPropertyDependencyRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYENUMERATEDVALUE] = (d) => { + return IfcPropertyEnumeratedValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYENUMERATION] = (d) => { + return IfcPropertyEnumeration.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYLISTVALUE] = (d) => { + return IfcPropertyListValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYREFERENCEVALUE] = (d) => { + return IfcPropertyReferenceValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYSET] = (d) => { + return IfcPropertySet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYSETDEFINITION] = (d) => { + return IfcPropertySetDefinition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYSETTEMPLATE] = (d) => { + return IfcPropertySetTemplate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYSINGLEVALUE] = (d) => { + return IfcPropertySingleValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYTABLEVALUE] = (d) => { + return IfcPropertyTableValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYTEMPLATE] = (d) => { + return IfcPropertyTemplate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROPERTYTEMPLATEDEFINITION] = (d) => { + return IfcPropertyTemplateDefinition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROTECTIVEDEVICE] = (d) => { + return IfcProtectiveDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROTECTIVEDEVICETRIPPINGUNIT] = (d) => { + return IfcProtectiveDeviceTrippingUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROTECTIVEDEVICETRIPPINGUNITTYPE] = (d) => { + return IfcProtectiveDeviceTrippingUnitType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROTECTIVEDEVICETYPE] = (d) => { + return IfcProtectiveDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPROXY] = (d) => { + return IfcProxy.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPUMP] = (d) => { + return IfcPump.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCPUMPTYPE] = (d) => { + return IfcPumpType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYAREA] = (d) => { + return IfcQuantityArea.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYCOUNT] = (d) => { + return IfcQuantityCount.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYLENGTH] = (d) => { + return IfcQuantityLength.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYSET] = (d) => { + return IfcQuantitySet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYTIME] = (d) => { + return IfcQuantityTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYVOLUME] = (d) => { + return IfcQuantityVolume.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCQUANTITYWEIGHT] = (d) => { + return IfcQuantityWeight.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRAILING] = (d) => { + return IfcRailing.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRAILINGTYPE] = (d) => { + return IfcRailingType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRAMP] = (d) => { + return IfcRamp.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRAMPFLIGHT] = (d) => { + return IfcRampFlight.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRAMPFLIGHTTYPE] = (d) => { + return IfcRampFlightType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRAMPTYPE] = (d) => { + return IfcRampType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRATIONALBSPLINECURVEWITHKNOTS] = (d) => { + return IfcRationalBSplineCurveWithKnots.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRATIONALBSPLINESURFACEWITHKNOTS] = (d) => { + return IfcRationalBSplineSurfaceWithKnots.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRECTANGLEHOLLOWPROFILEDEF] = (d) => { + return IfcRectangleHollowProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRECTANGLEPROFILEDEF] = (d) => { + return IfcRectangleProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRECTANGULARPYRAMID] = (d) => { + return IfcRectangularPyramid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRECTANGULARTRIMMEDSURFACE] = (d) => { + return IfcRectangularTrimmedSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRECURRENCEPATTERN] = (d) => { + return IfcRecurrencePattern.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREFERENCE] = (d) => { + return IfcReference.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREFERENT] = (d) => { + return IfcReferent.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREGULARTIMESERIES] = (d) => { + return IfcRegularTimeSeries.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCEMENTBARPROPERTIES] = (d) => { + return IfcReinforcementBarProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCEMENTDEFINITIONPROPERTIES] = (d) => { + return IfcReinforcementDefinitionProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCINGBAR] = (d) => { + return IfcReinforcingBar.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCINGBARTYPE] = (d) => { + return IfcReinforcingBarType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCINGELEMENT] = (d) => { + return IfcReinforcingElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCINGELEMENTTYPE] = (d) => { + return IfcReinforcingElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCINGMESH] = (d) => { + return IfcReinforcingMesh.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREINFORCINGMESHTYPE] = (d) => { + return IfcReinforcingMeshType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELAGGREGATES] = (d) => { + return IfcRelAggregates.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNS] = (d) => { + return IfcRelAssigns.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTOACTOR] = (d) => { + return IfcRelAssignsToActor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTOCONTROL] = (d) => { + return IfcRelAssignsToControl.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTOGROUP] = (d) => { + return IfcRelAssignsToGroup.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTOGROUPBYFACTOR] = (d) => { + return IfcRelAssignsToGroupByFactor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTOPROCESS] = (d) => { + return IfcRelAssignsToProcess.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTOPRODUCT] = (d) => { + return IfcRelAssignsToProduct.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSIGNSTORESOURCE] = (d) => { + return IfcRelAssignsToResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATES] = (d) => { + return IfcRelAssociates.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATESAPPROVAL] = (d) => { + return IfcRelAssociatesApproval.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATESCLASSIFICATION] = (d) => { + return IfcRelAssociatesClassification.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATESCONSTRAINT] = (d) => { + return IfcRelAssociatesConstraint.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATESDOCUMENT] = (d) => { + return IfcRelAssociatesDocument.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATESLIBRARY] = (d) => { + return IfcRelAssociatesLibrary.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELASSOCIATESMATERIAL] = (d) => { + return IfcRelAssociatesMaterial.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTS] = (d) => { + return IfcRelConnects.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSELEMENTS] = (d) => { + return IfcRelConnectsElements.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSPATHELEMENTS] = (d) => { + return IfcRelConnectsPathElements.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSPORTTOELEMENT] = (d) => { + return IfcRelConnectsPortToElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSPORTS] = (d) => { + return IfcRelConnectsPorts.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSSTRUCTURALACTIVITY] = (d) => { + return IfcRelConnectsStructuralActivity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSSTRUCTURALMEMBER] = (d) => { + return IfcRelConnectsStructuralMember.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSWITHECCENTRICITY] = (d) => { + return IfcRelConnectsWithEccentricity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONNECTSWITHREALIZINGELEMENTS] = (d) => { + return IfcRelConnectsWithRealizingElements.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCONTAINEDINSPATIALSTRUCTURE] = (d) => { + return IfcRelContainedInSpatialStructure.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCOVERSBLDGELEMENTS] = (d) => { + return IfcRelCoversBldgElements.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELCOVERSSPACES] = (d) => { + return IfcRelCoversSpaces.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDECLARES] = (d) => { + return IfcRelDeclares.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDECOMPOSES] = (d) => { + return IfcRelDecomposes.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDEFINES] = (d) => { + return IfcRelDefines.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDEFINESBYOBJECT] = (d) => { + return IfcRelDefinesByObject.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDEFINESBYPROPERTIES] = (d) => { + return IfcRelDefinesByProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDEFINESBYTEMPLATE] = (d) => { + return IfcRelDefinesByTemplate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELDEFINESBYTYPE] = (d) => { + return IfcRelDefinesByType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELFILLSELEMENT] = (d) => { + return IfcRelFillsElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELFLOWCONTROLELEMENTS] = (d) => { + return IfcRelFlowControlElements.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELINTERFERESELEMENTS] = (d) => { + return IfcRelInterferesElements.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELNESTS] = (d) => { + return IfcRelNests.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELPOSITIONS] = (d) => { + return IfcRelPositions.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELPROJECTSELEMENT] = (d) => { + return IfcRelProjectsElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELREFERENCEDINSPATIALSTRUCTURE] = (d) => { + return IfcRelReferencedInSpatialStructure.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELSEQUENCE] = (d) => { + return IfcRelSequence.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELSERVICESBUILDINGS] = (d) => { + return IfcRelServicesBuildings.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELSPACEBOUNDARY] = (d) => { + return IfcRelSpaceBoundary.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELSPACEBOUNDARY1STLEVEL] = (d) => { + return IfcRelSpaceBoundary1stLevel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELSPACEBOUNDARY2NDLEVEL] = (d) => { + return IfcRelSpaceBoundary2ndLevel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELVOIDSELEMENT] = (d) => { + return IfcRelVoidsElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRELATIONSHIP] = (d) => { + return IfcRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREPARAMETRISEDCOMPOSITECURVESEGMENT] = (d) => { + return IfcReparametrisedCompositeCurveSegment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREPRESENTATION] = (d) => { + return IfcRepresentation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREPRESENTATIONCONTEXT] = (d) => { + return IfcRepresentationContext.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREPRESENTATIONITEM] = (d) => { + return IfcRepresentationItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREPRESENTATIONMAP] = (d) => { + return IfcRepresentationMap.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRESOURCE] = (d) => { + return IfcResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRESOURCEAPPROVALRELATIONSHIP] = (d) => { + return IfcResourceApprovalRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRESOURCECONSTRAINTRELATIONSHIP] = (d) => { + return IfcResourceConstraintRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRESOURCELEVELRELATIONSHIP] = (d) => { + return IfcResourceLevelRelationship.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRESOURCETIME] = (d) => { + return IfcResourceTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREVOLVEDAREASOLID] = (d) => { + return IfcRevolvedAreaSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCREVOLVEDAREASOLIDTAPERED] = (d) => { + return IfcRevolvedAreaSolidTapered.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRIGHTCIRCULARCONE] = (d) => { + return IfcRightCircularCone.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCRIGHTCIRCULARCYLINDER] = (d) => { + return IfcRightCircularCylinder.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCROOF] = (d) => { + return IfcRoof.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCROOFTYPE] = (d) => { + return IfcRoofType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCROOT] = (d) => { + return IfcRoot.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCROUNDEDRECTANGLEPROFILEDEF] = (d) => { + return IfcRoundedRectangleProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSIUNIT] = (d) => { + return IfcSIUnit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSANITARYTERMINAL] = (d) => { + return IfcSanitaryTerminal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSANITARYTERMINALTYPE] = (d) => { + return IfcSanitaryTerminalType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSCHEDULINGTIME] = (d) => { + return IfcSchedulingTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSEAMCURVE] = (d) => { + return IfcSeamCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSECTIONPROPERTIES] = (d) => { + return IfcSectionProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSECTIONREINFORCEMENTPROPERTIES] = (d) => { + return IfcSectionReinforcementProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSECTIONEDSOLID] = (d) => { + return IfcSectionedSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSECTIONEDSOLIDHORIZONTAL] = (d) => { + return IfcSectionedSolidHorizontal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSECTIONEDSPINE] = (d) => { + return IfcSectionedSpine.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSENSOR] = (d) => { + return IfcSensor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSENSORTYPE] = (d) => { + return IfcSensorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSHADINGDEVICE] = (d) => { + return IfcShadingDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSHADINGDEVICETYPE] = (d) => { + return IfcShadingDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSHAPEASPECT] = (d) => { + return IfcShapeAspect.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSHAPEMODEL] = (d) => { + return IfcShapeModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSHAPEREPRESENTATION] = (d) => { + return IfcShapeRepresentation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSHELLBASEDSURFACEMODEL] = (d) => { + return IfcShellBasedSurfaceModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSIMPLEPROPERTY] = (d) => { + return IfcSimpleProperty.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSIMPLEPROPERTYTEMPLATE] = (d) => { + return IfcSimplePropertyTemplate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSITE] = (d) => { + return IfcSite.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSLAB] = (d) => { + return IfcSlab.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSLABELEMENTEDCASE] = (d) => { + return IfcSlabElementedCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSLABSTANDARDCASE] = (d) => { + return IfcSlabStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSLABTYPE] = (d) => { + return IfcSlabType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSLIPPAGECONNECTIONCONDITION] = (d) => { + return IfcSlippageConnectionCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSOLARDEVICE] = (d) => { + return IfcSolarDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSOLARDEVICETYPE] = (d) => { + return IfcSolarDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSOLIDMODEL] = (d) => { + return IfcSolidModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPACE] = (d) => { + return IfcSpace.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPACEHEATER] = (d) => { + return IfcSpaceHeater.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPACEHEATERTYPE] = (d) => { + return IfcSpaceHeaterType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPACETYPE] = (d) => { + return IfcSpaceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPATIALELEMENT] = (d) => { + return IfcSpatialElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPATIALELEMENTTYPE] = (d) => { + return IfcSpatialElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPATIALSTRUCTUREELEMENT] = (d) => { + return IfcSpatialStructureElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPATIALSTRUCTUREELEMENTTYPE] = (d) => { + return IfcSpatialStructureElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPATIALZONE] = (d) => { + return IfcSpatialZone.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPATIALZONETYPE] = (d) => { + return IfcSpatialZoneType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPHERE] = (d) => { + return IfcSphere.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSPHERICALSURFACE] = (d) => { + return IfcSphericalSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTACKTERMINAL] = (d) => { + return IfcStackTerminal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTACKTERMINALTYPE] = (d) => { + return IfcStackTerminalType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTAIR] = (d) => { + return IfcStair.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTAIRFLIGHT] = (d) => { + return IfcStairFlight.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTAIRFLIGHTTYPE] = (d) => { + return IfcStairFlightType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTAIRTYPE] = (d) => { + return IfcStairType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALACTION] = (d) => { + return IfcStructuralAction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALACTIVITY] = (d) => { + return IfcStructuralActivity.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALANALYSISMODEL] = (d) => { + return IfcStructuralAnalysisModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCONNECTION] = (d) => { + return IfcStructuralConnection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCONNECTIONCONDITION] = (d) => { + return IfcStructuralConnectionCondition.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCURVEACTION] = (d) => { + return IfcStructuralCurveAction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCURVECONNECTION] = (d) => { + return IfcStructuralCurveConnection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCURVEMEMBER] = (d) => { + return IfcStructuralCurveMember.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCURVEMEMBERVARYING] = (d) => { + return IfcStructuralCurveMemberVarying.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALCURVEREACTION] = (d) => { + return IfcStructuralCurveReaction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALITEM] = (d) => { + return IfcStructuralItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLINEARACTION] = (d) => { + return IfcStructuralLinearAction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOAD] = (d) => { + return IfcStructuralLoad.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADCASE] = (d) => { + return IfcStructuralLoadCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADCONFIGURATION] = (d) => { + return IfcStructuralLoadConfiguration.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADGROUP] = (d) => { + return IfcStructuralLoadGroup.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADLINEARFORCE] = (d) => { + return IfcStructuralLoadLinearForce.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADORRESULT] = (d) => { + return IfcStructuralLoadOrResult.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADPLANARFORCE] = (d) => { + return IfcStructuralLoadPlanarForce.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADSINGLEDISPLACEMENT] = (d) => { + return IfcStructuralLoadSingleDisplacement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADSINGLEDISPLACEMENTDISTORTION] = (d) => { + return IfcStructuralLoadSingleDisplacementDistortion.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADSINGLEFORCE] = (d) => { + return IfcStructuralLoadSingleForce.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADSINGLEFORCEWARPING] = (d) => { + return IfcStructuralLoadSingleForceWarping.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADSTATIC] = (d) => { + return IfcStructuralLoadStatic.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALLOADTEMPERATURE] = (d) => { + return IfcStructuralLoadTemperature.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALMEMBER] = (d) => { + return IfcStructuralMember.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALPLANARACTION] = (d) => { + return IfcStructuralPlanarAction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALPOINTACTION] = (d) => { + return IfcStructuralPointAction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALPOINTCONNECTION] = (d) => { + return IfcStructuralPointConnection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALPOINTREACTION] = (d) => { + return IfcStructuralPointReaction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALREACTION] = (d) => { + return IfcStructuralReaction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALRESULTGROUP] = (d) => { + return IfcStructuralResultGroup.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALSURFACEACTION] = (d) => { + return IfcStructuralSurfaceAction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALSURFACECONNECTION] = (d) => { + return IfcStructuralSurfaceConnection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALSURFACEMEMBER] = (d) => { + return IfcStructuralSurfaceMember.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALSURFACEMEMBERVARYING] = (d) => { + return IfcStructuralSurfaceMemberVarying.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTRUCTURALSURFACEREACTION] = (d) => { + return IfcStructuralSurfaceReaction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTYLEMODEL] = (d) => { + return IfcStyleModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTYLEDITEM] = (d) => { + return IfcStyledItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSTYLEDREPRESENTATION] = (d) => { + return IfcStyledRepresentation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSUBCONTRACTRESOURCE] = (d) => { + return IfcSubContractResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSUBCONTRACTRESOURCETYPE] = (d) => { + return IfcSubContractResourceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSUBEDGE] = (d) => { + return IfcSubedge.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACE] = (d) => { + return IfcSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACECURVE] = (d) => { + return IfcSurfaceCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACECURVESWEPTAREASOLID] = (d) => { + return IfcSurfaceCurveSweptAreaSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACEFEATURE] = (d) => { + return IfcSurfaceFeature.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACEOFLINEAREXTRUSION] = (d) => { + return IfcSurfaceOfLinearExtrusion.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACEOFREVOLUTION] = (d) => { + return IfcSurfaceOfRevolution.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACEREINFORCEMENTAREA] = (d) => { + return IfcSurfaceReinforcementArea.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACESTYLE] = (d) => { + return IfcSurfaceStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACESTYLELIGHTING] = (d) => { + return IfcSurfaceStyleLighting.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACESTYLEREFRACTION] = (d) => { + return IfcSurfaceStyleRefraction.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACESTYLERENDERING] = (d) => { + return IfcSurfaceStyleRendering.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACESTYLESHADING] = (d) => { + return IfcSurfaceStyleShading.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACESTYLEWITHTEXTURES] = (d) => { + return IfcSurfaceStyleWithTextures.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSURFACETEXTURE] = (d) => { + return IfcSurfaceTexture.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSWEPTAREASOLID] = (d) => { + return IfcSweptAreaSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSWEPTDISKSOLID] = (d) => { + return IfcSweptDiskSolid.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSWEPTDISKSOLIDPOLYGONAL] = (d) => { + return IfcSweptDiskSolidPolygonal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSWEPTSURFACE] = (d) => { + return IfcSweptSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSWITCHINGDEVICE] = (d) => { + return IfcSwitchingDevice.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSWITCHINGDEVICETYPE] = (d) => { + return IfcSwitchingDeviceType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSYSTEM] = (d) => { + return IfcSystem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSYSTEMFURNITUREELEMENT] = (d) => { + return IfcSystemFurnitureElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCSYSTEMFURNITUREELEMENTTYPE] = (d) => { + return IfcSystemFurnitureElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTSHAPEPROFILEDEF] = (d) => { + return IfcTShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTABLE] = (d) => { + return IfcTable.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTABLECOLUMN] = (d) => { + return IfcTableColumn.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTABLEROW] = (d) => { + return IfcTableRow.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTANK] = (d) => { + return IfcTank.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTANKTYPE] = (d) => { + return IfcTankType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTASK] = (d) => { + return IfcTask.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTASKTIME] = (d) => { + return IfcTaskTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTASKTIMERECURRING] = (d) => { + return IfcTaskTimeRecurring.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTASKTYPE] = (d) => { + return IfcTaskType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTELECOMADDRESS] = (d) => { + return IfcTelecomAddress.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTENDON] = (d) => { + return IfcTendon.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTENDONANCHOR] = (d) => { + return IfcTendonAnchor.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTENDONANCHORTYPE] = (d) => { + return IfcTendonAnchorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTENDONCONDUIT] = (d) => { + return IfcTendonConduit.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTENDONCONDUITTYPE] = (d) => { + return IfcTendonConduitType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTENDONTYPE] = (d) => { + return IfcTendonType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTESSELLATEDFACESET] = (d) => { + return IfcTessellatedFaceSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTESSELLATEDITEM] = (d) => { + return IfcTessellatedItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTLITERAL] = (d) => { + return IfcTextLiteral.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTLITERALWITHEXTENT] = (d) => { + return IfcTextLiteralWithExtent.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTSTYLE] = (d) => { + return IfcTextStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTSTYLEFONTMODEL] = (d) => { + return IfcTextStyleFontModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTSTYLEFORDEFINEDFONT] = (d) => { + return IfcTextStyleForDefinedFont.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTSTYLETEXTMODEL] = (d) => { + return IfcTextStyleTextModel.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTURECOORDINATE] = (d) => { + return IfcTextureCoordinate.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTURECOORDINATEGENERATOR] = (d) => { + return IfcTextureCoordinateGenerator.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTUREMAP] = (d) => { + return IfcTextureMap.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTUREVERTEX] = (d) => { + return IfcTextureVertex.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTEXTUREVERTEXLIST] = (d) => { + return IfcTextureVertexList.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTIMEPERIOD] = (d) => { + return IfcTimePeriod.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTIMESERIES] = (d) => { + return IfcTimeSeries.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTIMESERIESVALUE] = (d) => { + return IfcTimeSeriesValue.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTOPOLOGICALREPRESENTATIONITEM] = (d) => { + return IfcTopologicalRepresentationItem.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTOPOLOGYREPRESENTATION] = (d) => { + return IfcTopologyRepresentation.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTOROIDALSURFACE] = (d) => { + return IfcToroidalSurface.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRANSFORMER] = (d) => { + return IfcTransformer.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRANSFORMERTYPE] = (d) => { + return IfcTransformerType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRANSITIONCURVESEGMENT2D] = (d) => { + return IfcTransitionCurveSegment2D.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRANSPORTELEMENT] = (d) => { + return IfcTransportElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRANSPORTELEMENTTYPE] = (d) => { + return IfcTransportElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRAPEZIUMPROFILEDEF] = (d) => { + return IfcTrapeziumProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRIANGULATEDFACESET] = (d) => { + return IfcTriangulatedFaceSet.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRIANGULATEDIRREGULARNETWORK] = (d) => { + return IfcTriangulatedIrregularNetwork.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTRIMMEDCURVE] = (d) => { + return IfcTrimmedCurve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTUBEBUNDLE] = (d) => { + return IfcTubeBundle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTUBEBUNDLETYPE] = (d) => { + return IfcTubeBundleType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTYPEOBJECT] = (d) => { + return IfcTypeObject.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTYPEPROCESS] = (d) => { + return IfcTypeProcess.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTYPEPRODUCT] = (d) => { + return IfcTypeProduct.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCTYPERESOURCE] = (d) => { + return IfcTypeResource.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCUSHAPEPROFILEDEF] = (d) => { + return IfcUShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCUNITASSIGNMENT] = (d) => { + return IfcUnitAssignment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCUNITARYCONTROLELEMENT] = (d) => { + return IfcUnitaryControlElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCUNITARYCONTROLELEMENTTYPE] = (d) => { + return IfcUnitaryControlElementType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCUNITARYEQUIPMENT] = (d) => { + return IfcUnitaryEquipment.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCUNITARYEQUIPMENTTYPE] = (d) => { + return IfcUnitaryEquipmentType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVALVE] = (d) => { + return IfcValve.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVALVETYPE] = (d) => { + return IfcValveType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVECTOR] = (d) => { + return IfcVector.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVERTEX] = (d) => { + return IfcVertex.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVERTEXLOOP] = (d) => { + return IfcVertexLoop.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVERTEXPOINT] = (d) => { + return IfcVertexPoint.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVIBRATIONDAMPER] = (d) => { + return IfcVibrationDamper.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVIBRATIONDAMPERTYPE] = (d) => { + return IfcVibrationDamperType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVIBRATIONISOLATOR] = (d) => { + return IfcVibrationIsolator.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVIBRATIONISOLATORTYPE] = (d) => { + return IfcVibrationIsolatorType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVIRTUALELEMENT] = (d) => { + return IfcVirtualElement.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVIRTUALGRIDINTERSECTION] = (d) => { + return IfcVirtualGridIntersection.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCVOIDINGFEATURE] = (d) => { + return IfcVoidingFeature.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWALL] = (d) => { + return IfcWall.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWALLELEMENTEDCASE] = (d) => { + return IfcWallElementedCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWALLSTANDARDCASE] = (d) => { + return IfcWallStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWALLTYPE] = (d) => { + return IfcWallType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWASTETERMINAL] = (d) => { + return IfcWasteTerminal.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWASTETERMINALTYPE] = (d) => { + return IfcWasteTerminalType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWINDOW] = (d) => { + return IfcWindow.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWINDOWLININGPROPERTIES] = (d) => { + return IfcWindowLiningProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWINDOWPANELPROPERTIES] = (d) => { + return IfcWindowPanelProperties.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWINDOWSTANDARDCASE] = (d) => { + return IfcWindowStandardCase.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWINDOWSTYLE] = (d) => { + return IfcWindowStyle.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWINDOWTYPE] = (d) => { + return IfcWindowType.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWORKCALENDAR] = (d) => { + return IfcWorkCalendar.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWORKCONTROL] = (d) => { + return IfcWorkControl.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWORKPLAN] = (d) => { + return IfcWorkPlan.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWORKSCHEDULE] = (d) => { + return IfcWorkSchedule.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCWORKTIME] = (d) => { + return IfcWorkTime.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCZSHAPEPROFILEDEF] = (d) => { + return IfcZShapeProfileDef.FromTape(d.ID, d.type, d.arguments); +}; +FromRawLineData[IFCZONE] = (d) => { + return IfcZone.FromTape(d.ID, d.type, d.arguments); +}; +var IfcActionRequest = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.PredefinedType = PredefinedType; + this.Status = Status; + this.LongDescription = LongDescription; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Status = tape[ptr++]; + let LongDescription = tape[ptr++]; + return new IfcActionRequest(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.PredefinedType); + args.push(this.Status); + args.push(this.LongDescription); + return args; + } +}; +var IfcActor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.TheActor = TheActor; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let TheActor = tape[ptr++]; + return new IfcActor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.TheActor); + return args; + } +}; +var IfcActorRole = class { + constructor(expressID, type, Role, UserDefinedRole, Description) { + this.expressID = expressID; + this.type = type; + this.Role = Role; + this.UserDefinedRole = UserDefinedRole; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Role = tape[ptr++]; + let UserDefinedRole = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcActorRole(expressID, type, Role, UserDefinedRole, Description); + } + ToTape() { + let args = []; + args.push(this.Role); + args.push(this.UserDefinedRole); + args.push(this.Description); + return args; + } +}; +var IfcActuator = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcActuator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcActuatorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcActuatorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAddress = class { + constructor(expressID, type, Purpose, Description, UserDefinedPurpose) { + this.expressID = expressID; + this.type = type; + this.Purpose = Purpose; + this.Description = Description; + this.UserDefinedPurpose = UserDefinedPurpose; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Purpose = tape[ptr++]; + let Description = tape[ptr++]; + let UserDefinedPurpose = tape[ptr++]; + return new IfcAddress(expressID, type, Purpose, Description, UserDefinedPurpose); + } + ToTape() { + let args = []; + args.push(this.Purpose); + args.push(this.Description); + args.push(this.UserDefinedPurpose); + return args; + } +}; +var IfcAdvancedBrep = class { + constructor(expressID, type, Outer) { + this.expressID = expressID; + this.type = type; + this.Outer = Outer; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Outer = tape[ptr++]; + return new IfcAdvancedBrep(expressID, type, Outer); + } + ToTape() { + let args = []; + args.push(this.Outer); + return args; + } +}; +var IfcAdvancedBrepWithVoids = class { + constructor(expressID, type, Outer, Voids) { + this.expressID = expressID; + this.type = type; + this.Outer = Outer; + this.Voids = Voids; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Outer = tape[ptr++]; + let Voids = tape[ptr++]; + return new IfcAdvancedBrepWithVoids(expressID, type, Outer, Voids); + } + ToTape() { + let args = []; + args.push(this.Outer); + args.push(this.Voids); + return args; + } +}; +var IfcAdvancedFace = class { + constructor(expressID, type, Bounds, FaceSurface, SameSense) { + this.expressID = expressID; + this.type = type; + this.Bounds = Bounds; + this.FaceSurface = FaceSurface; + this.SameSense = SameSense; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Bounds = tape[ptr++]; + let FaceSurface = tape[ptr++]; + let SameSense = tape[ptr++]; + return new IfcAdvancedFace(expressID, type, Bounds, FaceSurface, SameSense); + } + ToTape() { + let args = []; + args.push(this.Bounds); + args.push(this.FaceSurface); + args.push(this.SameSense); + return args; + } +}; +var IfcAirTerminal = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAirTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAirTerminalBox = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAirTerminalBox(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAirTerminalBoxType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAirTerminalBoxType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAirTerminalType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAirTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAirToAirHeatRecovery = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAirToAirHeatRecovery(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAirToAirHeatRecoveryType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAirToAirHeatRecoveryType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAlarm = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAlarm(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAlarmType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAlarmType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAlignment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Axis = Axis; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Axis = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAlignment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Axis); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAlignment2DHorizontal = class { + constructor(expressID, type, StartDistAlong, Segments) { + this.expressID = expressID; + this.type = type; + this.StartDistAlong = StartDistAlong; + this.Segments = Segments; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let StartDistAlong = tape[ptr++]; + let Segments = tape[ptr++]; + return new IfcAlignment2DHorizontal(expressID, type, StartDistAlong, Segments); + } + ToTape() { + let args = []; + args.push(this.StartDistAlong); + args.push(this.Segments); + return args; + } +}; +var IfcAlignment2DHorizontalSegment = class { + constructor(expressID, type, TangentialContinuity, StartTag, EndTag, CurveGeometry) { + this.expressID = expressID; + this.type = type; + this.TangentialContinuity = TangentialContinuity; + this.StartTag = StartTag; + this.EndTag = EndTag; + this.CurveGeometry = CurveGeometry; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TangentialContinuity = tape[ptr++]; + let StartTag = tape[ptr++]; + let EndTag = tape[ptr++]; + let CurveGeometry = tape[ptr++]; + return new IfcAlignment2DHorizontalSegment(expressID, type, TangentialContinuity, StartTag, EndTag, CurveGeometry); + } + ToTape() { + let args = []; + args.push(this.TangentialContinuity); + args.push(this.StartTag); + args.push(this.EndTag); + args.push(this.CurveGeometry); + return args; + } +}; +var IfcAlignment2DSegment = class { + constructor(expressID, type, TangentialContinuity, StartTag, EndTag) { + this.expressID = expressID; + this.type = type; + this.TangentialContinuity = TangentialContinuity; + this.StartTag = StartTag; + this.EndTag = EndTag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TangentialContinuity = tape[ptr++]; + let StartTag = tape[ptr++]; + let EndTag = tape[ptr++]; + return new IfcAlignment2DSegment(expressID, type, TangentialContinuity, StartTag, EndTag); + } + ToTape() { + let args = []; + args.push(this.TangentialContinuity); + args.push(this.StartTag); + args.push(this.EndTag); + return args; + } +}; +var IfcAlignment2DVerSegCircularArc = class { + constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, Radius, IsConvex) { + this.expressID = expressID; + this.type = type; + this.TangentialContinuity = TangentialContinuity; + this.StartTag = StartTag; + this.EndTag = EndTag; + this.StartDistAlong = StartDistAlong; + this.HorizontalLength = HorizontalLength; + this.StartHeight = StartHeight; + this.StartGradient = StartGradient; + this.Radius = Radius; + this.IsConvex = IsConvex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TangentialContinuity = tape[ptr++]; + let StartTag = tape[ptr++]; + let EndTag = tape[ptr++]; + let StartDistAlong = tape[ptr++]; + let HorizontalLength = tape[ptr++]; + let StartHeight = tape[ptr++]; + let StartGradient = tape[ptr++]; + let Radius = tape[ptr++]; + let IsConvex = tape[ptr++]; + return new IfcAlignment2DVerSegCircularArc(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, Radius, IsConvex); + } + ToTape() { + let args = []; + args.push(this.TangentialContinuity); + args.push(this.StartTag); + args.push(this.EndTag); + args.push(this.StartDistAlong); + args.push(this.HorizontalLength); + args.push(this.StartHeight); + args.push(this.StartGradient); + args.push(this.Radius); + args.push(this.IsConvex); + return args; + } +}; +var IfcAlignment2DVerSegLine = class { + constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient) { + this.expressID = expressID; + this.type = type; + this.TangentialContinuity = TangentialContinuity; + this.StartTag = StartTag; + this.EndTag = EndTag; + this.StartDistAlong = StartDistAlong; + this.HorizontalLength = HorizontalLength; + this.StartHeight = StartHeight; + this.StartGradient = StartGradient; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TangentialContinuity = tape[ptr++]; + let StartTag = tape[ptr++]; + let EndTag = tape[ptr++]; + let StartDistAlong = tape[ptr++]; + let HorizontalLength = tape[ptr++]; + let StartHeight = tape[ptr++]; + let StartGradient = tape[ptr++]; + return new IfcAlignment2DVerSegLine(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient); + } + ToTape() { + let args = []; + args.push(this.TangentialContinuity); + args.push(this.StartTag); + args.push(this.EndTag); + args.push(this.StartDistAlong); + args.push(this.HorizontalLength); + args.push(this.StartHeight); + args.push(this.StartGradient); + return args; + } +}; +var IfcAlignment2DVerSegParabolicArc = class { + constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, ParabolaConstant, IsConvex) { + this.expressID = expressID; + this.type = type; + this.TangentialContinuity = TangentialContinuity; + this.StartTag = StartTag; + this.EndTag = EndTag; + this.StartDistAlong = StartDistAlong; + this.HorizontalLength = HorizontalLength; + this.StartHeight = StartHeight; + this.StartGradient = StartGradient; + this.ParabolaConstant = ParabolaConstant; + this.IsConvex = IsConvex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TangentialContinuity = tape[ptr++]; + let StartTag = tape[ptr++]; + let EndTag = tape[ptr++]; + let StartDistAlong = tape[ptr++]; + let HorizontalLength = tape[ptr++]; + let StartHeight = tape[ptr++]; + let StartGradient = tape[ptr++]; + let ParabolaConstant = tape[ptr++]; + let IsConvex = tape[ptr++]; + return new IfcAlignment2DVerSegParabolicArc(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient, ParabolaConstant, IsConvex); + } + ToTape() { + let args = []; + args.push(this.TangentialContinuity); + args.push(this.StartTag); + args.push(this.EndTag); + args.push(this.StartDistAlong); + args.push(this.HorizontalLength); + args.push(this.StartHeight); + args.push(this.StartGradient); + args.push(this.ParabolaConstant); + args.push(this.IsConvex); + return args; + } +}; +var IfcAlignment2DVertical = class { + constructor(expressID, type, Segments) { + this.expressID = expressID; + this.type = type; + this.Segments = Segments; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Segments = tape[ptr++]; + return new IfcAlignment2DVertical(expressID, type, Segments); + } + ToTape() { + let args = []; + args.push(this.Segments); + return args; + } +}; +var IfcAlignment2DVerticalSegment = class { + constructor(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient) { + this.expressID = expressID; + this.type = type; + this.TangentialContinuity = TangentialContinuity; + this.StartTag = StartTag; + this.EndTag = EndTag; + this.StartDistAlong = StartDistAlong; + this.HorizontalLength = HorizontalLength; + this.StartHeight = StartHeight; + this.StartGradient = StartGradient; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TangentialContinuity = tape[ptr++]; + let StartTag = tape[ptr++]; + let EndTag = tape[ptr++]; + let StartDistAlong = tape[ptr++]; + let HorizontalLength = tape[ptr++]; + let StartHeight = tape[ptr++]; + let StartGradient = tape[ptr++]; + return new IfcAlignment2DVerticalSegment(expressID, type, TangentialContinuity, StartTag, EndTag, StartDistAlong, HorizontalLength, StartHeight, StartGradient); + } + ToTape() { + let args = []; + args.push(this.TangentialContinuity); + args.push(this.StartTag); + args.push(this.EndTag); + args.push(this.StartDistAlong); + args.push(this.HorizontalLength); + args.push(this.StartHeight); + args.push(this.StartGradient); + return args; + } +}; +var IfcAlignmentCurve = class { + constructor(expressID, type, Horizontal, Vertical, Tag) { + this.expressID = expressID; + this.type = type; + this.Horizontal = Horizontal; + this.Vertical = Vertical; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Horizontal = tape[ptr++]; + let Vertical = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcAlignmentCurve(expressID, type, Horizontal, Vertical, Tag); + } + ToTape() { + let args = []; + args.push(this.Horizontal); + args.push(this.Vertical); + args.push(this.Tag); + return args; + } +}; +var IfcAnnotation = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + return new IfcAnnotation(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + return args; + } +}; +var IfcAnnotationFillArea = class { + constructor(expressID, type, OuterBoundary, InnerBoundaries) { + this.expressID = expressID; + this.type = type; + this.OuterBoundary = OuterBoundary; + this.InnerBoundaries = InnerBoundaries; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let OuterBoundary = tape[ptr++]; + let InnerBoundaries = tape[ptr++]; + return new IfcAnnotationFillArea(expressID, type, OuterBoundary, InnerBoundaries); + } + ToTape() { + let args = []; + args.push(this.OuterBoundary); + args.push(this.InnerBoundaries); + return args; + } +}; +var IfcApplication = class { + constructor(expressID, type, ApplicationDeveloper, Version, ApplicationFullName, ApplicationIdentifier) { + this.expressID = expressID; + this.type = type; + this.ApplicationDeveloper = ApplicationDeveloper; + this.Version = Version; + this.ApplicationFullName = ApplicationFullName; + this.ApplicationIdentifier = ApplicationIdentifier; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ApplicationDeveloper = tape[ptr++]; + let Version = tape[ptr++]; + let ApplicationFullName = tape[ptr++]; + let ApplicationIdentifier = tape[ptr++]; + return new IfcApplication(expressID, type, ApplicationDeveloper, Version, ApplicationFullName, ApplicationIdentifier); + } + ToTape() { + let args = []; + args.push(this.ApplicationDeveloper); + args.push(this.Version); + args.push(this.ApplicationFullName); + args.push(this.ApplicationIdentifier); + return args; + } +}; +var IfcAppliedValue = class { + constructor(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.AppliedValue = AppliedValue; + this.UnitBasis = UnitBasis; + this.ApplicableDate = ApplicableDate; + this.FixedUntilDate = FixedUntilDate; + this.Category = Category; + this.Condition = Condition; + this.ArithmeticOperator = ArithmeticOperator; + this.Components = Components; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let AppliedValue = tape[ptr++]; + let UnitBasis = tape[ptr++]; + let ApplicableDate = tape[ptr++]; + let FixedUntilDate = tape[ptr++]; + let Category = tape[ptr++]; + let Condition = tape[ptr++]; + let ArithmeticOperator = tape[ptr++]; + let Components = tape[ptr++]; + return new IfcAppliedValue(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.AppliedValue); + args.push(this.UnitBasis); + args.push(this.ApplicableDate); + args.push(this.FixedUntilDate); + args.push(this.Category); + args.push(this.Condition); + args.push(this.ArithmeticOperator); + args.push(this.Components); + return args; + } +}; +var IfcApproval = class { + constructor(expressID, type, Identifier, Name, Description, TimeOfApproval, Status, Level, Qualifier, RequestingApproval, GivingApproval) { + this.expressID = expressID; + this.type = type; + this.Identifier = Identifier; + this.Name = Name; + this.Description = Description; + this.TimeOfApproval = TimeOfApproval; + this.Status = Status; + this.Level = Level; + this.Qualifier = Qualifier; + this.RequestingApproval = RequestingApproval; + this.GivingApproval = GivingApproval; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Identifier = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let TimeOfApproval = tape[ptr++]; + let Status = tape[ptr++]; + let Level = tape[ptr++]; + let Qualifier = tape[ptr++]; + let RequestingApproval = tape[ptr++]; + let GivingApproval = tape[ptr++]; + return new IfcApproval(expressID, type, Identifier, Name, Description, TimeOfApproval, Status, Level, Qualifier, RequestingApproval, GivingApproval); + } + ToTape() { + let args = []; + args.push(this.Identifier); + args.push(this.Name); + args.push(this.Description); + args.push(this.TimeOfApproval); + args.push(this.Status); + args.push(this.Level); + args.push(this.Qualifier); + args.push(this.RequestingApproval); + args.push(this.GivingApproval); + return args; + } +}; +var IfcApprovalRelationship = class { + constructor(expressID, type, Name, Description, RelatingApproval, RelatedApprovals) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingApproval = RelatingApproval; + this.RelatedApprovals = RelatedApprovals; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingApproval = tape[ptr++]; + let RelatedApprovals = tape[ptr++]; + return new IfcApprovalRelationship(expressID, type, Name, Description, RelatingApproval, RelatedApprovals); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingApproval); + args.push(this.RelatedApprovals); + return args; + } +}; +var IfcArbitraryClosedProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, OuterCurve) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.OuterCurve = OuterCurve; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let OuterCurve = tape[ptr++]; + return new IfcArbitraryClosedProfileDef(expressID, type, ProfileType, ProfileName, OuterCurve); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.OuterCurve); + return args; + } +}; +var IfcArbitraryOpenProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Curve) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Curve = Curve; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Curve = tape[ptr++]; + return new IfcArbitraryOpenProfileDef(expressID, type, ProfileType, ProfileName, Curve); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Curve); + return args; + } +}; +var IfcArbitraryProfileDefWithVoids = class { + constructor(expressID, type, ProfileType, ProfileName, OuterCurve, InnerCurves) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.OuterCurve = OuterCurve; + this.InnerCurves = InnerCurves; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let OuterCurve = tape[ptr++]; + let InnerCurves = tape[ptr++]; + return new IfcArbitraryProfileDefWithVoids(expressID, type, ProfileType, ProfileName, OuterCurve, InnerCurves); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.OuterCurve); + args.push(this.InnerCurves); + return args; + } +}; +var IfcAsset = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, OriginalValue, CurrentValue, TotalReplacementCost, Owner, User, ResponsiblePerson, IncorporationDate, DepreciatedValue) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.OriginalValue = OriginalValue; + this.CurrentValue = CurrentValue; + this.TotalReplacementCost = TotalReplacementCost; + this.Owner = Owner; + this.User = User; + this.ResponsiblePerson = ResponsiblePerson; + this.IncorporationDate = IncorporationDate; + this.DepreciatedValue = DepreciatedValue; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let OriginalValue = tape[ptr++]; + let CurrentValue = tape[ptr++]; + let TotalReplacementCost = tape[ptr++]; + let Owner = tape[ptr++]; + let User = tape[ptr++]; + let ResponsiblePerson = tape[ptr++]; + let IncorporationDate = tape[ptr++]; + let DepreciatedValue = tape[ptr++]; + return new IfcAsset(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, OriginalValue, CurrentValue, TotalReplacementCost, Owner, User, ResponsiblePerson, IncorporationDate, DepreciatedValue); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.OriginalValue); + args.push(this.CurrentValue); + args.push(this.TotalReplacementCost); + args.push(this.Owner); + args.push(this.User); + args.push(this.ResponsiblePerson); + args.push(this.IncorporationDate); + args.push(this.DepreciatedValue); + return args; + } +}; +var IfcAsymmetricIShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, BottomFlangeWidth, OverallDepth, WebThickness, BottomFlangeThickness, BottomFlangeFilletRadius, TopFlangeWidth, TopFlangeThickness, TopFlangeFilletRadius, BottomFlangeEdgeRadius, BottomFlangeSlope, TopFlangeEdgeRadius, TopFlangeSlope) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.BottomFlangeWidth = BottomFlangeWidth; + this.OverallDepth = OverallDepth; + this.WebThickness = WebThickness; + this.BottomFlangeThickness = BottomFlangeThickness; + this.BottomFlangeFilletRadius = BottomFlangeFilletRadius; + this.TopFlangeWidth = TopFlangeWidth; + this.TopFlangeThickness = TopFlangeThickness; + this.TopFlangeFilletRadius = TopFlangeFilletRadius; + this.BottomFlangeEdgeRadius = BottomFlangeEdgeRadius; + this.BottomFlangeSlope = BottomFlangeSlope; + this.TopFlangeEdgeRadius = TopFlangeEdgeRadius; + this.TopFlangeSlope = TopFlangeSlope; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let BottomFlangeWidth = tape[ptr++]; + let OverallDepth = tape[ptr++]; + let WebThickness = tape[ptr++]; + let BottomFlangeThickness = tape[ptr++]; + let BottomFlangeFilletRadius = tape[ptr++]; + let TopFlangeWidth = tape[ptr++]; + let TopFlangeThickness = tape[ptr++]; + let TopFlangeFilletRadius = tape[ptr++]; + let BottomFlangeEdgeRadius = tape[ptr++]; + let BottomFlangeSlope = tape[ptr++]; + let TopFlangeEdgeRadius = tape[ptr++]; + let TopFlangeSlope = tape[ptr++]; + return new IfcAsymmetricIShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, BottomFlangeWidth, OverallDepth, WebThickness, BottomFlangeThickness, BottomFlangeFilletRadius, TopFlangeWidth, TopFlangeThickness, TopFlangeFilletRadius, BottomFlangeEdgeRadius, BottomFlangeSlope, TopFlangeEdgeRadius, TopFlangeSlope); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.BottomFlangeWidth); + args.push(this.OverallDepth); + args.push(this.WebThickness); + args.push(this.BottomFlangeThickness); + args.push(this.BottomFlangeFilletRadius); + args.push(this.TopFlangeWidth); + args.push(this.TopFlangeThickness); + args.push(this.TopFlangeFilletRadius); + args.push(this.BottomFlangeEdgeRadius); + args.push(this.BottomFlangeSlope); + args.push(this.TopFlangeEdgeRadius); + args.push(this.TopFlangeSlope); + return args; + } +}; +var IfcAudioVisualAppliance = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAudioVisualAppliance(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAudioVisualApplianceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcAudioVisualApplianceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcAxis1Placement = class { + constructor(expressID, type, Location, Axis) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Axis = Axis; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Axis = tape[ptr++]; + return new IfcAxis1Placement(expressID, type, Location, Axis); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Axis); + return args; + } +}; +var IfcAxis2Placement2D = class { + constructor(expressID, type, Location, RefDirection) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.RefDirection = RefDirection; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let RefDirection = tape[ptr++]; + return new IfcAxis2Placement2D(expressID, type, Location, RefDirection); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.RefDirection); + return args; + } +}; +var IfcAxis2Placement3D = class { + constructor(expressID, type, Location, Axis, RefDirection) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Axis = Axis; + this.RefDirection = RefDirection; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Axis = tape[ptr++]; + let RefDirection = tape[ptr++]; + return new IfcAxis2Placement3D(expressID, type, Location, Axis, RefDirection); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Axis); + args.push(this.RefDirection); + return args; + } +}; +var IfcBSplineCurve = class { + constructor(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.Degree = Degree; + this.ControlPointsList = ControlPointsList; + this.CurveForm = CurveForm; + this.ClosedCurve = ClosedCurve; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Degree = tape[ptr++]; + let ControlPointsList = tape[ptr++]; + let CurveForm = tape[ptr++]; + let ClosedCurve = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcBSplineCurve(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.Degree); + args.push(this.ControlPointsList); + args.push(this.CurveForm); + args.push(this.ClosedCurve); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcBSplineCurveWithKnots = class { + constructor(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec) { + this.expressID = expressID; + this.type = type; + this.Degree = Degree; + this.ControlPointsList = ControlPointsList; + this.CurveForm = CurveForm; + this.ClosedCurve = ClosedCurve; + this.SelfIntersect = SelfIntersect; + this.KnotMultiplicities = KnotMultiplicities; + this.Knots = Knots; + this.KnotSpec = KnotSpec; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Degree = tape[ptr++]; + let ControlPointsList = tape[ptr++]; + let CurveForm = tape[ptr++]; + let ClosedCurve = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + let KnotMultiplicities = tape[ptr++]; + let Knots = tape[ptr++]; + let KnotSpec = tape[ptr++]; + return new IfcBSplineCurveWithKnots(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec); + } + ToTape() { + let args = []; + args.push(this.Degree); + args.push(this.ControlPointsList); + args.push(this.CurveForm); + args.push(this.ClosedCurve); + args.push(this.SelfIntersect); + args.push(this.KnotMultiplicities); + args.push(this.Knots); + args.push(this.KnotSpec); + return args; + } +}; +var IfcBSplineSurface = class { + constructor(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.UDegree = UDegree; + this.VDegree = VDegree; + this.ControlPointsList = ControlPointsList; + this.SurfaceForm = SurfaceForm; + this.UClosed = UClosed; + this.VClosed = VClosed; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let UDegree = tape[ptr++]; + let VDegree = tape[ptr++]; + let ControlPointsList = tape[ptr++]; + let SurfaceForm = tape[ptr++]; + let UClosed = tape[ptr++]; + let VClosed = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcBSplineSurface(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.UDegree); + args.push(this.VDegree); + args.push(this.ControlPointsList); + args.push(this.SurfaceForm); + args.push(this.UClosed); + args.push(this.VClosed); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcBSplineSurfaceWithKnots = class { + constructor(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec) { + this.expressID = expressID; + this.type = type; + this.UDegree = UDegree; + this.VDegree = VDegree; + this.ControlPointsList = ControlPointsList; + this.SurfaceForm = SurfaceForm; + this.UClosed = UClosed; + this.VClosed = VClosed; + this.SelfIntersect = SelfIntersect; + this.UMultiplicities = UMultiplicities; + this.VMultiplicities = VMultiplicities; + this.UKnots = UKnots; + this.VKnots = VKnots; + this.KnotSpec = KnotSpec; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let UDegree = tape[ptr++]; + let VDegree = tape[ptr++]; + let ControlPointsList = tape[ptr++]; + let SurfaceForm = tape[ptr++]; + let UClosed = tape[ptr++]; + let VClosed = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + let UMultiplicities = tape[ptr++]; + let VMultiplicities = tape[ptr++]; + let UKnots = tape[ptr++]; + let VKnots = tape[ptr++]; + let KnotSpec = tape[ptr++]; + return new IfcBSplineSurfaceWithKnots(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec); + } + ToTape() { + let args = []; + args.push(this.UDegree); + args.push(this.VDegree); + args.push(this.ControlPointsList); + args.push(this.SurfaceForm); + args.push(this.UClosed); + args.push(this.VClosed); + args.push(this.SelfIntersect); + args.push(this.UMultiplicities); + args.push(this.VMultiplicities); + args.push(this.UKnots); + args.push(this.VKnots); + args.push(this.KnotSpec); + return args; + } +}; +var IfcBeam = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBeam(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBeamStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBeamStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBeamType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBeamType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBearing = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBearing(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBearingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBearingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBlobTexture = class { + constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, RasterFormat, RasterCode) { + this.expressID = expressID; + this.type = type; + this.RepeatS = RepeatS; + this.RepeatT = RepeatT; + this.Mode = Mode; + this.TextureTransform = TextureTransform; + this.Parameter = Parameter; + this.RasterFormat = RasterFormat; + this.RasterCode = RasterCode; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RepeatS = tape[ptr++]; + let RepeatT = tape[ptr++]; + let Mode = tape[ptr++]; + let TextureTransform = tape[ptr++]; + let Parameter = tape[ptr++]; + let RasterFormat = tape[ptr++]; + let RasterCode = tape[ptr++]; + return new IfcBlobTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, RasterFormat, RasterCode); + } + ToTape() { + let args = []; + args.push(this.RepeatS); + args.push(this.RepeatT); + args.push(this.Mode); + args.push(this.TextureTransform); + args.push(this.Parameter); + args.push(this.RasterFormat); + args.push(this.RasterCode); + return args; + } +}; +var IfcBlock = class { + constructor(expressID, type, Position, XLength, YLength, ZLength) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.XLength = XLength; + this.YLength = YLength; + this.ZLength = ZLength; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let XLength = tape[ptr++]; + let YLength = tape[ptr++]; + let ZLength = tape[ptr++]; + return new IfcBlock(expressID, type, Position, XLength, YLength, ZLength); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.XLength); + args.push(this.YLength); + args.push(this.ZLength); + return args; + } +}; +var IfcBoiler = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBoiler(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBoilerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBoilerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBooleanClippingResult = class { + constructor(expressID, type, Operator, FirstOperand, SecondOperand) { + this.expressID = expressID; + this.type = type; + this.Operator = Operator; + this.FirstOperand = FirstOperand; + this.SecondOperand = SecondOperand; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Operator = tape[ptr++]; + let FirstOperand = tape[ptr++]; + let SecondOperand = tape[ptr++]; + return new IfcBooleanClippingResult(expressID, type, Operator, FirstOperand, SecondOperand); + } + ToTape() { + let args = []; + args.push(this.Operator); + args.push(this.FirstOperand); + args.push(this.SecondOperand); + return args; + } +}; +var IfcBooleanResult = class { + constructor(expressID, type, Operator, FirstOperand, SecondOperand) { + this.expressID = expressID; + this.type = type; + this.Operator = Operator; + this.FirstOperand = FirstOperand; + this.SecondOperand = SecondOperand; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Operator = tape[ptr++]; + let FirstOperand = tape[ptr++]; + let SecondOperand = tape[ptr++]; + return new IfcBooleanResult(expressID, type, Operator, FirstOperand, SecondOperand); + } + ToTape() { + let args = []; + args.push(this.Operator); + args.push(this.FirstOperand); + args.push(this.SecondOperand); + return args; + } +}; +var IfcBoundaryCondition = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcBoundaryCondition(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcBoundaryCurve = class { + constructor(expressID, type, Segments, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.Segments = Segments; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Segments = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcBoundaryCurve(expressID, type, Segments, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.Segments); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcBoundaryEdgeCondition = class { + constructor(expressID, type, Name, TranslationalStiffnessByLengthX, TranslationalStiffnessByLengthY, TranslationalStiffnessByLengthZ, RotationalStiffnessByLengthX, RotationalStiffnessByLengthY, RotationalStiffnessByLengthZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.TranslationalStiffnessByLengthX = TranslationalStiffnessByLengthX; + this.TranslationalStiffnessByLengthY = TranslationalStiffnessByLengthY; + this.TranslationalStiffnessByLengthZ = TranslationalStiffnessByLengthZ; + this.RotationalStiffnessByLengthX = RotationalStiffnessByLengthX; + this.RotationalStiffnessByLengthY = RotationalStiffnessByLengthY; + this.RotationalStiffnessByLengthZ = RotationalStiffnessByLengthZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let TranslationalStiffnessByLengthX = tape[ptr++]; + let TranslationalStiffnessByLengthY = tape[ptr++]; + let TranslationalStiffnessByLengthZ = tape[ptr++]; + let RotationalStiffnessByLengthX = tape[ptr++]; + let RotationalStiffnessByLengthY = tape[ptr++]; + let RotationalStiffnessByLengthZ = tape[ptr++]; + return new IfcBoundaryEdgeCondition(expressID, type, Name, TranslationalStiffnessByLengthX, TranslationalStiffnessByLengthY, TranslationalStiffnessByLengthZ, RotationalStiffnessByLengthX, RotationalStiffnessByLengthY, RotationalStiffnessByLengthZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.TranslationalStiffnessByLengthX); + args.push(this.TranslationalStiffnessByLengthY); + args.push(this.TranslationalStiffnessByLengthZ); + args.push(this.RotationalStiffnessByLengthX); + args.push(this.RotationalStiffnessByLengthY); + args.push(this.RotationalStiffnessByLengthZ); + return args; + } +}; +var IfcBoundaryFaceCondition = class { + constructor(expressID, type, Name, TranslationalStiffnessByAreaX, TranslationalStiffnessByAreaY, TranslationalStiffnessByAreaZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.TranslationalStiffnessByAreaX = TranslationalStiffnessByAreaX; + this.TranslationalStiffnessByAreaY = TranslationalStiffnessByAreaY; + this.TranslationalStiffnessByAreaZ = TranslationalStiffnessByAreaZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let TranslationalStiffnessByAreaX = tape[ptr++]; + let TranslationalStiffnessByAreaY = tape[ptr++]; + let TranslationalStiffnessByAreaZ = tape[ptr++]; + return new IfcBoundaryFaceCondition(expressID, type, Name, TranslationalStiffnessByAreaX, TranslationalStiffnessByAreaY, TranslationalStiffnessByAreaZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.TranslationalStiffnessByAreaX); + args.push(this.TranslationalStiffnessByAreaY); + args.push(this.TranslationalStiffnessByAreaZ); + return args; + } +}; +var IfcBoundaryNodeCondition = class { + constructor(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.TranslationalStiffnessX = TranslationalStiffnessX; + this.TranslationalStiffnessY = TranslationalStiffnessY; + this.TranslationalStiffnessZ = TranslationalStiffnessZ; + this.RotationalStiffnessX = RotationalStiffnessX; + this.RotationalStiffnessY = RotationalStiffnessY; + this.RotationalStiffnessZ = RotationalStiffnessZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let TranslationalStiffnessX = tape[ptr++]; + let TranslationalStiffnessY = tape[ptr++]; + let TranslationalStiffnessZ = tape[ptr++]; + let RotationalStiffnessX = tape[ptr++]; + let RotationalStiffnessY = tape[ptr++]; + let RotationalStiffnessZ = tape[ptr++]; + return new IfcBoundaryNodeCondition(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.TranslationalStiffnessX); + args.push(this.TranslationalStiffnessY); + args.push(this.TranslationalStiffnessZ); + args.push(this.RotationalStiffnessX); + args.push(this.RotationalStiffnessY); + args.push(this.RotationalStiffnessZ); + return args; + } +}; +var IfcBoundaryNodeConditionWarping = class { + constructor(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ, WarpingStiffness) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.TranslationalStiffnessX = TranslationalStiffnessX; + this.TranslationalStiffnessY = TranslationalStiffnessY; + this.TranslationalStiffnessZ = TranslationalStiffnessZ; + this.RotationalStiffnessX = RotationalStiffnessX; + this.RotationalStiffnessY = RotationalStiffnessY; + this.RotationalStiffnessZ = RotationalStiffnessZ; + this.WarpingStiffness = WarpingStiffness; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let TranslationalStiffnessX = tape[ptr++]; + let TranslationalStiffnessY = tape[ptr++]; + let TranslationalStiffnessZ = tape[ptr++]; + let RotationalStiffnessX = tape[ptr++]; + let RotationalStiffnessY = tape[ptr++]; + let RotationalStiffnessZ = tape[ptr++]; + let WarpingStiffness = tape[ptr++]; + return new IfcBoundaryNodeConditionWarping(expressID, type, Name, TranslationalStiffnessX, TranslationalStiffnessY, TranslationalStiffnessZ, RotationalStiffnessX, RotationalStiffnessY, RotationalStiffnessZ, WarpingStiffness); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.TranslationalStiffnessX); + args.push(this.TranslationalStiffnessY); + args.push(this.TranslationalStiffnessZ); + args.push(this.RotationalStiffnessX); + args.push(this.RotationalStiffnessY); + args.push(this.RotationalStiffnessZ); + args.push(this.WarpingStiffness); + return args; + } +}; +var IfcBoundedCurve = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcBoundedCurve(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcBoundedSurface = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcBoundedSurface(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcBoundingBox = class { + constructor(expressID, type, Corner, XDim, YDim, ZDim) { + this.expressID = expressID; + this.type = type; + this.Corner = Corner; + this.XDim = XDim; + this.YDim = YDim; + this.ZDim = ZDim; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Corner = tape[ptr++]; + let XDim = tape[ptr++]; + let YDim = tape[ptr++]; + let ZDim = tape[ptr++]; + return new IfcBoundingBox(expressID, type, Corner, XDim, YDim, ZDim); + } + ToTape() { + let args = []; + args.push(this.Corner); + args.push(this.XDim); + args.push(this.YDim); + args.push(this.ZDim); + return args; + } +}; +var IfcBoxedHalfSpace = class { + constructor(expressID, type, BaseSurface, AgreementFlag, Enclosure) { + this.expressID = expressID; + this.type = type; + this.BaseSurface = BaseSurface; + this.AgreementFlag = AgreementFlag; + this.Enclosure = Enclosure; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BaseSurface = tape[ptr++]; + let AgreementFlag = tape[ptr++]; + let Enclosure = tape[ptr++]; + return new IfcBoxedHalfSpace(expressID, type, BaseSurface, AgreementFlag, Enclosure); + } + ToTape() { + let args = []; + args.push(this.BaseSurface); + args.push(this.AgreementFlag); + args.push(this.Enclosure); + return args; + } +}; +var IfcBridge = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBridge(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBridgePart = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBridgePart(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBuilding = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, ElevationOfRefHeight, ElevationOfTerrain, BuildingAddress) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + this.ElevationOfRefHeight = ElevationOfRefHeight; + this.ElevationOfTerrain = ElevationOfTerrain; + this.BuildingAddress = BuildingAddress; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + let ElevationOfRefHeight = tape[ptr++]; + let ElevationOfTerrain = tape[ptr++]; + let BuildingAddress = tape[ptr++]; + return new IfcBuilding(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, ElevationOfRefHeight, ElevationOfTerrain, BuildingAddress); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + args.push(this.ElevationOfRefHeight); + args.push(this.ElevationOfTerrain); + args.push(this.BuildingAddress); + return args; + } +}; +var IfcBuildingElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcBuildingElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcBuildingElementPart = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBuildingElementPart(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBuildingElementPartType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBuildingElementPartType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBuildingElementProxy = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBuildingElementProxy(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBuildingElementProxyType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBuildingElementProxyType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBuildingElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcBuildingElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcBuildingStorey = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, Elevation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + this.Elevation = Elevation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + let Elevation = tape[ptr++]; + return new IfcBuildingStorey(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, Elevation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + args.push(this.Elevation); + return args; + } +}; +var IfcBuildingSystem = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, LongName) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.PredefinedType = PredefinedType; + this.LongName = LongName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let LongName = tape[ptr++]; + return new IfcBuildingSystem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, LongName); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.PredefinedType); + args.push(this.LongName); + return args; + } +}; +var IfcBurner = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBurner(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcBurnerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcBurnerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Depth, Width, WallThickness, Girth, InternalFilletRadius) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Depth = Depth; + this.Width = Width; + this.WallThickness = WallThickness; + this.Girth = Girth; + this.InternalFilletRadius = InternalFilletRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Depth = tape[ptr++]; + let Width = tape[ptr++]; + let WallThickness = tape[ptr++]; + let Girth = tape[ptr++]; + let InternalFilletRadius = tape[ptr++]; + return new IfcCShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, Width, WallThickness, Girth, InternalFilletRadius); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Depth); + args.push(this.Width); + args.push(this.WallThickness); + args.push(this.Girth); + args.push(this.InternalFilletRadius); + return args; + } +}; +var IfcCableCarrierFitting = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableCarrierFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableCarrierFittingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableCarrierFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableCarrierSegment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableCarrierSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableCarrierSegmentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableCarrierSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableFitting = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableFittingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableSegment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCableSegmentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCableSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCaissonFoundation = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCaissonFoundation(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCaissonFoundationType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCaissonFoundationType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCartesianPoint = class { + constructor(expressID, type, Coordinates) { + this.expressID = expressID; + this.type = type; + this.Coordinates = Coordinates; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Coordinates = tape[ptr++]; + return new IfcCartesianPoint(expressID, type, Coordinates); + } + ToTape() { + let args = []; + args.push(this.Coordinates); + return args; + } +}; +var IfcCartesianPointList = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcCartesianPointList(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcCartesianPointList2D = class { + constructor(expressID, type, CoordList, TagList) { + this.expressID = expressID; + this.type = type; + this.CoordList = CoordList; + this.TagList = TagList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CoordList = tape[ptr++]; + let TagList = tape[ptr++]; + return new IfcCartesianPointList2D(expressID, type, CoordList, TagList); + } + ToTape() { + let args = []; + args.push(this.CoordList); + args.push(this.TagList); + return args; + } +}; +var IfcCartesianPointList3D = class { + constructor(expressID, type, CoordList, TagList) { + this.expressID = expressID; + this.type = type; + this.CoordList = CoordList; + this.TagList = TagList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CoordList = tape[ptr++]; + let TagList = tape[ptr++]; + return new IfcCartesianPointList3D(expressID, type, CoordList, TagList); + } + ToTape() { + let args = []; + args.push(this.CoordList); + args.push(this.TagList); + return args; + } +}; +var IfcCartesianTransformationOperator = class { + constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale) { + this.expressID = expressID; + this.type = type; + this.Axis1 = Axis1; + this.Axis2 = Axis2; + this.LocalOrigin = LocalOrigin; + this.Scale = Scale; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Axis1 = tape[ptr++]; + let Axis2 = tape[ptr++]; + let LocalOrigin = tape[ptr++]; + let Scale = tape[ptr++]; + return new IfcCartesianTransformationOperator(expressID, type, Axis1, Axis2, LocalOrigin, Scale); + } + ToTape() { + let args = []; + args.push(this.Axis1); + args.push(this.Axis2); + args.push(this.LocalOrigin); + args.push(this.Scale); + return args; + } +}; +var IfcCartesianTransformationOperator2D = class { + constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale) { + this.expressID = expressID; + this.type = type; + this.Axis1 = Axis1; + this.Axis2 = Axis2; + this.LocalOrigin = LocalOrigin; + this.Scale = Scale; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Axis1 = tape[ptr++]; + let Axis2 = tape[ptr++]; + let LocalOrigin = tape[ptr++]; + let Scale = tape[ptr++]; + return new IfcCartesianTransformationOperator2D(expressID, type, Axis1, Axis2, LocalOrigin, Scale); + } + ToTape() { + let args = []; + args.push(this.Axis1); + args.push(this.Axis2); + args.push(this.LocalOrigin); + args.push(this.Scale); + return args; + } +}; +var IfcCartesianTransformationOperator2DnonUniform = class { + constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Scale2) { + this.expressID = expressID; + this.type = type; + this.Axis1 = Axis1; + this.Axis2 = Axis2; + this.LocalOrigin = LocalOrigin; + this.Scale = Scale; + this.Scale2 = Scale2; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Axis1 = tape[ptr++]; + let Axis2 = tape[ptr++]; + let LocalOrigin = tape[ptr++]; + let Scale = tape[ptr++]; + let Scale2 = tape[ptr++]; + return new IfcCartesianTransformationOperator2DnonUniform(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Scale2); + } + ToTape() { + let args = []; + args.push(this.Axis1); + args.push(this.Axis2); + args.push(this.LocalOrigin); + args.push(this.Scale); + args.push(this.Scale2); + return args; + } +}; +var IfcCartesianTransformationOperator3D = class { + constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3) { + this.expressID = expressID; + this.type = type; + this.Axis1 = Axis1; + this.Axis2 = Axis2; + this.LocalOrigin = LocalOrigin; + this.Scale = Scale; + this.Axis3 = Axis3; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Axis1 = tape[ptr++]; + let Axis2 = tape[ptr++]; + let LocalOrigin = tape[ptr++]; + let Scale = tape[ptr++]; + let Axis3 = tape[ptr++]; + return new IfcCartesianTransformationOperator3D(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3); + } + ToTape() { + let args = []; + args.push(this.Axis1); + args.push(this.Axis2); + args.push(this.LocalOrigin); + args.push(this.Scale); + args.push(this.Axis3); + return args; + } +}; +var IfcCartesianTransformationOperator3DnonUniform = class { + constructor(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3, Scale2, Scale3) { + this.expressID = expressID; + this.type = type; + this.Axis1 = Axis1; + this.Axis2 = Axis2; + this.LocalOrigin = LocalOrigin; + this.Scale = Scale; + this.Axis3 = Axis3; + this.Scale2 = Scale2; + this.Scale3 = Scale3; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Axis1 = tape[ptr++]; + let Axis2 = tape[ptr++]; + let LocalOrigin = tape[ptr++]; + let Scale = tape[ptr++]; + let Axis3 = tape[ptr++]; + let Scale2 = tape[ptr++]; + let Scale3 = tape[ptr++]; + return new IfcCartesianTransformationOperator3DnonUniform(expressID, type, Axis1, Axis2, LocalOrigin, Scale, Axis3, Scale2, Scale3); + } + ToTape() { + let args = []; + args.push(this.Axis1); + args.push(this.Axis2); + args.push(this.LocalOrigin); + args.push(this.Scale); + args.push(this.Axis3); + args.push(this.Scale2); + args.push(this.Scale3); + return args; + } +}; +var IfcCenterLineProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Curve, Thickness) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Curve = Curve; + this.Thickness = Thickness; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Curve = tape[ptr++]; + let Thickness = tape[ptr++]; + return new IfcCenterLineProfileDef(expressID, type, ProfileType, ProfileName, Curve, Thickness); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Curve); + args.push(this.Thickness); + return args; + } +}; +var IfcChiller = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcChiller(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcChillerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcChillerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcChimney = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcChimney(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcChimneyType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcChimneyType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCircle = class { + constructor(expressID, type, Position, Radius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.Radius = Radius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + return new IfcCircle(expressID, type, Position, Radius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.Radius); + return args; + } +}; +var IfcCircleHollowProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Radius, WallThickness) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Radius = Radius; + this.WallThickness = WallThickness; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + let WallThickness = tape[ptr++]; + return new IfcCircleHollowProfileDef(expressID, type, ProfileType, ProfileName, Position, Radius, WallThickness); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Radius); + args.push(this.WallThickness); + return args; + } +}; +var IfcCircleProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Radius) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Radius = Radius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + return new IfcCircleProfileDef(expressID, type, ProfileType, ProfileName, Position, Radius); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Radius); + return args; + } +}; +var IfcCircularArcSegment2D = class { + constructor(expressID, type, StartPoint, StartDirection, SegmentLength, Radius, IsCCW) { + this.expressID = expressID; + this.type = type; + this.StartPoint = StartPoint; + this.StartDirection = StartDirection; + this.SegmentLength = SegmentLength; + this.Radius = Radius; + this.IsCCW = IsCCW; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let StartPoint = tape[ptr++]; + let StartDirection = tape[ptr++]; + let SegmentLength = tape[ptr++]; + let Radius = tape[ptr++]; + let IsCCW = tape[ptr++]; + return new IfcCircularArcSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength, Radius, IsCCW); + } + ToTape() { + let args = []; + args.push(this.StartPoint); + args.push(this.StartDirection); + args.push(this.SegmentLength); + args.push(this.Radius); + args.push(this.IsCCW); + return args; + } +}; +var IfcCivilElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcCivilElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcCivilElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcCivilElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcClassification = class { + constructor(expressID, type, Source, Edition, EditionDate, Name, Description, Location, ReferenceTokens) { + this.expressID = expressID; + this.type = type; + this.Source = Source; + this.Edition = Edition; + this.EditionDate = EditionDate; + this.Name = Name; + this.Description = Description; + this.Location = Location; + this.ReferenceTokens = ReferenceTokens; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Source = tape[ptr++]; + let Edition = tape[ptr++]; + let EditionDate = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Location = tape[ptr++]; + let ReferenceTokens = tape[ptr++]; + return new IfcClassification(expressID, type, Source, Edition, EditionDate, Name, Description, Location, ReferenceTokens); + } + ToTape() { + let args = []; + args.push(this.Source); + args.push(this.Edition); + args.push(this.EditionDate); + args.push(this.Name); + args.push(this.Description); + args.push(this.Location); + args.push(this.ReferenceTokens); + return args; + } +}; +var IfcClassificationReference = class { + constructor(expressID, type, Location, Identification, Name, ReferencedSource, Description, Sort) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + this.ReferencedSource = ReferencedSource; + this.Description = Description; + this.Sort = Sort; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + let ReferencedSource = tape[ptr++]; + let Description = tape[ptr++]; + let Sort = tape[ptr++]; + return new IfcClassificationReference(expressID, type, Location, Identification, Name, ReferencedSource, Description, Sort); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + args.push(this.ReferencedSource); + args.push(this.Description); + args.push(this.Sort); + return args; + } +}; +var IfcClosedShell = class { + constructor(expressID, type, CfsFaces) { + this.expressID = expressID; + this.type = type; + this.CfsFaces = CfsFaces; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CfsFaces = tape[ptr++]; + return new IfcClosedShell(expressID, type, CfsFaces); + } + ToTape() { + let args = []; + args.push(this.CfsFaces); + return args; + } +}; +var IfcCoil = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCoil(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCoilType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCoilType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcColourRgb = class { + constructor(expressID, type, Name, Red, Green, Blue) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Red = Red; + this.Green = Green; + this.Blue = Blue; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Red = tape[ptr++]; + let Green = tape[ptr++]; + let Blue = tape[ptr++]; + return new IfcColourRgb(expressID, type, Name, Red, Green, Blue); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Red); + args.push(this.Green); + args.push(this.Blue); + return args; + } +}; +var IfcColourRgbList = class { + constructor(expressID, type, ColourList) { + this.expressID = expressID; + this.type = type; + this.ColourList = ColourList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ColourList = tape[ptr++]; + return new IfcColourRgbList(expressID, type, ColourList); + } + ToTape() { + let args = []; + args.push(this.ColourList); + return args; + } +}; +var IfcColourSpecification = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcColourSpecification(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcColumn = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcColumn(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcColumnStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcColumnStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcColumnType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcColumnType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCommunicationsAppliance = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCommunicationsAppliance(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCommunicationsApplianceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCommunicationsApplianceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcComplexProperty = class { + constructor(expressID, type, Name, Description, UsageName, HasProperties) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.UsageName = UsageName; + this.HasProperties = HasProperties; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let UsageName = tape[ptr++]; + let HasProperties = tape[ptr++]; + return new IfcComplexProperty(expressID, type, Name, Description, UsageName, HasProperties); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.UsageName); + args.push(this.HasProperties); + return args; + } +}; +var IfcComplexPropertyTemplate = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, UsageName, TemplateType, HasPropertyTemplates) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.UsageName = UsageName; + this.TemplateType = TemplateType; + this.HasPropertyTemplates = HasPropertyTemplates; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let UsageName = tape[ptr++]; + let TemplateType = tape[ptr++]; + let HasPropertyTemplates = tape[ptr++]; + return new IfcComplexPropertyTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, UsageName, TemplateType, HasPropertyTemplates); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.UsageName); + args.push(this.TemplateType); + args.push(this.HasPropertyTemplates); + return args; + } +}; +var IfcCompositeCurve = class { + constructor(expressID, type, Segments, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.Segments = Segments; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Segments = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcCompositeCurve(expressID, type, Segments, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.Segments); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcCompositeCurveOnSurface = class { + constructor(expressID, type, Segments, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.Segments = Segments; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Segments = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcCompositeCurveOnSurface(expressID, type, Segments, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.Segments); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcCompositeCurveSegment = class { + constructor(expressID, type, Transition, SameSense, ParentCurve) { + this.expressID = expressID; + this.type = type; + this.Transition = Transition; + this.SameSense = SameSense; + this.ParentCurve = ParentCurve; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Transition = tape[ptr++]; + let SameSense = tape[ptr++]; + let ParentCurve = tape[ptr++]; + return new IfcCompositeCurveSegment(expressID, type, Transition, SameSense, ParentCurve); + } + ToTape() { + let args = []; + args.push(this.Transition); + args.push(this.SameSense); + args.push(this.ParentCurve); + return args; + } +}; +var IfcCompositeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Profiles, Label) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Profiles = Profiles; + this.Label = Label; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Profiles = tape[ptr++]; + let Label = tape[ptr++]; + return new IfcCompositeProfileDef(expressID, type, ProfileType, ProfileName, Profiles, Label); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Profiles); + args.push(this.Label); + return args; + } +}; +var IfcCompressor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCompressor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCompressorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCompressorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCondenser = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCondenser(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCondenserType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCondenserType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConic = class { + constructor(expressID, type, Position) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + return new IfcConic(expressID, type, Position); + } + ToTape() { + let args = []; + args.push(this.Position); + return args; + } +}; +var IfcConnectedFaceSet = class { + constructor(expressID, type, CfsFaces) { + this.expressID = expressID; + this.type = type; + this.CfsFaces = CfsFaces; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CfsFaces = tape[ptr++]; + return new IfcConnectedFaceSet(expressID, type, CfsFaces); + } + ToTape() { + let args = []; + args.push(this.CfsFaces); + return args; + } +}; +var IfcConnectionCurveGeometry = class { + constructor(expressID, type, CurveOnRelatingElement, CurveOnRelatedElement) { + this.expressID = expressID; + this.type = type; + this.CurveOnRelatingElement = CurveOnRelatingElement; + this.CurveOnRelatedElement = CurveOnRelatedElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CurveOnRelatingElement = tape[ptr++]; + let CurveOnRelatedElement = tape[ptr++]; + return new IfcConnectionCurveGeometry(expressID, type, CurveOnRelatingElement, CurveOnRelatedElement); + } + ToTape() { + let args = []; + args.push(this.CurveOnRelatingElement); + args.push(this.CurveOnRelatedElement); + return args; + } +}; +var IfcConnectionGeometry = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcConnectionGeometry(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcConnectionPointEccentricity = class { + constructor(expressID, type, PointOnRelatingElement, PointOnRelatedElement, EccentricityInX, EccentricityInY, EccentricityInZ) { + this.expressID = expressID; + this.type = type; + this.PointOnRelatingElement = PointOnRelatingElement; + this.PointOnRelatedElement = PointOnRelatedElement; + this.EccentricityInX = EccentricityInX; + this.EccentricityInY = EccentricityInY; + this.EccentricityInZ = EccentricityInZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let PointOnRelatingElement = tape[ptr++]; + let PointOnRelatedElement = tape[ptr++]; + let EccentricityInX = tape[ptr++]; + let EccentricityInY = tape[ptr++]; + let EccentricityInZ = tape[ptr++]; + return new IfcConnectionPointEccentricity(expressID, type, PointOnRelatingElement, PointOnRelatedElement, EccentricityInX, EccentricityInY, EccentricityInZ); + } + ToTape() { + let args = []; + args.push(this.PointOnRelatingElement); + args.push(this.PointOnRelatedElement); + args.push(this.EccentricityInX); + args.push(this.EccentricityInY); + args.push(this.EccentricityInZ); + return args; + } +}; +var IfcConnectionPointGeometry = class { + constructor(expressID, type, PointOnRelatingElement, PointOnRelatedElement) { + this.expressID = expressID; + this.type = type; + this.PointOnRelatingElement = PointOnRelatingElement; + this.PointOnRelatedElement = PointOnRelatedElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let PointOnRelatingElement = tape[ptr++]; + let PointOnRelatedElement = tape[ptr++]; + return new IfcConnectionPointGeometry(expressID, type, PointOnRelatingElement, PointOnRelatedElement); + } + ToTape() { + let args = []; + args.push(this.PointOnRelatingElement); + args.push(this.PointOnRelatedElement); + return args; + } +}; +var IfcConnectionSurfaceGeometry = class { + constructor(expressID, type, SurfaceOnRelatingElement, SurfaceOnRelatedElement) { + this.expressID = expressID; + this.type = type; + this.SurfaceOnRelatingElement = SurfaceOnRelatingElement; + this.SurfaceOnRelatedElement = SurfaceOnRelatedElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SurfaceOnRelatingElement = tape[ptr++]; + let SurfaceOnRelatedElement = tape[ptr++]; + return new IfcConnectionSurfaceGeometry(expressID, type, SurfaceOnRelatingElement, SurfaceOnRelatedElement); + } + ToTape() { + let args = []; + args.push(this.SurfaceOnRelatingElement); + args.push(this.SurfaceOnRelatedElement); + return args; + } +}; +var IfcConnectionVolumeGeometry = class { + constructor(expressID, type, VolumeOnRelatingElement, VolumeOnRelatedElement) { + this.expressID = expressID; + this.type = type; + this.VolumeOnRelatingElement = VolumeOnRelatingElement; + this.VolumeOnRelatedElement = VolumeOnRelatedElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let VolumeOnRelatingElement = tape[ptr++]; + let VolumeOnRelatedElement = tape[ptr++]; + return new IfcConnectionVolumeGeometry(expressID, type, VolumeOnRelatingElement, VolumeOnRelatedElement); + } + ToTape() { + let args = []; + args.push(this.VolumeOnRelatingElement); + args.push(this.VolumeOnRelatedElement); + return args; + } +}; +var IfcConstraint = class { + constructor(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.ConstraintGrade = ConstraintGrade; + this.ConstraintSource = ConstraintSource; + this.CreatingActor = CreatingActor; + this.CreationTime = CreationTime; + this.UserDefinedGrade = UserDefinedGrade; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ConstraintGrade = tape[ptr++]; + let ConstraintSource = tape[ptr++]; + let CreatingActor = tape[ptr++]; + let CreationTime = tape[ptr++]; + let UserDefinedGrade = tape[ptr++]; + return new IfcConstraint(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.ConstraintGrade); + args.push(this.ConstraintSource); + args.push(this.CreatingActor); + args.push(this.CreationTime); + args.push(this.UserDefinedGrade); + return args; + } +}; +var IfcConstructionEquipmentResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcConstructionEquipmentResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConstructionEquipmentResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcConstructionEquipmentResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConstructionMaterialResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcConstructionMaterialResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConstructionMaterialResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcConstructionMaterialResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConstructionProductResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcConstructionProductResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConstructionProductResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcConstructionProductResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConstructionResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + return new IfcConstructionResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + return args; + } +}; +var IfcConstructionResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + return new IfcConstructionResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + return args; + } +}; +var IfcContext = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.LongName = LongName; + this.Phase = Phase; + this.RepresentationContexts = RepresentationContexts; + this.UnitsInContext = UnitsInContext; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let LongName = tape[ptr++]; + let Phase = tape[ptr++]; + let RepresentationContexts = tape[ptr++]; + let UnitsInContext = tape[ptr++]; + return new IfcContext(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.LongName); + args.push(this.Phase); + args.push(this.RepresentationContexts); + args.push(this.UnitsInContext); + return args; + } +}; +var IfcContextDependentUnit = class { + constructor(expressID, type, Dimensions, UnitType, Name) { + this.expressID = expressID; + this.type = type; + this.Dimensions = Dimensions; + this.UnitType = UnitType; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Dimensions = tape[ptr++]; + let UnitType = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcContextDependentUnit(expressID, type, Dimensions, UnitType, Name); + } + ToTape() { + let args = []; + args.push(this.Dimensions); + args.push(this.UnitType); + args.push(this.Name); + return args; + } +}; +var IfcControl = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + return new IfcControl(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + return args; + } +}; +var IfcController = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcController(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcControllerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcControllerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcConversionBasedUnit = class { + constructor(expressID, type, Dimensions, UnitType, Name, ConversionFactor) { + this.expressID = expressID; + this.type = type; + this.Dimensions = Dimensions; + this.UnitType = UnitType; + this.Name = Name; + this.ConversionFactor = ConversionFactor; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Dimensions = tape[ptr++]; + let UnitType = tape[ptr++]; + let Name = tape[ptr++]; + let ConversionFactor = tape[ptr++]; + return new IfcConversionBasedUnit(expressID, type, Dimensions, UnitType, Name, ConversionFactor); + } + ToTape() { + let args = []; + args.push(this.Dimensions); + args.push(this.UnitType); + args.push(this.Name); + args.push(this.ConversionFactor); + return args; + } +}; +var IfcConversionBasedUnitWithOffset = class { + constructor(expressID, type, Dimensions, UnitType, Name, ConversionFactor, ConversionOffset) { + this.expressID = expressID; + this.type = type; + this.Dimensions = Dimensions; + this.UnitType = UnitType; + this.Name = Name; + this.ConversionFactor = ConversionFactor; + this.ConversionOffset = ConversionOffset; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Dimensions = tape[ptr++]; + let UnitType = tape[ptr++]; + let Name = tape[ptr++]; + let ConversionFactor = tape[ptr++]; + let ConversionOffset = tape[ptr++]; + return new IfcConversionBasedUnitWithOffset(expressID, type, Dimensions, UnitType, Name, ConversionFactor, ConversionOffset); + } + ToTape() { + let args = []; + args.push(this.Dimensions); + args.push(this.UnitType); + args.push(this.Name); + args.push(this.ConversionFactor); + args.push(this.ConversionOffset); + return args; + } +}; +var IfcCooledBeam = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCooledBeam(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCooledBeamType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCooledBeamType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCoolingTower = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCoolingTower(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCoolingTowerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCoolingTowerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCoordinateOperation = class { + constructor(expressID, type, SourceCRS, TargetCRS) { + this.expressID = expressID; + this.type = type; + this.SourceCRS = SourceCRS; + this.TargetCRS = TargetCRS; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SourceCRS = tape[ptr++]; + let TargetCRS = tape[ptr++]; + return new IfcCoordinateOperation(expressID, type, SourceCRS, TargetCRS); + } + ToTape() { + let args = []; + args.push(this.SourceCRS); + args.push(this.TargetCRS); + return args; + } +}; +var IfcCoordinateReferenceSystem = class { + constructor(expressID, type, Name, Description, GeodeticDatum, VerticalDatum) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.GeodeticDatum = GeodeticDatum; + this.VerticalDatum = VerticalDatum; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let GeodeticDatum = tape[ptr++]; + let VerticalDatum = tape[ptr++]; + return new IfcCoordinateReferenceSystem(expressID, type, Name, Description, GeodeticDatum, VerticalDatum); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.GeodeticDatum); + args.push(this.VerticalDatum); + return args; + } +}; +var IfcCostItem = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, CostValues, CostQuantities) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.PredefinedType = PredefinedType; + this.CostValues = CostValues; + this.CostQuantities = CostQuantities; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let CostValues = tape[ptr++]; + let CostQuantities = tape[ptr++]; + return new IfcCostItem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, CostValues, CostQuantities); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.PredefinedType); + args.push(this.CostValues); + args.push(this.CostQuantities); + return args; + } +}; +var IfcCostSchedule = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, SubmittedOn, UpdateDate) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.PredefinedType = PredefinedType; + this.Status = Status; + this.SubmittedOn = SubmittedOn; + this.UpdateDate = UpdateDate; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Status = tape[ptr++]; + let SubmittedOn = tape[ptr++]; + let UpdateDate = tape[ptr++]; + return new IfcCostSchedule(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, SubmittedOn, UpdateDate); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.PredefinedType); + args.push(this.Status); + args.push(this.SubmittedOn); + args.push(this.UpdateDate); + return args; + } +}; +var IfcCostValue = class { + constructor(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.AppliedValue = AppliedValue; + this.UnitBasis = UnitBasis; + this.ApplicableDate = ApplicableDate; + this.FixedUntilDate = FixedUntilDate; + this.Category = Category; + this.Condition = Condition; + this.ArithmeticOperator = ArithmeticOperator; + this.Components = Components; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let AppliedValue = tape[ptr++]; + let UnitBasis = tape[ptr++]; + let ApplicableDate = tape[ptr++]; + let FixedUntilDate = tape[ptr++]; + let Category = tape[ptr++]; + let Condition = tape[ptr++]; + let ArithmeticOperator = tape[ptr++]; + let Components = tape[ptr++]; + return new IfcCostValue(expressID, type, Name, Description, AppliedValue, UnitBasis, ApplicableDate, FixedUntilDate, Category, Condition, ArithmeticOperator, Components); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.AppliedValue); + args.push(this.UnitBasis); + args.push(this.ApplicableDate); + args.push(this.FixedUntilDate); + args.push(this.Category); + args.push(this.Condition); + args.push(this.ArithmeticOperator); + args.push(this.Components); + return args; + } +}; +var IfcCovering = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCovering(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCoveringType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCoveringType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCrewResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCrewResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCrewResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCrewResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCsgPrimitive3D = class { + constructor(expressID, type, Position) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + return new IfcCsgPrimitive3D(expressID, type, Position); + } + ToTape() { + let args = []; + args.push(this.Position); + return args; + } +}; +var IfcCsgSolid = class { + constructor(expressID, type, TreeRootExpression) { + this.expressID = expressID; + this.type = type; + this.TreeRootExpression = TreeRootExpression; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TreeRootExpression = tape[ptr++]; + return new IfcCsgSolid(expressID, type, TreeRootExpression); + } + ToTape() { + let args = []; + args.push(this.TreeRootExpression); + return args; + } +}; +var IfcCurrencyRelationship = class { + constructor(expressID, type, Name, Description, RelatingMonetaryUnit, RelatedMonetaryUnit, ExchangeRate, RateDateTime, RateSource) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingMonetaryUnit = RelatingMonetaryUnit; + this.RelatedMonetaryUnit = RelatedMonetaryUnit; + this.ExchangeRate = ExchangeRate; + this.RateDateTime = RateDateTime; + this.RateSource = RateSource; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingMonetaryUnit = tape[ptr++]; + let RelatedMonetaryUnit = tape[ptr++]; + let ExchangeRate = tape[ptr++]; + let RateDateTime = tape[ptr++]; + let RateSource = tape[ptr++]; + return new IfcCurrencyRelationship(expressID, type, Name, Description, RelatingMonetaryUnit, RelatedMonetaryUnit, ExchangeRate, RateDateTime, RateSource); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingMonetaryUnit); + args.push(this.RelatedMonetaryUnit); + args.push(this.ExchangeRate); + args.push(this.RateDateTime); + args.push(this.RateSource); + return args; + } +}; +var IfcCurtainWall = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCurtainWall(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCurtainWallType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcCurtainWallType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcCurve = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcCurve(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcCurveBoundedPlane = class { + constructor(expressID, type, BasisSurface, OuterBoundary, InnerBoundaries) { + this.expressID = expressID; + this.type = type; + this.BasisSurface = BasisSurface; + this.OuterBoundary = OuterBoundary; + this.InnerBoundaries = InnerBoundaries; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisSurface = tape[ptr++]; + let OuterBoundary = tape[ptr++]; + let InnerBoundaries = tape[ptr++]; + return new IfcCurveBoundedPlane(expressID, type, BasisSurface, OuterBoundary, InnerBoundaries); + } + ToTape() { + let args = []; + args.push(this.BasisSurface); + args.push(this.OuterBoundary); + args.push(this.InnerBoundaries); + return args; + } +}; +var IfcCurveBoundedSurface = class { + constructor(expressID, type, BasisSurface, Boundaries, ImplicitOuter) { + this.expressID = expressID; + this.type = type; + this.BasisSurface = BasisSurface; + this.Boundaries = Boundaries; + this.ImplicitOuter = ImplicitOuter; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisSurface = tape[ptr++]; + let Boundaries = tape[ptr++]; + let ImplicitOuter = tape[ptr++]; + return new IfcCurveBoundedSurface(expressID, type, BasisSurface, Boundaries, ImplicitOuter); + } + ToTape() { + let args = []; + args.push(this.BasisSurface); + args.push(this.Boundaries); + args.push(this.ImplicitOuter); + return args; + } +}; +var IfcCurveSegment2D = class { + constructor(expressID, type, StartPoint, StartDirection, SegmentLength) { + this.expressID = expressID; + this.type = type; + this.StartPoint = StartPoint; + this.StartDirection = StartDirection; + this.SegmentLength = SegmentLength; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let StartPoint = tape[ptr++]; + let StartDirection = tape[ptr++]; + let SegmentLength = tape[ptr++]; + return new IfcCurveSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength); + } + ToTape() { + let args = []; + args.push(this.StartPoint); + args.push(this.StartDirection); + args.push(this.SegmentLength); + return args; + } +}; +var IfcCurveStyle = class { + constructor(expressID, type, Name, CurveFont, CurveWidth, CurveColour, ModelOrDraughting) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.CurveFont = CurveFont; + this.CurveWidth = CurveWidth; + this.CurveColour = CurveColour; + this.ModelOrDraughting = ModelOrDraughting; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let CurveFont = tape[ptr++]; + let CurveWidth = tape[ptr++]; + let CurveColour = tape[ptr++]; + let ModelOrDraughting = tape[ptr++]; + return new IfcCurveStyle(expressID, type, Name, CurveFont, CurveWidth, CurveColour, ModelOrDraughting); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.CurveFont); + args.push(this.CurveWidth); + args.push(this.CurveColour); + args.push(this.ModelOrDraughting); + return args; + } +}; +var IfcCurveStyleFont = class { + constructor(expressID, type, Name, PatternList) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.PatternList = PatternList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let PatternList = tape[ptr++]; + return new IfcCurveStyleFont(expressID, type, Name, PatternList); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.PatternList); + return args; + } +}; +var IfcCurveStyleFontAndScaling = class { + constructor(expressID, type, Name, CurveFont, CurveFontScaling) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.CurveFont = CurveFont; + this.CurveFontScaling = CurveFontScaling; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let CurveFont = tape[ptr++]; + let CurveFontScaling = tape[ptr++]; + return new IfcCurveStyleFontAndScaling(expressID, type, Name, CurveFont, CurveFontScaling); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.CurveFont); + args.push(this.CurveFontScaling); + return args; + } +}; +var IfcCurveStyleFontPattern = class { + constructor(expressID, type, VisibleSegmentLength, InvisibleSegmentLength) { + this.expressID = expressID; + this.type = type; + this.VisibleSegmentLength = VisibleSegmentLength; + this.InvisibleSegmentLength = InvisibleSegmentLength; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let VisibleSegmentLength = tape[ptr++]; + let InvisibleSegmentLength = tape[ptr++]; + return new IfcCurveStyleFontPattern(expressID, type, VisibleSegmentLength, InvisibleSegmentLength); + } + ToTape() { + let args = []; + args.push(this.VisibleSegmentLength); + args.push(this.InvisibleSegmentLength); + return args; + } +}; +var IfcCylindricalSurface = class { + constructor(expressID, type, Position, Radius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.Radius = Radius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + return new IfcCylindricalSurface(expressID, type, Position, Radius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.Radius); + return args; + } +}; +var IfcDamper = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDamper(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDamperType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDamperType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDeepFoundation = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcDeepFoundation(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcDeepFoundationType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcDeepFoundationType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcDerivedProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.ParentProfile = ParentProfile; + this.Operator = Operator; + this.Label = Label; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let ParentProfile = tape[ptr++]; + let Operator = tape[ptr++]; + let Label = tape[ptr++]; + return new IfcDerivedProfileDef(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.ParentProfile); + args.push(this.Operator); + args.push(this.Label); + return args; + } +}; +var IfcDerivedUnit = class { + constructor(expressID, type, Elements, UnitType, UserDefinedType) { + this.expressID = expressID; + this.type = type; + this.Elements = Elements; + this.UnitType = UnitType; + this.UserDefinedType = UserDefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Elements = tape[ptr++]; + let UnitType = tape[ptr++]; + let UserDefinedType = tape[ptr++]; + return new IfcDerivedUnit(expressID, type, Elements, UnitType, UserDefinedType); + } + ToTape() { + let args = []; + args.push(this.Elements); + args.push(this.UnitType); + args.push(this.UserDefinedType); + return args; + } +}; +var IfcDerivedUnitElement = class { + constructor(expressID, type, Unit, Exponent) { + this.expressID = expressID; + this.type = type; + this.Unit = Unit; + this.Exponent = Exponent; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Unit = tape[ptr++]; + let Exponent = tape[ptr++]; + return new IfcDerivedUnitElement(expressID, type, Unit, Exponent); + } + ToTape() { + let args = []; + args.push(this.Unit); + args.push(this.Exponent); + return args; + } +}; +var IfcDimensionalExponents = class { + constructor(expressID, type, LengthExponent, MassExponent, TimeExponent, ElectricCurrentExponent, ThermodynamicTemperatureExponent, AmountOfSubstanceExponent, LuminousIntensityExponent) { + this.expressID = expressID; + this.type = type; + this.LengthExponent = LengthExponent; + this.MassExponent = MassExponent; + this.TimeExponent = TimeExponent; + this.ElectricCurrentExponent = ElectricCurrentExponent; + this.ThermodynamicTemperatureExponent = ThermodynamicTemperatureExponent; + this.AmountOfSubstanceExponent = AmountOfSubstanceExponent; + this.LuminousIntensityExponent = LuminousIntensityExponent; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let LengthExponent = tape[ptr++]; + let MassExponent = tape[ptr++]; + let TimeExponent = tape[ptr++]; + let ElectricCurrentExponent = tape[ptr++]; + let ThermodynamicTemperatureExponent = tape[ptr++]; + let AmountOfSubstanceExponent = tape[ptr++]; + let LuminousIntensityExponent = tape[ptr++]; + return new IfcDimensionalExponents(expressID, type, LengthExponent, MassExponent, TimeExponent, ElectricCurrentExponent, ThermodynamicTemperatureExponent, AmountOfSubstanceExponent, LuminousIntensityExponent); + } + ToTape() { + let args = []; + args.push(this.LengthExponent); + args.push(this.MassExponent); + args.push(this.TimeExponent); + args.push(this.ElectricCurrentExponent); + args.push(this.ThermodynamicTemperatureExponent); + args.push(this.AmountOfSubstanceExponent); + args.push(this.LuminousIntensityExponent); + return args; + } +}; +var IfcDirection = class { + constructor(expressID, type, DirectionRatios) { + this.expressID = expressID; + this.type = type; + this.DirectionRatios = DirectionRatios; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let DirectionRatios = tape[ptr++]; + return new IfcDirection(expressID, type, DirectionRatios); + } + ToTape() { + let args = []; + args.push(this.DirectionRatios); + return args; + } +}; +var IfcDiscreteAccessory = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDiscreteAccessory(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDiscreteAccessoryType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDiscreteAccessoryType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDistanceExpression = class { + constructor(expressID, type, DistanceAlong, OffsetLateral, OffsetVertical, OffsetLongitudinal, AlongHorizontal) { + this.expressID = expressID; + this.type = type; + this.DistanceAlong = DistanceAlong; + this.OffsetLateral = OffsetLateral; + this.OffsetVertical = OffsetVertical; + this.OffsetLongitudinal = OffsetLongitudinal; + this.AlongHorizontal = AlongHorizontal; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let DistanceAlong = tape[ptr++]; + let OffsetLateral = tape[ptr++]; + let OffsetVertical = tape[ptr++]; + let OffsetLongitudinal = tape[ptr++]; + let AlongHorizontal = tape[ptr++]; + return new IfcDistanceExpression(expressID, type, DistanceAlong, OffsetLateral, OffsetVertical, OffsetLongitudinal, AlongHorizontal); + } + ToTape() { + let args = []; + args.push(this.DistanceAlong); + args.push(this.OffsetLateral); + args.push(this.OffsetVertical); + args.push(this.OffsetLongitudinal); + args.push(this.AlongHorizontal); + return args; + } +}; +var IfcDistributionChamberElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDistributionChamberElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDistributionChamberElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDistributionChamberElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDistributionCircuit = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.LongName = LongName; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let LongName = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDistributionCircuit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.LongName); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDistributionControlElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcDistributionControlElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcDistributionControlElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcDistributionControlElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcDistributionElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcDistributionElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcDistributionElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcDistributionElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcDistributionFlowElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcDistributionFlowElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcDistributionFlowElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcDistributionFlowElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcDistributionPort = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, FlowDirection, PredefinedType, SystemType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.FlowDirection = FlowDirection; + this.PredefinedType = PredefinedType; + this.SystemType = SystemType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let FlowDirection = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let SystemType = tape[ptr++]; + return new IfcDistributionPort(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, FlowDirection, PredefinedType, SystemType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.FlowDirection); + args.push(this.PredefinedType); + args.push(this.SystemType); + return args; + } +}; +var IfcDistributionSystem = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.LongName = LongName; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let LongName = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDistributionSystem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.LongName); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDocumentInformation = class { + constructor(expressID, type, Identification, Name, Description, Location, Purpose, IntendedUse, Scope, Revision, DocumentOwner, Editors, CreationTime, LastRevisionTime, ElectronicFormat, ValidFrom, ValidUntil, Confidentiality, Status) { + this.expressID = expressID; + this.type = type; + this.Identification = Identification; + this.Name = Name; + this.Description = Description; + this.Location = Location; + this.Purpose = Purpose; + this.IntendedUse = IntendedUse; + this.Scope = Scope; + this.Revision = Revision; + this.DocumentOwner = DocumentOwner; + this.Editors = Editors; + this.CreationTime = CreationTime; + this.LastRevisionTime = LastRevisionTime; + this.ElectronicFormat = ElectronicFormat; + this.ValidFrom = ValidFrom; + this.ValidUntil = ValidUntil; + this.Confidentiality = Confidentiality; + this.Status = Status; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Location = tape[ptr++]; + let Purpose = tape[ptr++]; + let IntendedUse = tape[ptr++]; + let Scope = tape[ptr++]; + let Revision = tape[ptr++]; + let DocumentOwner = tape[ptr++]; + let Editors = tape[ptr++]; + let CreationTime = tape[ptr++]; + let LastRevisionTime = tape[ptr++]; + let ElectronicFormat = tape[ptr++]; + let ValidFrom = tape[ptr++]; + let ValidUntil = tape[ptr++]; + let Confidentiality = tape[ptr++]; + let Status = tape[ptr++]; + return new IfcDocumentInformation(expressID, type, Identification, Name, Description, Location, Purpose, IntendedUse, Scope, Revision, DocumentOwner, Editors, CreationTime, LastRevisionTime, ElectronicFormat, ValidFrom, ValidUntil, Confidentiality, Status); + } + ToTape() { + let args = []; + args.push(this.Identification); + args.push(this.Name); + args.push(this.Description); + args.push(this.Location); + args.push(this.Purpose); + args.push(this.IntendedUse); + args.push(this.Scope); + args.push(this.Revision); + args.push(this.DocumentOwner); + args.push(this.Editors); + args.push(this.CreationTime); + args.push(this.LastRevisionTime); + args.push(this.ElectronicFormat); + args.push(this.ValidFrom); + args.push(this.ValidUntil); + args.push(this.Confidentiality); + args.push(this.Status); + return args; + } +}; +var IfcDocumentInformationRelationship = class { + constructor(expressID, type, Name, Description, RelatingDocument, RelatedDocuments, RelationshipType) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingDocument = RelatingDocument; + this.RelatedDocuments = RelatedDocuments; + this.RelationshipType = RelationshipType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingDocument = tape[ptr++]; + let RelatedDocuments = tape[ptr++]; + let RelationshipType = tape[ptr++]; + return new IfcDocumentInformationRelationship(expressID, type, Name, Description, RelatingDocument, RelatedDocuments, RelationshipType); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingDocument); + args.push(this.RelatedDocuments); + args.push(this.RelationshipType); + return args; + } +}; +var IfcDocumentReference = class { + constructor(expressID, type, Location, Identification, Name, Description, ReferencedDocument) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + this.Description = Description; + this.ReferencedDocument = ReferencedDocument; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ReferencedDocument = tape[ptr++]; + return new IfcDocumentReference(expressID, type, Location, Identification, Name, Description, ReferencedDocument); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + args.push(this.Description); + args.push(this.ReferencedDocument); + return args; + } +}; +var IfcDoor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.OverallHeight = OverallHeight; + this.OverallWidth = OverallWidth; + this.PredefinedType = PredefinedType; + this.OperationType = OperationType; + this.UserDefinedOperationType = UserDefinedOperationType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let OverallHeight = tape[ptr++]; + let OverallWidth = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let OperationType = tape[ptr++]; + let UserDefinedOperationType = tape[ptr++]; + return new IfcDoor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.OverallHeight); + args.push(this.OverallWidth); + args.push(this.PredefinedType); + args.push(this.OperationType); + args.push(this.UserDefinedOperationType); + return args; + } +}; +var IfcDoorLiningProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, ThresholdDepth, ThresholdThickness, TransomThickness, TransomOffset, LiningOffset, ThresholdOffset, CasingThickness, CasingDepth, ShapeAspectStyle, LiningToPanelOffsetX, LiningToPanelOffsetY) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.LiningDepth = LiningDepth; + this.LiningThickness = LiningThickness; + this.ThresholdDepth = ThresholdDepth; + this.ThresholdThickness = ThresholdThickness; + this.TransomThickness = TransomThickness; + this.TransomOffset = TransomOffset; + this.LiningOffset = LiningOffset; + this.ThresholdOffset = ThresholdOffset; + this.CasingThickness = CasingThickness; + this.CasingDepth = CasingDepth; + this.ShapeAspectStyle = ShapeAspectStyle; + this.LiningToPanelOffsetX = LiningToPanelOffsetX; + this.LiningToPanelOffsetY = LiningToPanelOffsetY; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let LiningDepth = tape[ptr++]; + let LiningThickness = tape[ptr++]; + let ThresholdDepth = tape[ptr++]; + let ThresholdThickness = tape[ptr++]; + let TransomThickness = tape[ptr++]; + let TransomOffset = tape[ptr++]; + let LiningOffset = tape[ptr++]; + let ThresholdOffset = tape[ptr++]; + let CasingThickness = tape[ptr++]; + let CasingDepth = tape[ptr++]; + let ShapeAspectStyle = tape[ptr++]; + let LiningToPanelOffsetX = tape[ptr++]; + let LiningToPanelOffsetY = tape[ptr++]; + return new IfcDoorLiningProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, ThresholdDepth, ThresholdThickness, TransomThickness, TransomOffset, LiningOffset, ThresholdOffset, CasingThickness, CasingDepth, ShapeAspectStyle, LiningToPanelOffsetX, LiningToPanelOffsetY); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.LiningDepth); + args.push(this.LiningThickness); + args.push(this.ThresholdDepth); + args.push(this.ThresholdThickness); + args.push(this.TransomThickness); + args.push(this.TransomOffset); + args.push(this.LiningOffset); + args.push(this.ThresholdOffset); + args.push(this.CasingThickness); + args.push(this.CasingDepth); + args.push(this.ShapeAspectStyle); + args.push(this.LiningToPanelOffsetX); + args.push(this.LiningToPanelOffsetY); + return args; + } +}; +var IfcDoorPanelProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, PanelDepth, PanelOperation, PanelWidth, PanelPosition, ShapeAspectStyle) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.PanelDepth = PanelDepth; + this.PanelOperation = PanelOperation; + this.PanelWidth = PanelWidth; + this.PanelPosition = PanelPosition; + this.ShapeAspectStyle = ShapeAspectStyle; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let PanelDepth = tape[ptr++]; + let PanelOperation = tape[ptr++]; + let PanelWidth = tape[ptr++]; + let PanelPosition = tape[ptr++]; + let ShapeAspectStyle = tape[ptr++]; + return new IfcDoorPanelProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, PanelDepth, PanelOperation, PanelWidth, PanelPosition, ShapeAspectStyle); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.PanelDepth); + args.push(this.PanelOperation); + args.push(this.PanelWidth); + args.push(this.PanelPosition); + args.push(this.ShapeAspectStyle); + return args; + } +}; +var IfcDoorStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.OverallHeight = OverallHeight; + this.OverallWidth = OverallWidth; + this.PredefinedType = PredefinedType; + this.OperationType = OperationType; + this.UserDefinedOperationType = UserDefinedOperationType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let OverallHeight = tape[ptr++]; + let OverallWidth = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let OperationType = tape[ptr++]; + let UserDefinedOperationType = tape[ptr++]; + return new IfcDoorStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, OperationType, UserDefinedOperationType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.OverallHeight); + args.push(this.OverallWidth); + args.push(this.PredefinedType); + args.push(this.OperationType); + args.push(this.UserDefinedOperationType); + return args; + } +}; +var IfcDoorStyle = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, OperationType, ConstructionType, ParameterTakesPrecedence, Sizeable) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.OperationType = OperationType; + this.ConstructionType = ConstructionType; + this.ParameterTakesPrecedence = ParameterTakesPrecedence; + this.Sizeable = Sizeable; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let OperationType = tape[ptr++]; + let ConstructionType = tape[ptr++]; + let ParameterTakesPrecedence = tape[ptr++]; + let Sizeable = tape[ptr++]; + return new IfcDoorStyle(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, OperationType, ConstructionType, ParameterTakesPrecedence, Sizeable); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.OperationType); + args.push(this.ConstructionType); + args.push(this.ParameterTakesPrecedence); + args.push(this.Sizeable); + return args; + } +}; +var IfcDoorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, OperationType, ParameterTakesPrecedence, UserDefinedOperationType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.OperationType = OperationType; + this.ParameterTakesPrecedence = ParameterTakesPrecedence; + this.UserDefinedOperationType = UserDefinedOperationType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let OperationType = tape[ptr++]; + let ParameterTakesPrecedence = tape[ptr++]; + let UserDefinedOperationType = tape[ptr++]; + return new IfcDoorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, OperationType, ParameterTakesPrecedence, UserDefinedOperationType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.OperationType); + args.push(this.ParameterTakesPrecedence); + args.push(this.UserDefinedOperationType); + return args; + } +}; +var IfcDraughtingPreDefinedColour = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcDraughtingPreDefinedColour(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcDraughtingPreDefinedCurveFont = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcDraughtingPreDefinedCurveFont(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcDuctFitting = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDuctFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDuctFittingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDuctFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDuctSegment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDuctSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDuctSegmentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDuctSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDuctSilencer = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDuctSilencer(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcDuctSilencerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcDuctSilencerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEdge = class { + constructor(expressID, type, EdgeStart, EdgeEnd) { + this.expressID = expressID; + this.type = type; + this.EdgeStart = EdgeStart; + this.EdgeEnd = EdgeEnd; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let EdgeStart = tape[ptr++]; + let EdgeEnd = tape[ptr++]; + return new IfcEdge(expressID, type, EdgeStart, EdgeEnd); + } + ToTape() { + let args = []; + args.push(this.EdgeStart); + args.push(this.EdgeEnd); + return args; + } +}; +var IfcEdgeCurve = class { + constructor(expressID, type, EdgeStart, EdgeEnd, EdgeGeometry, SameSense) { + this.expressID = expressID; + this.type = type; + this.EdgeStart = EdgeStart; + this.EdgeEnd = EdgeEnd; + this.EdgeGeometry = EdgeGeometry; + this.SameSense = SameSense; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let EdgeStart = tape[ptr++]; + let EdgeEnd = tape[ptr++]; + let EdgeGeometry = tape[ptr++]; + let SameSense = tape[ptr++]; + return new IfcEdgeCurve(expressID, type, EdgeStart, EdgeEnd, EdgeGeometry, SameSense); + } + ToTape() { + let args = []; + args.push(this.EdgeStart); + args.push(this.EdgeEnd); + args.push(this.EdgeGeometry); + args.push(this.SameSense); + return args; + } +}; +var IfcEdgeLoop = class { + constructor(expressID, type, EdgeList) { + this.expressID = expressID; + this.type = type; + this.EdgeList = EdgeList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let EdgeList = tape[ptr++]; + return new IfcEdgeLoop(expressID, type, EdgeList); + } + ToTape() { + let args = []; + args.push(this.EdgeList); + return args; + } +}; +var IfcElectricAppliance = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricAppliance(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricApplianceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricApplianceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricDistributionBoard = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricDistributionBoard(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricDistributionBoardType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricDistributionBoardType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricFlowStorageDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricFlowStorageDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricFlowStorageDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricFlowStorageDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricGenerator = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricGenerator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricGeneratorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricGeneratorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricMotor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricMotor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricMotorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricMotorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricTimeControl = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricTimeControl(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElectricTimeControlType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElectricTimeControlType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcElementAssembly = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, AssemblyPlace, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.AssemblyPlace = AssemblyPlace; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let AssemblyPlace = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElementAssembly(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, AssemblyPlace, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.AssemblyPlace); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElementAssemblyType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcElementAssemblyType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcElementComponent = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcElementComponent(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcElementComponentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcElementComponentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcElementQuantity = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, MethodOfMeasurement, Quantities) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.MethodOfMeasurement = MethodOfMeasurement; + this.Quantities = Quantities; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let MethodOfMeasurement = tape[ptr++]; + let Quantities = tape[ptr++]; + return new IfcElementQuantity(expressID, type, GlobalId, OwnerHistory, Name, Description, MethodOfMeasurement, Quantities); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.MethodOfMeasurement); + args.push(this.Quantities); + return args; + } +}; +var IfcElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcElementarySurface = class { + constructor(expressID, type, Position) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + return new IfcElementarySurface(expressID, type, Position); + } + ToTape() { + let args = []; + args.push(this.Position); + return args; + } +}; +var IfcEllipse = class { + constructor(expressID, type, Position, SemiAxis1, SemiAxis2) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.SemiAxis1 = SemiAxis1; + this.SemiAxis2 = SemiAxis2; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let SemiAxis1 = tape[ptr++]; + let SemiAxis2 = tape[ptr++]; + return new IfcEllipse(expressID, type, Position, SemiAxis1, SemiAxis2); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.SemiAxis1); + args.push(this.SemiAxis2); + return args; + } +}; +var IfcEllipseProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, SemiAxis1, SemiAxis2) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.SemiAxis1 = SemiAxis1; + this.SemiAxis2 = SemiAxis2; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let SemiAxis1 = tape[ptr++]; + let SemiAxis2 = tape[ptr++]; + return new IfcEllipseProfileDef(expressID, type, ProfileType, ProfileName, Position, SemiAxis1, SemiAxis2); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.SemiAxis1); + args.push(this.SemiAxis2); + return args; + } +}; +var IfcEnergyConversionDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcEnergyConversionDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcEnergyConversionDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcEnergyConversionDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcEngine = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcEngine(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEngineType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcEngineType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEvaporativeCooler = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcEvaporativeCooler(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEvaporativeCoolerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcEvaporativeCoolerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEvaporator = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcEvaporator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEvaporatorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcEvaporatorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcEvent = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType, EventTriggerType, UserDefinedEventTriggerType, EventOccurenceTime) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.PredefinedType = PredefinedType; + this.EventTriggerType = EventTriggerType; + this.UserDefinedEventTriggerType = UserDefinedEventTriggerType; + this.EventOccurenceTime = EventOccurenceTime; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let EventTriggerType = tape[ptr++]; + let UserDefinedEventTriggerType = tape[ptr++]; + let EventOccurenceTime = tape[ptr++]; + return new IfcEvent(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType, EventTriggerType, UserDefinedEventTriggerType, EventOccurenceTime); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.PredefinedType); + args.push(this.EventTriggerType); + args.push(this.UserDefinedEventTriggerType); + args.push(this.EventOccurenceTime); + return args; + } +}; +var IfcEventTime = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ActualDate, EarlyDate, LateDate, ScheduleDate) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.ActualDate = ActualDate; + this.EarlyDate = EarlyDate; + this.LateDate = LateDate; + this.ScheduleDate = ScheduleDate; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let ActualDate = tape[ptr++]; + let EarlyDate = tape[ptr++]; + let LateDate = tape[ptr++]; + let ScheduleDate = tape[ptr++]; + return new IfcEventTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ActualDate, EarlyDate, LateDate, ScheduleDate); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.ActualDate); + args.push(this.EarlyDate); + args.push(this.LateDate); + args.push(this.ScheduleDate); + return args; + } +}; +var IfcEventType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, EventTriggerType, UserDefinedEventTriggerType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ProcessType = ProcessType; + this.PredefinedType = PredefinedType; + this.EventTriggerType = EventTriggerType; + this.UserDefinedEventTriggerType = UserDefinedEventTriggerType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ProcessType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let EventTriggerType = tape[ptr++]; + let UserDefinedEventTriggerType = tape[ptr++]; + return new IfcEventType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, EventTriggerType, UserDefinedEventTriggerType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ProcessType); + args.push(this.PredefinedType); + args.push(this.EventTriggerType); + args.push(this.UserDefinedEventTriggerType); + return args; + } +}; +var IfcExtendedProperties = class { + constructor(expressID, type, Name, Description, Properties2) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Properties = Properties2; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Properties2 = tape[ptr++]; + return new IfcExtendedProperties(expressID, type, Name, Description, Properties2); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Properties); + return args; + } +}; +var IfcExternalInformation = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcExternalInformation(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcExternalReference = class { + constructor(expressID, type, Location, Identification, Name) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcExternalReference(expressID, type, Location, Identification, Name); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + return args; + } +}; +var IfcExternalReferenceRelationship = class { + constructor(expressID, type, Name, Description, RelatingReference, RelatedResourceObjects) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingReference = RelatingReference; + this.RelatedResourceObjects = RelatedResourceObjects; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingReference = tape[ptr++]; + let RelatedResourceObjects = tape[ptr++]; + return new IfcExternalReferenceRelationship(expressID, type, Name, Description, RelatingReference, RelatedResourceObjects); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingReference); + args.push(this.RelatedResourceObjects); + return args; + } +}; +var IfcExternalSpatialElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcExternalSpatialElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.PredefinedType); + return args; + } +}; +var IfcExternalSpatialStructureElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + return new IfcExternalSpatialStructureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + return args; + } +}; +var IfcExternallyDefinedHatchStyle = class { + constructor(expressID, type, Location, Identification, Name) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcExternallyDefinedHatchStyle(expressID, type, Location, Identification, Name); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + return args; + } +}; +var IfcExternallyDefinedSurfaceStyle = class { + constructor(expressID, type, Location, Identification, Name) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcExternallyDefinedSurfaceStyle(expressID, type, Location, Identification, Name); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + return args; + } +}; +var IfcExternallyDefinedTextFont = class { + constructor(expressID, type, Location, Identification, Name) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcExternallyDefinedTextFont(expressID, type, Location, Identification, Name); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + return args; + } +}; +var IfcExtrudedAreaSolid = class { + constructor(expressID, type, SweptArea, Position, ExtrudedDirection, Depth) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + this.ExtrudedDirection = ExtrudedDirection; + this.Depth = Depth; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + let ExtrudedDirection = tape[ptr++]; + let Depth = tape[ptr++]; + return new IfcExtrudedAreaSolid(expressID, type, SweptArea, Position, ExtrudedDirection, Depth); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + args.push(this.ExtrudedDirection); + args.push(this.Depth); + return args; + } +}; +var IfcExtrudedAreaSolidTapered = class { + constructor(expressID, type, SweptArea, Position, ExtrudedDirection, Depth, EndSweptArea) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + this.ExtrudedDirection = ExtrudedDirection; + this.Depth = Depth; + this.EndSweptArea = EndSweptArea; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + let ExtrudedDirection = tape[ptr++]; + let Depth = tape[ptr++]; + let EndSweptArea = tape[ptr++]; + return new IfcExtrudedAreaSolidTapered(expressID, type, SweptArea, Position, ExtrudedDirection, Depth, EndSweptArea); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + args.push(this.ExtrudedDirection); + args.push(this.Depth); + args.push(this.EndSweptArea); + return args; + } +}; +var IfcFace = class { + constructor(expressID, type, Bounds) { + this.expressID = expressID; + this.type = type; + this.Bounds = Bounds; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Bounds = tape[ptr++]; + return new IfcFace(expressID, type, Bounds); + } + ToTape() { + let args = []; + args.push(this.Bounds); + return args; + } +}; +var IfcFaceBasedSurfaceModel = class { + constructor(expressID, type, FbsmFaces) { + this.expressID = expressID; + this.type = type; + this.FbsmFaces = FbsmFaces; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let FbsmFaces = tape[ptr++]; + return new IfcFaceBasedSurfaceModel(expressID, type, FbsmFaces); + } + ToTape() { + let args = []; + args.push(this.FbsmFaces); + return args; + } +}; +var IfcFaceBound = class { + constructor(expressID, type, Bound, Orientation) { + this.expressID = expressID; + this.type = type; + this.Bound = Bound; + this.Orientation = Orientation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Bound = tape[ptr++]; + let Orientation = tape[ptr++]; + return new IfcFaceBound(expressID, type, Bound, Orientation); + } + ToTape() { + let args = []; + args.push(this.Bound); + args.push(this.Orientation); + return args; + } +}; +var IfcFaceOuterBound = class { + constructor(expressID, type, Bound, Orientation) { + this.expressID = expressID; + this.type = type; + this.Bound = Bound; + this.Orientation = Orientation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Bound = tape[ptr++]; + let Orientation = tape[ptr++]; + return new IfcFaceOuterBound(expressID, type, Bound, Orientation); + } + ToTape() { + let args = []; + args.push(this.Bound); + args.push(this.Orientation); + return args; + } +}; +var IfcFaceSurface = class { + constructor(expressID, type, Bounds, FaceSurface, SameSense) { + this.expressID = expressID; + this.type = type; + this.Bounds = Bounds; + this.FaceSurface = FaceSurface; + this.SameSense = SameSense; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Bounds = tape[ptr++]; + let FaceSurface = tape[ptr++]; + let SameSense = tape[ptr++]; + return new IfcFaceSurface(expressID, type, Bounds, FaceSurface, SameSense); + } + ToTape() { + let args = []; + args.push(this.Bounds); + args.push(this.FaceSurface); + args.push(this.SameSense); + return args; + } +}; +var IfcFacetedBrep = class { + constructor(expressID, type, Outer) { + this.expressID = expressID; + this.type = type; + this.Outer = Outer; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Outer = tape[ptr++]; + return new IfcFacetedBrep(expressID, type, Outer); + } + ToTape() { + let args = []; + args.push(this.Outer); + return args; + } +}; +var IfcFacetedBrepWithVoids = class { + constructor(expressID, type, Outer, Voids) { + this.expressID = expressID; + this.type = type; + this.Outer = Outer; + this.Voids = Voids; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Outer = tape[ptr++]; + let Voids = tape[ptr++]; + return new IfcFacetedBrepWithVoids(expressID, type, Outer, Voids); + } + ToTape() { + let args = []; + args.push(this.Outer); + args.push(this.Voids); + return args; + } +}; +var IfcFacility = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + return new IfcFacility(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + return args; + } +}; +var IfcFacilityPart = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + return new IfcFacilityPart(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + return args; + } +}; +var IfcFailureConnectionCondition = class { + constructor(expressID, type, Name, TensionFailureX, TensionFailureY, TensionFailureZ, CompressionFailureX, CompressionFailureY, CompressionFailureZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.TensionFailureX = TensionFailureX; + this.TensionFailureY = TensionFailureY; + this.TensionFailureZ = TensionFailureZ; + this.CompressionFailureX = CompressionFailureX; + this.CompressionFailureY = CompressionFailureY; + this.CompressionFailureZ = CompressionFailureZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let TensionFailureX = tape[ptr++]; + let TensionFailureY = tape[ptr++]; + let TensionFailureZ = tape[ptr++]; + let CompressionFailureX = tape[ptr++]; + let CompressionFailureY = tape[ptr++]; + let CompressionFailureZ = tape[ptr++]; + return new IfcFailureConnectionCondition(expressID, type, Name, TensionFailureX, TensionFailureY, TensionFailureZ, CompressionFailureX, CompressionFailureY, CompressionFailureZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.TensionFailureX); + args.push(this.TensionFailureY); + args.push(this.TensionFailureZ); + args.push(this.CompressionFailureX); + args.push(this.CompressionFailureY); + args.push(this.CompressionFailureZ); + return args; + } +}; +var IfcFan = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFan(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFanType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFanType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFastener = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFastener(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFastenerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFastenerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFeatureElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFeatureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFeatureElementAddition = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFeatureElementAddition(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFeatureElementSubtraction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFeatureElementSubtraction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFillAreaStyle = class { + constructor(expressID, type, Name, FillStyles, ModelorDraughting) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.FillStyles = FillStyles; + this.ModelorDraughting = ModelorDraughting; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let FillStyles = tape[ptr++]; + let ModelorDraughting = tape[ptr++]; + return new IfcFillAreaStyle(expressID, type, Name, FillStyles, ModelorDraughting); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.FillStyles); + args.push(this.ModelorDraughting); + return args; + } +}; +var IfcFillAreaStyleHatching = class { + constructor(expressID, type, HatchLineAppearance, StartOfNextHatchLine, PointOfReferenceHatchLine, PatternStart, HatchLineAngle) { + this.expressID = expressID; + this.type = type; + this.HatchLineAppearance = HatchLineAppearance; + this.StartOfNextHatchLine = StartOfNextHatchLine; + this.PointOfReferenceHatchLine = PointOfReferenceHatchLine; + this.PatternStart = PatternStart; + this.HatchLineAngle = HatchLineAngle; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let HatchLineAppearance = tape[ptr++]; + let StartOfNextHatchLine = tape[ptr++]; + let PointOfReferenceHatchLine = tape[ptr++]; + let PatternStart = tape[ptr++]; + let HatchLineAngle = tape[ptr++]; + return new IfcFillAreaStyleHatching(expressID, type, HatchLineAppearance, StartOfNextHatchLine, PointOfReferenceHatchLine, PatternStart, HatchLineAngle); + } + ToTape() { + let args = []; + args.push(this.HatchLineAppearance); + args.push(this.StartOfNextHatchLine); + args.push(this.PointOfReferenceHatchLine); + args.push(this.PatternStart); + args.push(this.HatchLineAngle); + return args; + } +}; +var IfcFillAreaStyleTiles = class { + constructor(expressID, type, TilingPattern, Tiles, TilingScale) { + this.expressID = expressID; + this.type = type; + this.TilingPattern = TilingPattern; + this.Tiles = Tiles; + this.TilingScale = TilingScale; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TilingPattern = tape[ptr++]; + let Tiles = tape[ptr++]; + let TilingScale = tape[ptr++]; + return new IfcFillAreaStyleTiles(expressID, type, TilingPattern, Tiles, TilingScale); + } + ToTape() { + let args = []; + args.push(this.TilingPattern); + args.push(this.Tiles); + args.push(this.TilingScale); + return args; + } +}; +var IfcFilter = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFilter(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFilterType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFilterType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFireSuppressionTerminal = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFireSuppressionTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFireSuppressionTerminalType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFireSuppressionTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFixedReferenceSweptAreaSolid = class { + constructor(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, FixedReference) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + this.Directrix = Directrix; + this.StartParam = StartParam; + this.EndParam = EndParam; + this.FixedReference = FixedReference; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + let Directrix = tape[ptr++]; + let StartParam = tape[ptr++]; + let EndParam = tape[ptr++]; + let FixedReference = tape[ptr++]; + return new IfcFixedReferenceSweptAreaSolid(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, FixedReference); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + args.push(this.Directrix); + args.push(this.StartParam); + args.push(this.EndParam); + args.push(this.FixedReference); + return args; + } +}; +var IfcFlowController = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowController(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowControllerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowControllerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFlowFitting = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowFittingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFlowInstrument = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFlowInstrument(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFlowInstrumentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFlowInstrumentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFlowMeter = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFlowMeter(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFlowMeterType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFlowMeterType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFlowMovingDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowMovingDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowMovingDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowMovingDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFlowSegment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowSegmentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFlowStorageDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowStorageDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowStorageDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowStorageDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFlowTerminal = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowTerminalType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFlowTreatmentDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFlowTreatmentDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFlowTreatmentDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFlowTreatmentDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFooting = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFooting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFootingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFootingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFurnishingElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcFurnishingElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcFurnishingElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcFurnishingElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcFurniture = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFurniture(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcFurnitureType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, AssemblyPlace, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.AssemblyPlace = AssemblyPlace; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let AssemblyPlace = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcFurnitureType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, AssemblyPlace, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.AssemblyPlace); + args.push(this.PredefinedType); + return args; + } +}; +var IfcGeographicElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcGeographicElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcGeographicElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcGeographicElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcGeometricCurveSet = class { + constructor(expressID, type, Elements) { + this.expressID = expressID; + this.type = type; + this.Elements = Elements; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Elements = tape[ptr++]; + return new IfcGeometricCurveSet(expressID, type, Elements); + } + ToTape() { + let args = []; + args.push(this.Elements); + return args; + } +}; +var IfcGeometricRepresentationContext = class { + constructor(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth) { + this.expressID = expressID; + this.type = type; + this.ContextIdentifier = ContextIdentifier; + this.ContextType = ContextType; + this.CoordinateSpaceDimension = CoordinateSpaceDimension; + this.Precision = Precision; + this.WorldCoordinateSystem = WorldCoordinateSystem; + this.TrueNorth = TrueNorth; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextIdentifier = tape[ptr++]; + let ContextType = tape[ptr++]; + let CoordinateSpaceDimension = tape[ptr++]; + let Precision = tape[ptr++]; + let WorldCoordinateSystem = tape[ptr++]; + let TrueNorth = tape[ptr++]; + return new IfcGeometricRepresentationContext(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth); + } + ToTape() { + let args = []; + args.push(this.ContextIdentifier); + args.push(this.ContextType); + args.push(this.CoordinateSpaceDimension); + args.push(this.Precision); + args.push(this.WorldCoordinateSystem); + args.push(this.TrueNorth); + return args; + } +}; +var IfcGeometricRepresentationItem = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcGeometricRepresentationItem(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcGeometricRepresentationSubContext = class { + constructor(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth, ParentContext, TargetScale, TargetView, UserDefinedTargetView) { + this.expressID = expressID; + this.type = type; + this.ContextIdentifier = ContextIdentifier; + this.ContextType = ContextType; + this.CoordinateSpaceDimension = CoordinateSpaceDimension; + this.Precision = Precision; + this.WorldCoordinateSystem = WorldCoordinateSystem; + this.TrueNorth = TrueNorth; + this.ParentContext = ParentContext; + this.TargetScale = TargetScale; + this.TargetView = TargetView; + this.UserDefinedTargetView = UserDefinedTargetView; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextIdentifier = tape[ptr++]; + let ContextType = tape[ptr++]; + let CoordinateSpaceDimension = tape[ptr++]; + let Precision = tape[ptr++]; + let WorldCoordinateSystem = tape[ptr++]; + let TrueNorth = tape[ptr++]; + let ParentContext = tape[ptr++]; + let TargetScale = tape[ptr++]; + let TargetView = tape[ptr++]; + let UserDefinedTargetView = tape[ptr++]; + return new IfcGeometricRepresentationSubContext(expressID, type, ContextIdentifier, ContextType, CoordinateSpaceDimension, Precision, WorldCoordinateSystem, TrueNorth, ParentContext, TargetScale, TargetView, UserDefinedTargetView); + } + ToTape() { + let args = []; + args.push(this.ContextIdentifier); + args.push(this.ContextType); + args.push(this.CoordinateSpaceDimension); + args.push(this.Precision); + args.push(this.WorldCoordinateSystem); + args.push(this.TrueNorth); + args.push(this.ParentContext); + args.push(this.TargetScale); + args.push(this.TargetView); + args.push(this.UserDefinedTargetView); + return args; + } +}; +var IfcGeometricSet = class { + constructor(expressID, type, Elements) { + this.expressID = expressID; + this.type = type; + this.Elements = Elements; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Elements = tape[ptr++]; + return new IfcGeometricSet(expressID, type, Elements); + } + ToTape() { + let args = []; + args.push(this.Elements); + return args; + } +}; +var IfcGrid = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, UAxes, VAxes, WAxes, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.UAxes = UAxes; + this.VAxes = VAxes; + this.WAxes = WAxes; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let UAxes = tape[ptr++]; + let VAxes = tape[ptr++]; + let WAxes = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcGrid(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, UAxes, VAxes, WAxes, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.UAxes); + args.push(this.VAxes); + args.push(this.WAxes); + args.push(this.PredefinedType); + return args; + } +}; +var IfcGridAxis = class { + constructor(expressID, type, AxisTag, AxisCurve, SameSense) { + this.expressID = expressID; + this.type = type; + this.AxisTag = AxisTag; + this.AxisCurve = AxisCurve; + this.SameSense = SameSense; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let AxisTag = tape[ptr++]; + let AxisCurve = tape[ptr++]; + let SameSense = tape[ptr++]; + return new IfcGridAxis(expressID, type, AxisTag, AxisCurve, SameSense); + } + ToTape() { + let args = []; + args.push(this.AxisTag); + args.push(this.AxisCurve); + args.push(this.SameSense); + return args; + } +}; +var IfcGridPlacement = class { + constructor(expressID, type, PlacementRelTo, PlacementLocation, PlacementRefDirection) { + this.expressID = expressID; + this.type = type; + this.PlacementRelTo = PlacementRelTo; + this.PlacementLocation = PlacementLocation; + this.PlacementRefDirection = PlacementRefDirection; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let PlacementRelTo = tape[ptr++]; + let PlacementLocation = tape[ptr++]; + let PlacementRefDirection = tape[ptr++]; + return new IfcGridPlacement(expressID, type, PlacementRelTo, PlacementLocation, PlacementRefDirection); + } + ToTape() { + let args = []; + args.push(this.PlacementRelTo); + args.push(this.PlacementLocation); + args.push(this.PlacementRefDirection); + return args; + } +}; +var IfcGroup = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + return new IfcGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + return args; + } +}; +var IfcHalfSpaceSolid = class { + constructor(expressID, type, BaseSurface, AgreementFlag) { + this.expressID = expressID; + this.type = type; + this.BaseSurface = BaseSurface; + this.AgreementFlag = AgreementFlag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BaseSurface = tape[ptr++]; + let AgreementFlag = tape[ptr++]; + return new IfcHalfSpaceSolid(expressID, type, BaseSurface, AgreementFlag); + } + ToTape() { + let args = []; + args.push(this.BaseSurface); + args.push(this.AgreementFlag); + return args; + } +}; +var IfcHeatExchanger = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcHeatExchanger(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcHeatExchangerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcHeatExchangerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcHumidifier = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcHumidifier(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcHumidifierType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcHumidifierType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcIShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, OverallWidth, OverallDepth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, FlangeSlope) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.OverallWidth = OverallWidth; + this.OverallDepth = OverallDepth; + this.WebThickness = WebThickness; + this.FlangeThickness = FlangeThickness; + this.FilletRadius = FilletRadius; + this.FlangeEdgeRadius = FlangeEdgeRadius; + this.FlangeSlope = FlangeSlope; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let OverallWidth = tape[ptr++]; + let OverallDepth = tape[ptr++]; + let WebThickness = tape[ptr++]; + let FlangeThickness = tape[ptr++]; + let FilletRadius = tape[ptr++]; + let FlangeEdgeRadius = tape[ptr++]; + let FlangeSlope = tape[ptr++]; + return new IfcIShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, OverallWidth, OverallDepth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, FlangeSlope); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.OverallWidth); + args.push(this.OverallDepth); + args.push(this.WebThickness); + args.push(this.FlangeThickness); + args.push(this.FilletRadius); + args.push(this.FlangeEdgeRadius); + args.push(this.FlangeSlope); + return args; + } +}; +var IfcImageTexture = class { + constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, URLReference) { + this.expressID = expressID; + this.type = type; + this.RepeatS = RepeatS; + this.RepeatT = RepeatT; + this.Mode = Mode; + this.TextureTransform = TextureTransform; + this.Parameter = Parameter; + this.URLReference = URLReference; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RepeatS = tape[ptr++]; + let RepeatT = tape[ptr++]; + let Mode = tape[ptr++]; + let TextureTransform = tape[ptr++]; + let Parameter = tape[ptr++]; + let URLReference = tape[ptr++]; + return new IfcImageTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, URLReference); + } + ToTape() { + let args = []; + args.push(this.RepeatS); + args.push(this.RepeatT); + args.push(this.Mode); + args.push(this.TextureTransform); + args.push(this.Parameter); + args.push(this.URLReference); + return args; + } +}; +var IfcIndexedColourMap = class { + constructor(expressID, type, MappedTo, Opacity, Colours, ColourIndex) { + this.expressID = expressID; + this.type = type; + this.MappedTo = MappedTo; + this.Opacity = Opacity; + this.Colours = Colours; + this.ColourIndex = ColourIndex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let MappedTo = tape[ptr++]; + let Opacity = tape[ptr++]; + let Colours = tape[ptr++]; + let ColourIndex = tape[ptr++]; + return new IfcIndexedColourMap(expressID, type, MappedTo, Opacity, Colours, ColourIndex); + } + ToTape() { + let args = []; + args.push(this.MappedTo); + args.push(this.Opacity); + args.push(this.Colours); + args.push(this.ColourIndex); + return args; + } +}; +var IfcIndexedPolyCurve = class { + constructor(expressID, type, Points, Segments, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.Points = Points; + this.Segments = Segments; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Points = tape[ptr++]; + let Segments = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcIndexedPolyCurve(expressID, type, Points, Segments, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.Points); + args.push(this.Segments); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcIndexedPolygonalFace = class { + constructor(expressID, type, CoordIndex) { + this.expressID = expressID; + this.type = type; + this.CoordIndex = CoordIndex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CoordIndex = tape[ptr++]; + return new IfcIndexedPolygonalFace(expressID, type, CoordIndex); + } + ToTape() { + let args = []; + args.push(this.CoordIndex); + return args; + } +}; +var IfcIndexedPolygonalFaceWithVoids = class { + constructor(expressID, type, CoordIndex, InnerCoordIndices) { + this.expressID = expressID; + this.type = type; + this.CoordIndex = CoordIndex; + this.InnerCoordIndices = InnerCoordIndices; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CoordIndex = tape[ptr++]; + let InnerCoordIndices = tape[ptr++]; + return new IfcIndexedPolygonalFaceWithVoids(expressID, type, CoordIndex, InnerCoordIndices); + } + ToTape() { + let args = []; + args.push(this.CoordIndex); + args.push(this.InnerCoordIndices); + return args; + } +}; +var IfcIndexedTextureMap = class { + constructor(expressID, type, Maps, MappedTo, TexCoords) { + this.expressID = expressID; + this.type = type; + this.Maps = Maps; + this.MappedTo = MappedTo; + this.TexCoords = TexCoords; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Maps = tape[ptr++]; + let MappedTo = tape[ptr++]; + let TexCoords = tape[ptr++]; + return new IfcIndexedTextureMap(expressID, type, Maps, MappedTo, TexCoords); + } + ToTape() { + let args = []; + args.push(this.Maps); + args.push(this.MappedTo); + args.push(this.TexCoords); + return args; + } +}; +var IfcIndexedTriangleTextureMap = class { + constructor(expressID, type, Maps, MappedTo, TexCoords, TexCoordIndex) { + this.expressID = expressID; + this.type = type; + this.Maps = Maps; + this.MappedTo = MappedTo; + this.TexCoords = TexCoords; + this.TexCoordIndex = TexCoordIndex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Maps = tape[ptr++]; + let MappedTo = tape[ptr++]; + let TexCoords = tape[ptr++]; + let TexCoordIndex = tape[ptr++]; + return new IfcIndexedTriangleTextureMap(expressID, type, Maps, MappedTo, TexCoords, TexCoordIndex); + } + ToTape() { + let args = []; + args.push(this.Maps); + args.push(this.MappedTo); + args.push(this.TexCoords); + args.push(this.TexCoordIndex); + return args; + } +}; +var IfcInterceptor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcInterceptor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcInterceptorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcInterceptorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcIntersectionCurve = class { + constructor(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation) { + this.expressID = expressID; + this.type = type; + this.Curve3D = Curve3D; + this.AssociatedGeometry = AssociatedGeometry; + this.MasterRepresentation = MasterRepresentation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Curve3D = tape[ptr++]; + let AssociatedGeometry = tape[ptr++]; + let MasterRepresentation = tape[ptr++]; + return new IfcIntersectionCurve(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation); + } + ToTape() { + let args = []; + args.push(this.Curve3D); + args.push(this.AssociatedGeometry); + args.push(this.MasterRepresentation); + return args; + } +}; +var IfcInventory = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, Jurisdiction, ResponsiblePersons, LastUpdateDate, CurrentValue, OriginalValue) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.PredefinedType = PredefinedType; + this.Jurisdiction = Jurisdiction; + this.ResponsiblePersons = ResponsiblePersons; + this.LastUpdateDate = LastUpdateDate; + this.CurrentValue = CurrentValue; + this.OriginalValue = OriginalValue; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Jurisdiction = tape[ptr++]; + let ResponsiblePersons = tape[ptr++]; + let LastUpdateDate = tape[ptr++]; + let CurrentValue = tape[ptr++]; + let OriginalValue = tape[ptr++]; + return new IfcInventory(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, Jurisdiction, ResponsiblePersons, LastUpdateDate, CurrentValue, OriginalValue); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.PredefinedType); + args.push(this.Jurisdiction); + args.push(this.ResponsiblePersons); + args.push(this.LastUpdateDate); + args.push(this.CurrentValue); + args.push(this.OriginalValue); + return args; + } +}; +var IfcIrregularTimeSeries = class { + constructor(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, Values) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.StartTime = StartTime; + this.EndTime = EndTime; + this.TimeSeriesDataType = TimeSeriesDataType; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.Unit = Unit; + this.Values = Values; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let StartTime = tape[ptr++]; + let EndTime = tape[ptr++]; + let TimeSeriesDataType = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let Unit = tape[ptr++]; + let Values = tape[ptr++]; + return new IfcIrregularTimeSeries(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, Values); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.StartTime); + args.push(this.EndTime); + args.push(this.TimeSeriesDataType); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.Unit); + args.push(this.Values); + return args; + } +}; +var IfcIrregularTimeSeriesValue = class { + constructor(expressID, type, TimeStamp, ListValues) { + this.expressID = expressID; + this.type = type; + this.TimeStamp = TimeStamp; + this.ListValues = ListValues; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TimeStamp = tape[ptr++]; + let ListValues = tape[ptr++]; + return new IfcIrregularTimeSeriesValue(expressID, type, TimeStamp, ListValues); + } + ToTape() { + let args = []; + args.push(this.TimeStamp); + args.push(this.ListValues); + return args; + } +}; +var IfcJunctionBox = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcJunctionBox(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcJunctionBoxType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcJunctionBoxType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Depth, Width, Thickness, FilletRadius, EdgeRadius, LegSlope) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Depth = Depth; + this.Width = Width; + this.Thickness = Thickness; + this.FilletRadius = FilletRadius; + this.EdgeRadius = EdgeRadius; + this.LegSlope = LegSlope; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Depth = tape[ptr++]; + let Width = tape[ptr++]; + let Thickness = tape[ptr++]; + let FilletRadius = tape[ptr++]; + let EdgeRadius = tape[ptr++]; + let LegSlope = tape[ptr++]; + return new IfcLShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, Width, Thickness, FilletRadius, EdgeRadius, LegSlope); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Depth); + args.push(this.Width); + args.push(this.Thickness); + args.push(this.FilletRadius); + args.push(this.EdgeRadius); + args.push(this.LegSlope); + return args; + } +}; +var IfcLaborResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcLaborResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLaborResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcLaborResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLagTime = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, LagValue, DurationType) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.LagValue = LagValue; + this.DurationType = DurationType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let LagValue = tape[ptr++]; + let DurationType = tape[ptr++]; + return new IfcLagTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, LagValue, DurationType); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.LagValue); + args.push(this.DurationType); + return args; + } +}; +var IfcLamp = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcLamp(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLampType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcLampType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLibraryInformation = class { + constructor(expressID, type, Name, Version, Publisher, VersionDate, Location, Description) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Version = Version; + this.Publisher = Publisher; + this.VersionDate = VersionDate; + this.Location = Location; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Version = tape[ptr++]; + let Publisher = tape[ptr++]; + let VersionDate = tape[ptr++]; + let Location = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcLibraryInformation(expressID, type, Name, Version, Publisher, VersionDate, Location, Description); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Version); + args.push(this.Publisher); + args.push(this.VersionDate); + args.push(this.Location); + args.push(this.Description); + return args; + } +}; +var IfcLibraryReference = class { + constructor(expressID, type, Location, Identification, Name, Description, Language, ReferencedLibrary) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + this.Identification = Identification; + this.Name = Name; + this.Description = Description; + this.Language = Language; + this.ReferencedLibrary = ReferencedLibrary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Language = tape[ptr++]; + let ReferencedLibrary = tape[ptr++]; + return new IfcLibraryReference(expressID, type, Location, Identification, Name, Description, Language, ReferencedLibrary); + } + ToTape() { + let args = []; + args.push(this.Location); + args.push(this.Identification); + args.push(this.Name); + args.push(this.Description); + args.push(this.Language); + args.push(this.ReferencedLibrary); + return args; + } +}; +var IfcLightDistributionData = class { + constructor(expressID, type, MainPlaneAngle, SecondaryPlaneAngle, LuminousIntensity) { + this.expressID = expressID; + this.type = type; + this.MainPlaneAngle = MainPlaneAngle; + this.SecondaryPlaneAngle = SecondaryPlaneAngle; + this.LuminousIntensity = LuminousIntensity; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let MainPlaneAngle = tape[ptr++]; + let SecondaryPlaneAngle = tape[ptr++]; + let LuminousIntensity = tape[ptr++]; + return new IfcLightDistributionData(expressID, type, MainPlaneAngle, SecondaryPlaneAngle, LuminousIntensity); + } + ToTape() { + let args = []; + args.push(this.MainPlaneAngle); + args.push(this.SecondaryPlaneAngle); + args.push(this.LuminousIntensity); + return args; + } +}; +var IfcLightFixture = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcLightFixture(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLightFixtureType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcLightFixtureType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcLightIntensityDistribution = class { + constructor(expressID, type, LightDistributionCurve, DistributionData) { + this.expressID = expressID; + this.type = type; + this.LightDistributionCurve = LightDistributionCurve; + this.DistributionData = DistributionData; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let LightDistributionCurve = tape[ptr++]; + let DistributionData = tape[ptr++]; + return new IfcLightIntensityDistribution(expressID, type, LightDistributionCurve, DistributionData); + } + ToTape() { + let args = []; + args.push(this.LightDistributionCurve); + args.push(this.DistributionData); + return args; + } +}; +var IfcLightSource = class { + constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LightColour = LightColour; + this.AmbientIntensity = AmbientIntensity; + this.Intensity = Intensity; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LightColour = tape[ptr++]; + let AmbientIntensity = tape[ptr++]; + let Intensity = tape[ptr++]; + return new IfcLightSource(expressID, type, Name, LightColour, AmbientIntensity, Intensity); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LightColour); + args.push(this.AmbientIntensity); + args.push(this.Intensity); + return args; + } +}; +var IfcLightSourceAmbient = class { + constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LightColour = LightColour; + this.AmbientIntensity = AmbientIntensity; + this.Intensity = Intensity; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LightColour = tape[ptr++]; + let AmbientIntensity = tape[ptr++]; + let Intensity = tape[ptr++]; + return new IfcLightSourceAmbient(expressID, type, Name, LightColour, AmbientIntensity, Intensity); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LightColour); + args.push(this.AmbientIntensity); + args.push(this.Intensity); + return args; + } +}; +var IfcLightSourceDirectional = class { + constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Orientation) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LightColour = LightColour; + this.AmbientIntensity = AmbientIntensity; + this.Intensity = Intensity; + this.Orientation = Orientation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LightColour = tape[ptr++]; + let AmbientIntensity = tape[ptr++]; + let Intensity = tape[ptr++]; + let Orientation = tape[ptr++]; + return new IfcLightSourceDirectional(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Orientation); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LightColour); + args.push(this.AmbientIntensity); + args.push(this.Intensity); + args.push(this.Orientation); + return args; + } +}; +var IfcLightSourceGoniometric = class { + constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, ColourAppearance, ColourTemperature, LuminousFlux, LightEmissionSource, LightDistributionDataSource) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LightColour = LightColour; + this.AmbientIntensity = AmbientIntensity; + this.Intensity = Intensity; + this.Position = Position; + this.ColourAppearance = ColourAppearance; + this.ColourTemperature = ColourTemperature; + this.LuminousFlux = LuminousFlux; + this.LightEmissionSource = LightEmissionSource; + this.LightDistributionDataSource = LightDistributionDataSource; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LightColour = tape[ptr++]; + let AmbientIntensity = tape[ptr++]; + let Intensity = tape[ptr++]; + let Position = tape[ptr++]; + let ColourAppearance = tape[ptr++]; + let ColourTemperature = tape[ptr++]; + let LuminousFlux = tape[ptr++]; + let LightEmissionSource = tape[ptr++]; + let LightDistributionDataSource = tape[ptr++]; + return new IfcLightSourceGoniometric(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, ColourAppearance, ColourTemperature, LuminousFlux, LightEmissionSource, LightDistributionDataSource); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LightColour); + args.push(this.AmbientIntensity); + args.push(this.Intensity); + args.push(this.Position); + args.push(this.ColourAppearance); + args.push(this.ColourTemperature); + args.push(this.LuminousFlux); + args.push(this.LightEmissionSource); + args.push(this.LightDistributionDataSource); + return args; + } +}; +var IfcLightSourcePositional = class { + constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LightColour = LightColour; + this.AmbientIntensity = AmbientIntensity; + this.Intensity = Intensity; + this.Position = Position; + this.Radius = Radius; + this.ConstantAttenuation = ConstantAttenuation; + this.DistanceAttenuation = DistanceAttenuation; + this.QuadricAttenuation = QuadricAttenuation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LightColour = tape[ptr++]; + let AmbientIntensity = tape[ptr++]; + let Intensity = tape[ptr++]; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + let ConstantAttenuation = tape[ptr++]; + let DistanceAttenuation = tape[ptr++]; + let QuadricAttenuation = tape[ptr++]; + return new IfcLightSourcePositional(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LightColour); + args.push(this.AmbientIntensity); + args.push(this.Intensity); + args.push(this.Position); + args.push(this.Radius); + args.push(this.ConstantAttenuation); + args.push(this.DistanceAttenuation); + args.push(this.QuadricAttenuation); + return args; + } +}; +var IfcLightSourceSpot = class { + constructor(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation, Orientation, ConcentrationExponent, SpreadAngle, BeamWidthAngle) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LightColour = LightColour; + this.AmbientIntensity = AmbientIntensity; + this.Intensity = Intensity; + this.Position = Position; + this.Radius = Radius; + this.ConstantAttenuation = ConstantAttenuation; + this.DistanceAttenuation = DistanceAttenuation; + this.QuadricAttenuation = QuadricAttenuation; + this.Orientation = Orientation; + this.ConcentrationExponent = ConcentrationExponent; + this.SpreadAngle = SpreadAngle; + this.BeamWidthAngle = BeamWidthAngle; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LightColour = tape[ptr++]; + let AmbientIntensity = tape[ptr++]; + let Intensity = tape[ptr++]; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + let ConstantAttenuation = tape[ptr++]; + let DistanceAttenuation = tape[ptr++]; + let QuadricAttenuation = tape[ptr++]; + let Orientation = tape[ptr++]; + let ConcentrationExponent = tape[ptr++]; + let SpreadAngle = tape[ptr++]; + let BeamWidthAngle = tape[ptr++]; + return new IfcLightSourceSpot(expressID, type, Name, LightColour, AmbientIntensity, Intensity, Position, Radius, ConstantAttenuation, DistanceAttenuation, QuadricAttenuation, Orientation, ConcentrationExponent, SpreadAngle, BeamWidthAngle); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LightColour); + args.push(this.AmbientIntensity); + args.push(this.Intensity); + args.push(this.Position); + args.push(this.Radius); + args.push(this.ConstantAttenuation); + args.push(this.DistanceAttenuation); + args.push(this.QuadricAttenuation); + args.push(this.Orientation); + args.push(this.ConcentrationExponent); + args.push(this.SpreadAngle); + args.push(this.BeamWidthAngle); + return args; + } +}; +var IfcLine = class { + constructor(expressID, type, Pnt, Dir) { + this.expressID = expressID; + this.type = type; + this.Pnt = Pnt; + this.Dir = Dir; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Pnt = tape[ptr++]; + let Dir = tape[ptr++]; + return new IfcLine(expressID, type, Pnt, Dir); + } + ToTape() { + let args = []; + args.push(this.Pnt); + args.push(this.Dir); + return args; + } +}; +var IfcLineSegment2D = class { + constructor(expressID, type, StartPoint, StartDirection, SegmentLength) { + this.expressID = expressID; + this.type = type; + this.StartPoint = StartPoint; + this.StartDirection = StartDirection; + this.SegmentLength = SegmentLength; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let StartPoint = tape[ptr++]; + let StartDirection = tape[ptr++]; + let SegmentLength = tape[ptr++]; + return new IfcLineSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength); + } + ToTape() { + let args = []; + args.push(this.StartPoint); + args.push(this.StartDirection); + args.push(this.SegmentLength); + return args; + } +}; +var IfcLinearPlacement = class { + constructor(expressID, type, PlacementRelTo, PlacementMeasuredAlong, Distance, Orientation, CartesianPosition) { + this.expressID = expressID; + this.type = type; + this.PlacementRelTo = PlacementRelTo; + this.PlacementMeasuredAlong = PlacementMeasuredAlong; + this.Distance = Distance; + this.Orientation = Orientation; + this.CartesianPosition = CartesianPosition; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let PlacementRelTo = tape[ptr++]; + let PlacementMeasuredAlong = tape[ptr++]; + let Distance = tape[ptr++]; + let Orientation = tape[ptr++]; + let CartesianPosition = tape[ptr++]; + return new IfcLinearPlacement(expressID, type, PlacementRelTo, PlacementMeasuredAlong, Distance, Orientation, CartesianPosition); + } + ToTape() { + let args = []; + args.push(this.PlacementRelTo); + args.push(this.PlacementMeasuredAlong); + args.push(this.Distance); + args.push(this.Orientation); + args.push(this.CartesianPosition); + return args; + } +}; +var IfcLinearPositioningElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Axis = Axis; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Axis = tape[ptr++]; + return new IfcLinearPositioningElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Axis); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Axis); + return args; + } +}; +var IfcLocalPlacement = class { + constructor(expressID, type, PlacementRelTo, RelativePlacement) { + this.expressID = expressID; + this.type = type; + this.PlacementRelTo = PlacementRelTo; + this.RelativePlacement = RelativePlacement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let PlacementRelTo = tape[ptr++]; + let RelativePlacement = tape[ptr++]; + return new IfcLocalPlacement(expressID, type, PlacementRelTo, RelativePlacement); + } + ToTape() { + let args = []; + args.push(this.PlacementRelTo); + args.push(this.RelativePlacement); + return args; + } +}; +var IfcLoop = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcLoop(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcManifoldSolidBrep = class { + constructor(expressID, type, Outer) { + this.expressID = expressID; + this.type = type; + this.Outer = Outer; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Outer = tape[ptr++]; + return new IfcManifoldSolidBrep(expressID, type, Outer); + } + ToTape() { + let args = []; + args.push(this.Outer); + return args; + } +}; +var IfcMapConversion = class { + constructor(expressID, type, SourceCRS, TargetCRS, Eastings, Northings, OrthogonalHeight, XAxisAbscissa, XAxisOrdinate, Scale) { + this.expressID = expressID; + this.type = type; + this.SourceCRS = SourceCRS; + this.TargetCRS = TargetCRS; + this.Eastings = Eastings; + this.Northings = Northings; + this.OrthogonalHeight = OrthogonalHeight; + this.XAxisAbscissa = XAxisAbscissa; + this.XAxisOrdinate = XAxisOrdinate; + this.Scale = Scale; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SourceCRS = tape[ptr++]; + let TargetCRS = tape[ptr++]; + let Eastings = tape[ptr++]; + let Northings = tape[ptr++]; + let OrthogonalHeight = tape[ptr++]; + let XAxisAbscissa = tape[ptr++]; + let XAxisOrdinate = tape[ptr++]; + let Scale = tape[ptr++]; + return new IfcMapConversion(expressID, type, SourceCRS, TargetCRS, Eastings, Northings, OrthogonalHeight, XAxisAbscissa, XAxisOrdinate, Scale); + } + ToTape() { + let args = []; + args.push(this.SourceCRS); + args.push(this.TargetCRS); + args.push(this.Eastings); + args.push(this.Northings); + args.push(this.OrthogonalHeight); + args.push(this.XAxisAbscissa); + args.push(this.XAxisOrdinate); + args.push(this.Scale); + return args; + } +}; +var IfcMappedItem = class { + constructor(expressID, type, MappingSource, MappingTarget) { + this.expressID = expressID; + this.type = type; + this.MappingSource = MappingSource; + this.MappingTarget = MappingTarget; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let MappingSource = tape[ptr++]; + let MappingTarget = tape[ptr++]; + return new IfcMappedItem(expressID, type, MappingSource, MappingTarget); + } + ToTape() { + let args = []; + args.push(this.MappingSource); + args.push(this.MappingTarget); + return args; + } +}; +var IfcMaterial = class { + constructor(expressID, type, Name, Description, Category) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Category = Category; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Category = tape[ptr++]; + return new IfcMaterial(expressID, type, Name, Description, Category); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Category); + return args; + } +}; +var IfcMaterialClassificationRelationship = class { + constructor(expressID, type, MaterialClassifications, ClassifiedMaterial) { + this.expressID = expressID; + this.type = type; + this.MaterialClassifications = MaterialClassifications; + this.ClassifiedMaterial = ClassifiedMaterial; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let MaterialClassifications = tape[ptr++]; + let ClassifiedMaterial = tape[ptr++]; + return new IfcMaterialClassificationRelationship(expressID, type, MaterialClassifications, ClassifiedMaterial); + } + ToTape() { + let args = []; + args.push(this.MaterialClassifications); + args.push(this.ClassifiedMaterial); + return args; + } +}; +var IfcMaterialConstituent = class { + constructor(expressID, type, Name, Description, Material, Fraction, Category) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Material = Material; + this.Fraction = Fraction; + this.Category = Category; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Material = tape[ptr++]; + let Fraction = tape[ptr++]; + let Category = tape[ptr++]; + return new IfcMaterialConstituent(expressID, type, Name, Description, Material, Fraction, Category); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Material); + args.push(this.Fraction); + args.push(this.Category); + return args; + } +}; +var IfcMaterialConstituentSet = class { + constructor(expressID, type, Name, Description, MaterialConstituents) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.MaterialConstituents = MaterialConstituents; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let MaterialConstituents = tape[ptr++]; + return new IfcMaterialConstituentSet(expressID, type, Name, Description, MaterialConstituents); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.MaterialConstituents); + return args; + } +}; +var IfcMaterialDefinition = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcMaterialDefinition(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcMaterialDefinitionRepresentation = class { + constructor(expressID, type, Name, Description, Representations, RepresentedMaterial) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Representations = Representations; + this.RepresentedMaterial = RepresentedMaterial; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Representations = tape[ptr++]; + let RepresentedMaterial = tape[ptr++]; + return new IfcMaterialDefinitionRepresentation(expressID, type, Name, Description, Representations, RepresentedMaterial); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Representations); + args.push(this.RepresentedMaterial); + return args; + } +}; +var IfcMaterialLayer = class { + constructor(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority) { + this.expressID = expressID; + this.type = type; + this.Material = Material; + this.LayerThickness = LayerThickness; + this.IsVentilated = IsVentilated; + this.Name = Name; + this.Description = Description; + this.Category = Category; + this.Priority = Priority; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Material = tape[ptr++]; + let LayerThickness = tape[ptr++]; + let IsVentilated = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Category = tape[ptr++]; + let Priority = tape[ptr++]; + return new IfcMaterialLayer(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority); + } + ToTape() { + let args = []; + args.push(this.Material); + args.push(this.LayerThickness); + args.push(this.IsVentilated); + args.push(this.Name); + args.push(this.Description); + args.push(this.Category); + args.push(this.Priority); + return args; + } +}; +var IfcMaterialLayerSet = class { + constructor(expressID, type, MaterialLayers, LayerSetName, Description) { + this.expressID = expressID; + this.type = type; + this.MaterialLayers = MaterialLayers; + this.LayerSetName = LayerSetName; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let MaterialLayers = tape[ptr++]; + let LayerSetName = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcMaterialLayerSet(expressID, type, MaterialLayers, LayerSetName, Description); + } + ToTape() { + let args = []; + args.push(this.MaterialLayers); + args.push(this.LayerSetName); + args.push(this.Description); + return args; + } +}; +var IfcMaterialLayerSetUsage = class { + constructor(expressID, type, ForLayerSet, LayerSetDirection, DirectionSense, OffsetFromReferenceLine, ReferenceExtent) { + this.expressID = expressID; + this.type = type; + this.ForLayerSet = ForLayerSet; + this.LayerSetDirection = LayerSetDirection; + this.DirectionSense = DirectionSense; + this.OffsetFromReferenceLine = OffsetFromReferenceLine; + this.ReferenceExtent = ReferenceExtent; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ForLayerSet = tape[ptr++]; + let LayerSetDirection = tape[ptr++]; + let DirectionSense = tape[ptr++]; + let OffsetFromReferenceLine = tape[ptr++]; + let ReferenceExtent = tape[ptr++]; + return new IfcMaterialLayerSetUsage(expressID, type, ForLayerSet, LayerSetDirection, DirectionSense, OffsetFromReferenceLine, ReferenceExtent); + } + ToTape() { + let args = []; + args.push(this.ForLayerSet); + args.push(this.LayerSetDirection); + args.push(this.DirectionSense); + args.push(this.OffsetFromReferenceLine); + args.push(this.ReferenceExtent); + return args; + } +}; +var IfcMaterialLayerWithOffsets = class { + constructor(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority, OffsetDirection, OffsetValues) { + this.expressID = expressID; + this.type = type; + this.Material = Material; + this.LayerThickness = LayerThickness; + this.IsVentilated = IsVentilated; + this.Name = Name; + this.Description = Description; + this.Category = Category; + this.Priority = Priority; + this.OffsetDirection = OffsetDirection; + this.OffsetValues = OffsetValues; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Material = tape[ptr++]; + let LayerThickness = tape[ptr++]; + let IsVentilated = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Category = tape[ptr++]; + let Priority = tape[ptr++]; + let OffsetDirection = tape[ptr++]; + let OffsetValues = tape[ptr++]; + return new IfcMaterialLayerWithOffsets(expressID, type, Material, LayerThickness, IsVentilated, Name, Description, Category, Priority, OffsetDirection, OffsetValues); + } + ToTape() { + let args = []; + args.push(this.Material); + args.push(this.LayerThickness); + args.push(this.IsVentilated); + args.push(this.Name); + args.push(this.Description); + args.push(this.Category); + args.push(this.Priority); + args.push(this.OffsetDirection); + args.push(this.OffsetValues); + return args; + } +}; +var IfcMaterialList = class { + constructor(expressID, type, Materials) { + this.expressID = expressID; + this.type = type; + this.Materials = Materials; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Materials = tape[ptr++]; + return new IfcMaterialList(expressID, type, Materials); + } + ToTape() { + let args = []; + args.push(this.Materials); + return args; + } +}; +var IfcMaterialProfile = class { + constructor(expressID, type, Name, Description, Material, Profile, Priority, Category) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Material = Material; + this.Profile = Profile; + this.Priority = Priority; + this.Category = Category; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Material = tape[ptr++]; + let Profile = tape[ptr++]; + let Priority = tape[ptr++]; + let Category = tape[ptr++]; + return new IfcMaterialProfile(expressID, type, Name, Description, Material, Profile, Priority, Category); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Material); + args.push(this.Profile); + args.push(this.Priority); + args.push(this.Category); + return args; + } +}; +var IfcMaterialProfileSet = class { + constructor(expressID, type, Name, Description, MaterialProfiles, CompositeProfile) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.MaterialProfiles = MaterialProfiles; + this.CompositeProfile = CompositeProfile; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let MaterialProfiles = tape[ptr++]; + let CompositeProfile = tape[ptr++]; + return new IfcMaterialProfileSet(expressID, type, Name, Description, MaterialProfiles, CompositeProfile); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.MaterialProfiles); + args.push(this.CompositeProfile); + return args; + } +}; +var IfcMaterialProfileSetUsage = class { + constructor(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent) { + this.expressID = expressID; + this.type = type; + this.ForProfileSet = ForProfileSet; + this.CardinalPoint = CardinalPoint; + this.ReferenceExtent = ReferenceExtent; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ForProfileSet = tape[ptr++]; + let CardinalPoint = tape[ptr++]; + let ReferenceExtent = tape[ptr++]; + return new IfcMaterialProfileSetUsage(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent); + } + ToTape() { + let args = []; + args.push(this.ForProfileSet); + args.push(this.CardinalPoint); + args.push(this.ReferenceExtent); + return args; + } +}; +var IfcMaterialProfileSetUsageTapering = class { + constructor(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent, ForProfileEndSet, CardinalEndPoint) { + this.expressID = expressID; + this.type = type; + this.ForProfileSet = ForProfileSet; + this.CardinalPoint = CardinalPoint; + this.ReferenceExtent = ReferenceExtent; + this.ForProfileEndSet = ForProfileEndSet; + this.CardinalEndPoint = CardinalEndPoint; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ForProfileSet = tape[ptr++]; + let CardinalPoint = tape[ptr++]; + let ReferenceExtent = tape[ptr++]; + let ForProfileEndSet = tape[ptr++]; + let CardinalEndPoint = tape[ptr++]; + return new IfcMaterialProfileSetUsageTapering(expressID, type, ForProfileSet, CardinalPoint, ReferenceExtent, ForProfileEndSet, CardinalEndPoint); + } + ToTape() { + let args = []; + args.push(this.ForProfileSet); + args.push(this.CardinalPoint); + args.push(this.ReferenceExtent); + args.push(this.ForProfileEndSet); + args.push(this.CardinalEndPoint); + return args; + } +}; +var IfcMaterialProfileWithOffsets = class { + constructor(expressID, type, Name, Description, Material, Profile, Priority, Category, OffsetValues) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Material = Material; + this.Profile = Profile; + this.Priority = Priority; + this.Category = Category; + this.OffsetValues = OffsetValues; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Material = tape[ptr++]; + let Profile = tape[ptr++]; + let Priority = tape[ptr++]; + let Category = tape[ptr++]; + let OffsetValues = tape[ptr++]; + return new IfcMaterialProfileWithOffsets(expressID, type, Name, Description, Material, Profile, Priority, Category, OffsetValues); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Material); + args.push(this.Profile); + args.push(this.Priority); + args.push(this.Category); + args.push(this.OffsetValues); + return args; + } +}; +var IfcMaterialProperties = class { + constructor(expressID, type, Name, Description, Properties2, Material) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Properties = Properties2; + this.Material = Material; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Properties2 = tape[ptr++]; + let Material = tape[ptr++]; + return new IfcMaterialProperties(expressID, type, Name, Description, Properties2, Material); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Properties); + args.push(this.Material); + return args; + } +}; +var IfcMaterialRelationship = class { + constructor(expressID, type, Name, Description, RelatingMaterial, RelatedMaterials, Expression) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingMaterial = RelatingMaterial; + this.RelatedMaterials = RelatedMaterials; + this.Expression = Expression; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingMaterial = tape[ptr++]; + let RelatedMaterials = tape[ptr++]; + let Expression = tape[ptr++]; + return new IfcMaterialRelationship(expressID, type, Name, Description, RelatingMaterial, RelatedMaterials, Expression); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingMaterial); + args.push(this.RelatedMaterials); + args.push(this.Expression); + return args; + } +}; +var IfcMaterialUsageDefinition = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcMaterialUsageDefinition(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcMeasureWithUnit = class { + constructor(expressID, type, ValueComponent, UnitComponent) { + this.expressID = expressID; + this.type = type; + this.ValueComponent = ValueComponent; + this.UnitComponent = UnitComponent; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ValueComponent = tape[ptr++]; + let UnitComponent = tape[ptr++]; + return new IfcMeasureWithUnit(expressID, type, ValueComponent, UnitComponent); + } + ToTape() { + let args = []; + args.push(this.ValueComponent); + args.push(this.UnitComponent); + return args; + } +}; +var IfcMechanicalFastener = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NominalDiameter, NominalLength, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.NominalDiameter = NominalDiameter; + this.NominalLength = NominalLength; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let NominalDiameter = tape[ptr++]; + let NominalLength = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMechanicalFastener(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NominalDiameter, NominalLength, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.NominalDiameter); + args.push(this.NominalLength); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMechanicalFastenerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, NominalLength) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.NominalDiameter = NominalDiameter; + this.NominalLength = NominalLength; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let NominalDiameter = tape[ptr++]; + let NominalLength = tape[ptr++]; + return new IfcMechanicalFastenerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, NominalLength); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.NominalDiameter); + args.push(this.NominalLength); + return args; + } +}; +var IfcMedicalDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMedicalDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMedicalDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMedicalDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMember = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMemberStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMemberStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMemberType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMemberType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMetric = class { + constructor(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, Benchmark, ValueSource, DataValue, ReferencePath) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.ConstraintGrade = ConstraintGrade; + this.ConstraintSource = ConstraintSource; + this.CreatingActor = CreatingActor; + this.CreationTime = CreationTime; + this.UserDefinedGrade = UserDefinedGrade; + this.Benchmark = Benchmark; + this.ValueSource = ValueSource; + this.DataValue = DataValue; + this.ReferencePath = ReferencePath; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ConstraintGrade = tape[ptr++]; + let ConstraintSource = tape[ptr++]; + let CreatingActor = tape[ptr++]; + let CreationTime = tape[ptr++]; + let UserDefinedGrade = tape[ptr++]; + let Benchmark = tape[ptr++]; + let ValueSource = tape[ptr++]; + let DataValue = tape[ptr++]; + let ReferencePath = tape[ptr++]; + return new IfcMetric(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, Benchmark, ValueSource, DataValue, ReferencePath); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.ConstraintGrade); + args.push(this.ConstraintSource); + args.push(this.CreatingActor); + args.push(this.CreationTime); + args.push(this.UserDefinedGrade); + args.push(this.Benchmark); + args.push(this.ValueSource); + args.push(this.DataValue); + args.push(this.ReferencePath); + return args; + } +}; +var IfcMirroredProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.ParentProfile = ParentProfile; + this.Operator = Operator; + this.Label = Label; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let ParentProfile = tape[ptr++]; + let Operator = tape[ptr++]; + let Label = tape[ptr++]; + return new IfcMirroredProfileDef(expressID, type, ProfileType, ProfileName, ParentProfile, Operator, Label); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.ParentProfile); + args.push(this.Operator); + args.push(this.Label); + return args; + } +}; +var IfcMonetaryUnit = class { + constructor(expressID, type, Currency) { + this.expressID = expressID; + this.type = type; + this.Currency = Currency; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Currency = tape[ptr++]; + return new IfcMonetaryUnit(expressID, type, Currency); + } + ToTape() { + let args = []; + args.push(this.Currency); + return args; + } +}; +var IfcMotorConnection = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMotorConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcMotorConnectionType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcMotorConnectionType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcNamedUnit = class { + constructor(expressID, type, Dimensions, UnitType) { + this.expressID = expressID; + this.type = type; + this.Dimensions = Dimensions; + this.UnitType = UnitType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Dimensions = tape[ptr++]; + let UnitType = tape[ptr++]; + return new IfcNamedUnit(expressID, type, Dimensions, UnitType); + } + ToTape() { + let args = []; + args.push(this.Dimensions); + args.push(this.UnitType); + return args; + } +}; +var IfcObject = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + return new IfcObject(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + return args; + } +}; +var IfcObjectDefinition = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcObjectDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcObjectPlacement = class { + constructor(expressID, type, PlacementRelTo) { + this.expressID = expressID; + this.type = type; + this.PlacementRelTo = PlacementRelTo; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let PlacementRelTo = tape[ptr++]; + return new IfcObjectPlacement(expressID, type, PlacementRelTo); + } + ToTape() { + let args = []; + args.push(this.PlacementRelTo); + return args; + } +}; +var IfcObjective = class { + constructor(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, BenchmarkValues, LogicalAggregator, ObjectiveQualifier, UserDefinedQualifier) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.ConstraintGrade = ConstraintGrade; + this.ConstraintSource = ConstraintSource; + this.CreatingActor = CreatingActor; + this.CreationTime = CreationTime; + this.UserDefinedGrade = UserDefinedGrade; + this.BenchmarkValues = BenchmarkValues; + this.LogicalAggregator = LogicalAggregator; + this.ObjectiveQualifier = ObjectiveQualifier; + this.UserDefinedQualifier = UserDefinedQualifier; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ConstraintGrade = tape[ptr++]; + let ConstraintSource = tape[ptr++]; + let CreatingActor = tape[ptr++]; + let CreationTime = tape[ptr++]; + let UserDefinedGrade = tape[ptr++]; + let BenchmarkValues = tape[ptr++]; + let LogicalAggregator = tape[ptr++]; + let ObjectiveQualifier = tape[ptr++]; + let UserDefinedQualifier = tape[ptr++]; + return new IfcObjective(expressID, type, Name, Description, ConstraintGrade, ConstraintSource, CreatingActor, CreationTime, UserDefinedGrade, BenchmarkValues, LogicalAggregator, ObjectiveQualifier, UserDefinedQualifier); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.ConstraintGrade); + args.push(this.ConstraintSource); + args.push(this.CreatingActor); + args.push(this.CreationTime); + args.push(this.UserDefinedGrade); + args.push(this.BenchmarkValues); + args.push(this.LogicalAggregator); + args.push(this.ObjectiveQualifier); + args.push(this.UserDefinedQualifier); + return args; + } +}; +var IfcOccupant = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.TheActor = TheActor; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let TheActor = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcOccupant(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheActor, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.TheActor); + args.push(this.PredefinedType); + return args; + } +}; +var IfcOffsetCurve = class { + constructor(expressID, type, BasisCurve) { + this.expressID = expressID; + this.type = type; + this.BasisCurve = BasisCurve; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisCurve = tape[ptr++]; + return new IfcOffsetCurve(expressID, type, BasisCurve); + } + ToTape() { + let args = []; + args.push(this.BasisCurve); + return args; + } +}; +var IfcOffsetCurve2D = class { + constructor(expressID, type, BasisCurve, Distance, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.BasisCurve = BasisCurve; + this.Distance = Distance; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisCurve = tape[ptr++]; + let Distance = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcOffsetCurve2D(expressID, type, BasisCurve, Distance, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.BasisCurve); + args.push(this.Distance); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcOffsetCurve3D = class { + constructor(expressID, type, BasisCurve, Distance, SelfIntersect, RefDirection) { + this.expressID = expressID; + this.type = type; + this.BasisCurve = BasisCurve; + this.Distance = Distance; + this.SelfIntersect = SelfIntersect; + this.RefDirection = RefDirection; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisCurve = tape[ptr++]; + let Distance = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + let RefDirection = tape[ptr++]; + return new IfcOffsetCurve3D(expressID, type, BasisCurve, Distance, SelfIntersect, RefDirection); + } + ToTape() { + let args = []; + args.push(this.BasisCurve); + args.push(this.Distance); + args.push(this.SelfIntersect); + args.push(this.RefDirection); + return args; + } +}; +var IfcOffsetCurveByDistances = class { + constructor(expressID, type, BasisCurve, OffsetValues, Tag) { + this.expressID = expressID; + this.type = type; + this.BasisCurve = BasisCurve; + this.OffsetValues = OffsetValues; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisCurve = tape[ptr++]; + let OffsetValues = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcOffsetCurveByDistances(expressID, type, BasisCurve, OffsetValues, Tag); + } + ToTape() { + let args = []; + args.push(this.BasisCurve); + args.push(this.OffsetValues); + args.push(this.Tag); + return args; + } +}; +var IfcOpenShell = class { + constructor(expressID, type, CfsFaces) { + this.expressID = expressID; + this.type = type; + this.CfsFaces = CfsFaces; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let CfsFaces = tape[ptr++]; + return new IfcOpenShell(expressID, type, CfsFaces); + } + ToTape() { + let args = []; + args.push(this.CfsFaces); + return args; + } +}; +var IfcOpeningElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcOpeningElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcOpeningStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcOpeningStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcOrganization = class { + constructor(expressID, type, Identification, Name, Description, Roles, Addresses) { + this.expressID = expressID; + this.type = type; + this.Identification = Identification; + this.Name = Name; + this.Description = Description; + this.Roles = Roles; + this.Addresses = Addresses; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Identification = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Roles = tape[ptr++]; + let Addresses = tape[ptr++]; + return new IfcOrganization(expressID, type, Identification, Name, Description, Roles, Addresses); + } + ToTape() { + let args = []; + args.push(this.Identification); + args.push(this.Name); + args.push(this.Description); + args.push(this.Roles); + args.push(this.Addresses); + return args; + } +}; +var IfcOrganizationRelationship = class { + constructor(expressID, type, Name, Description, RelatingOrganization, RelatedOrganizations) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingOrganization = RelatingOrganization; + this.RelatedOrganizations = RelatedOrganizations; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingOrganization = tape[ptr++]; + let RelatedOrganizations = tape[ptr++]; + return new IfcOrganizationRelationship(expressID, type, Name, Description, RelatingOrganization, RelatedOrganizations); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingOrganization); + args.push(this.RelatedOrganizations); + return args; + } +}; +var IfcOrientationExpression = class { + constructor(expressID, type, LateralAxisDirection, VerticalAxisDirection) { + this.expressID = expressID; + this.type = type; + this.LateralAxisDirection = LateralAxisDirection; + this.VerticalAxisDirection = VerticalAxisDirection; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let LateralAxisDirection = tape[ptr++]; + let VerticalAxisDirection = tape[ptr++]; + return new IfcOrientationExpression(expressID, type, LateralAxisDirection, VerticalAxisDirection); + } + ToTape() { + let args = []; + args.push(this.LateralAxisDirection); + args.push(this.VerticalAxisDirection); + return args; + } +}; +var IfcOrientedEdge = class { + constructor(expressID, type, EdgeStart, EdgeEnd, EdgeElement, Orientation) { + this.expressID = expressID; + this.type = type; + this.EdgeStart = EdgeStart; + this.EdgeEnd = EdgeEnd; + this.EdgeElement = EdgeElement; + this.Orientation = Orientation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let EdgeStart = tape[ptr++]; + let EdgeEnd = tape[ptr++]; + let EdgeElement = tape[ptr++]; + let Orientation = tape[ptr++]; + return new IfcOrientedEdge(expressID, type, EdgeStart, EdgeEnd, EdgeElement, Orientation); + } + ToTape() { + let args = []; + args.push(this.EdgeStart); + args.push(this.EdgeEnd); + args.push(this.EdgeElement); + args.push(this.Orientation); + return args; + } +}; +var IfcOuterBoundaryCurve = class { + constructor(expressID, type, Segments, SelfIntersect) { + this.expressID = expressID; + this.type = type; + this.Segments = Segments; + this.SelfIntersect = SelfIntersect; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Segments = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + return new IfcOuterBoundaryCurve(expressID, type, Segments, SelfIntersect); + } + ToTape() { + let args = []; + args.push(this.Segments); + args.push(this.SelfIntersect); + return args; + } +}; +var IfcOutlet = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcOutlet(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcOutletType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcOutletType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcOwnerHistory = class { + constructor(expressID, type, OwningUser, OwningApplication, State, ChangeAction, LastModifiedDate, LastModifyingUser, LastModifyingApplication, CreationDate) { + this.expressID = expressID; + this.type = type; + this.OwningUser = OwningUser; + this.OwningApplication = OwningApplication; + this.State = State; + this.ChangeAction = ChangeAction; + this.LastModifiedDate = LastModifiedDate; + this.LastModifyingUser = LastModifyingUser; + this.LastModifyingApplication = LastModifyingApplication; + this.CreationDate = CreationDate; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let OwningUser = tape[ptr++]; + let OwningApplication = tape[ptr++]; + let State = tape[ptr++]; + let ChangeAction = tape[ptr++]; + let LastModifiedDate = tape[ptr++]; + let LastModifyingUser = tape[ptr++]; + let LastModifyingApplication = tape[ptr++]; + let CreationDate = tape[ptr++]; + return new IfcOwnerHistory(expressID, type, OwningUser, OwningApplication, State, ChangeAction, LastModifiedDate, LastModifyingUser, LastModifyingApplication, CreationDate); + } + ToTape() { + let args = []; + args.push(this.OwningUser); + args.push(this.OwningApplication); + args.push(this.State); + args.push(this.ChangeAction); + args.push(this.LastModifiedDate); + args.push(this.LastModifyingUser); + args.push(this.LastModifyingApplication); + args.push(this.CreationDate); + return args; + } +}; +var IfcParameterizedProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + return new IfcParameterizedProfileDef(expressID, type, ProfileType, ProfileName, Position); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + return args; + } +}; +var IfcPath = class { + constructor(expressID, type, EdgeList) { + this.expressID = expressID; + this.type = type; + this.EdgeList = EdgeList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let EdgeList = tape[ptr++]; + return new IfcPath(expressID, type, EdgeList); + } + ToTape() { + let args = []; + args.push(this.EdgeList); + return args; + } +}; +var IfcPcurve = class { + constructor(expressID, type, BasisSurface, ReferenceCurve) { + this.expressID = expressID; + this.type = type; + this.BasisSurface = BasisSurface; + this.ReferenceCurve = ReferenceCurve; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisSurface = tape[ptr++]; + let ReferenceCurve = tape[ptr++]; + return new IfcPcurve(expressID, type, BasisSurface, ReferenceCurve); + } + ToTape() { + let args = []; + args.push(this.BasisSurface); + args.push(this.ReferenceCurve); + return args; + } +}; +var IfcPerformanceHistory = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LifeCyclePhase, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LifeCyclePhase = LifeCyclePhase; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LifeCyclePhase = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPerformanceHistory(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LifeCyclePhase, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LifeCyclePhase); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPermeableCoveringProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.OperationType = OperationType; + this.PanelPosition = PanelPosition; + this.FrameDepth = FrameDepth; + this.FrameThickness = FrameThickness; + this.ShapeAspectStyle = ShapeAspectStyle; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let OperationType = tape[ptr++]; + let PanelPosition = tape[ptr++]; + let FrameDepth = tape[ptr++]; + let FrameThickness = tape[ptr++]; + let ShapeAspectStyle = tape[ptr++]; + return new IfcPermeableCoveringProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.OperationType); + args.push(this.PanelPosition); + args.push(this.FrameDepth); + args.push(this.FrameThickness); + args.push(this.ShapeAspectStyle); + return args; + } +}; +var IfcPermit = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.PredefinedType = PredefinedType; + this.Status = Status; + this.LongDescription = LongDescription; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Status = tape[ptr++]; + let LongDescription = tape[ptr++]; + return new IfcPermit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.PredefinedType); + args.push(this.Status); + args.push(this.LongDescription); + return args; + } +}; +var IfcPerson = class { + constructor(expressID, type, Identification, FamilyName, GivenName, MiddleNames, PrefixTitles, SuffixTitles, Roles, Addresses) { + this.expressID = expressID; + this.type = type; + this.Identification = Identification; + this.FamilyName = FamilyName; + this.GivenName = GivenName; + this.MiddleNames = MiddleNames; + this.PrefixTitles = PrefixTitles; + this.SuffixTitles = SuffixTitles; + this.Roles = Roles; + this.Addresses = Addresses; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Identification = tape[ptr++]; + let FamilyName = tape[ptr++]; + let GivenName = tape[ptr++]; + let MiddleNames = tape[ptr++]; + let PrefixTitles = tape[ptr++]; + let SuffixTitles = tape[ptr++]; + let Roles = tape[ptr++]; + let Addresses = tape[ptr++]; + return new IfcPerson(expressID, type, Identification, FamilyName, GivenName, MiddleNames, PrefixTitles, SuffixTitles, Roles, Addresses); + } + ToTape() { + let args = []; + args.push(this.Identification); + args.push(this.FamilyName); + args.push(this.GivenName); + args.push(this.MiddleNames); + args.push(this.PrefixTitles); + args.push(this.SuffixTitles); + args.push(this.Roles); + args.push(this.Addresses); + return args; + } +}; +var IfcPersonAndOrganization = class { + constructor(expressID, type, ThePerson, TheOrganization, Roles) { + this.expressID = expressID; + this.type = type; + this.ThePerson = ThePerson; + this.TheOrganization = TheOrganization; + this.Roles = Roles; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ThePerson = tape[ptr++]; + let TheOrganization = tape[ptr++]; + let Roles = tape[ptr++]; + return new IfcPersonAndOrganization(expressID, type, ThePerson, TheOrganization, Roles); + } + ToTape() { + let args = []; + args.push(this.ThePerson); + args.push(this.TheOrganization); + args.push(this.Roles); + return args; + } +}; +var IfcPhysicalComplexQuantity = class { + constructor(expressID, type, Name, Description, HasQuantities, Discrimination, Quality, Usage) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.HasQuantities = HasQuantities; + this.Discrimination = Discrimination; + this.Quality = Quality; + this.Usage = Usage; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let HasQuantities = tape[ptr++]; + let Discrimination = tape[ptr++]; + let Quality = tape[ptr++]; + let Usage = tape[ptr++]; + return new IfcPhysicalComplexQuantity(expressID, type, Name, Description, HasQuantities, Discrimination, Quality, Usage); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.HasQuantities); + args.push(this.Discrimination); + args.push(this.Quality); + args.push(this.Usage); + return args; + } +}; +var IfcPhysicalQuantity = class { + constructor(expressID, type, Name, Description) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcPhysicalQuantity(expressID, type, Name, Description); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcPhysicalSimpleQuantity = class { + constructor(expressID, type, Name, Description, Unit) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + return new IfcPhysicalSimpleQuantity(expressID, type, Name, Description, Unit); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + return args; + } +}; +var IfcPile = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType, ConstructionType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + this.ConstructionType = ConstructionType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let ConstructionType = tape[ptr++]; + return new IfcPile(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType, ConstructionType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + args.push(this.ConstructionType); + return args; + } +}; +var IfcPileType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPileType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPipeFitting = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPipeFitting(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPipeFittingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPipeFittingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPipeSegment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPipeSegment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPipeSegmentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPipeSegmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPixelTexture = class { + constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, Width, Height, ColourComponents, Pixel) { + this.expressID = expressID; + this.type = type; + this.RepeatS = RepeatS; + this.RepeatT = RepeatT; + this.Mode = Mode; + this.TextureTransform = TextureTransform; + this.Parameter = Parameter; + this.Width = Width; + this.Height = Height; + this.ColourComponents = ColourComponents; + this.Pixel = Pixel; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RepeatS = tape[ptr++]; + let RepeatT = tape[ptr++]; + let Mode = tape[ptr++]; + let TextureTransform = tape[ptr++]; + let Parameter = tape[ptr++]; + let Width = tape[ptr++]; + let Height = tape[ptr++]; + let ColourComponents = tape[ptr++]; + let Pixel = tape[ptr++]; + return new IfcPixelTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter, Width, Height, ColourComponents, Pixel); + } + ToTape() { + let args = []; + args.push(this.RepeatS); + args.push(this.RepeatT); + args.push(this.Mode); + args.push(this.TextureTransform); + args.push(this.Parameter); + args.push(this.Width); + args.push(this.Height); + args.push(this.ColourComponents); + args.push(this.Pixel); + return args; + } +}; +var IfcPlacement = class { + constructor(expressID, type, Location) { + this.expressID = expressID; + this.type = type; + this.Location = Location; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Location = tape[ptr++]; + return new IfcPlacement(expressID, type, Location); + } + ToTape() { + let args = []; + args.push(this.Location); + return args; + } +}; +var IfcPlanarBox = class { + constructor(expressID, type, SizeInX, SizeInY, Placement) { + this.expressID = expressID; + this.type = type; + this.SizeInX = SizeInX; + this.SizeInY = SizeInY; + this.Placement = Placement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SizeInX = tape[ptr++]; + let SizeInY = tape[ptr++]; + let Placement = tape[ptr++]; + return new IfcPlanarBox(expressID, type, SizeInX, SizeInY, Placement); + } + ToTape() { + let args = []; + args.push(this.SizeInX); + args.push(this.SizeInY); + args.push(this.Placement); + return args; + } +}; +var IfcPlanarExtent = class { + constructor(expressID, type, SizeInX, SizeInY) { + this.expressID = expressID; + this.type = type; + this.SizeInX = SizeInX; + this.SizeInY = SizeInY; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SizeInX = tape[ptr++]; + let SizeInY = tape[ptr++]; + return new IfcPlanarExtent(expressID, type, SizeInX, SizeInY); + } + ToTape() { + let args = []; + args.push(this.SizeInX); + args.push(this.SizeInY); + return args; + } +}; +var IfcPlane = class { + constructor(expressID, type, Position) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + return new IfcPlane(expressID, type, Position); + } + ToTape() { + let args = []; + args.push(this.Position); + return args; + } +}; +var IfcPlate = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPlate(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPlateStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPlateStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPlateType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPlateType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPoint = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcPoint(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcPointOnCurve = class { + constructor(expressID, type, BasisCurve, PointParameter) { + this.expressID = expressID; + this.type = type; + this.BasisCurve = BasisCurve; + this.PointParameter = PointParameter; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisCurve = tape[ptr++]; + let PointParameter = tape[ptr++]; + return new IfcPointOnCurve(expressID, type, BasisCurve, PointParameter); + } + ToTape() { + let args = []; + args.push(this.BasisCurve); + args.push(this.PointParameter); + return args; + } +}; +var IfcPointOnSurface = class { + constructor(expressID, type, BasisSurface, PointParameterU, PointParameterV) { + this.expressID = expressID; + this.type = type; + this.BasisSurface = BasisSurface; + this.PointParameterU = PointParameterU; + this.PointParameterV = PointParameterV; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisSurface = tape[ptr++]; + let PointParameterU = tape[ptr++]; + let PointParameterV = tape[ptr++]; + return new IfcPointOnSurface(expressID, type, BasisSurface, PointParameterU, PointParameterV); + } + ToTape() { + let args = []; + args.push(this.BasisSurface); + args.push(this.PointParameterU); + args.push(this.PointParameterV); + return args; + } +}; +var IfcPolyLoop = class { + constructor(expressID, type, Polygon) { + this.expressID = expressID; + this.type = type; + this.Polygon = Polygon; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Polygon = tape[ptr++]; + return new IfcPolyLoop(expressID, type, Polygon); + } + ToTape() { + let args = []; + args.push(this.Polygon); + return args; + } +}; +var IfcPolygonalBoundedHalfSpace = class { + constructor(expressID, type, BaseSurface, AgreementFlag, Position, PolygonalBoundary) { + this.expressID = expressID; + this.type = type; + this.BaseSurface = BaseSurface; + this.AgreementFlag = AgreementFlag; + this.Position = Position; + this.PolygonalBoundary = PolygonalBoundary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BaseSurface = tape[ptr++]; + let AgreementFlag = tape[ptr++]; + let Position = tape[ptr++]; + let PolygonalBoundary = tape[ptr++]; + return new IfcPolygonalBoundedHalfSpace(expressID, type, BaseSurface, AgreementFlag, Position, PolygonalBoundary); + } + ToTape() { + let args = []; + args.push(this.BaseSurface); + args.push(this.AgreementFlag); + args.push(this.Position); + args.push(this.PolygonalBoundary); + return args; + } +}; +var IfcPolygonalFaceSet = class { + constructor(expressID, type, Coordinates, Closed, Faces, PnIndex) { + this.expressID = expressID; + this.type = type; + this.Coordinates = Coordinates; + this.Closed = Closed; + this.Faces = Faces; + this.PnIndex = PnIndex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Coordinates = tape[ptr++]; + let Closed = tape[ptr++]; + let Faces = tape[ptr++]; + let PnIndex = tape[ptr++]; + return new IfcPolygonalFaceSet(expressID, type, Coordinates, Closed, Faces, PnIndex); + } + ToTape() { + let args = []; + args.push(this.Coordinates); + args.push(this.Closed); + args.push(this.Faces); + args.push(this.PnIndex); + return args; + } +}; +var IfcPolyline = class { + constructor(expressID, type, Points) { + this.expressID = expressID; + this.type = type; + this.Points = Points; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Points = tape[ptr++]; + return new IfcPolyline(expressID, type, Points); + } + ToTape() { + let args = []; + args.push(this.Points); + return args; + } +}; +var IfcPort = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + return new IfcPort(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + return args; + } +}; +var IfcPositioningElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + return new IfcPositioningElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + return args; + } +}; +var IfcPostalAddress = class { + constructor(expressID, type, Purpose, Description, UserDefinedPurpose, InternalLocation, AddressLines, PostalBox, Town, Region, PostalCode, Country) { + this.expressID = expressID; + this.type = type; + this.Purpose = Purpose; + this.Description = Description; + this.UserDefinedPurpose = UserDefinedPurpose; + this.InternalLocation = InternalLocation; + this.AddressLines = AddressLines; + this.PostalBox = PostalBox; + this.Town = Town; + this.Region = Region; + this.PostalCode = PostalCode; + this.Country = Country; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Purpose = tape[ptr++]; + let Description = tape[ptr++]; + let UserDefinedPurpose = tape[ptr++]; + let InternalLocation = tape[ptr++]; + let AddressLines = tape[ptr++]; + let PostalBox = tape[ptr++]; + let Town = tape[ptr++]; + let Region = tape[ptr++]; + let PostalCode = tape[ptr++]; + let Country = tape[ptr++]; + return new IfcPostalAddress(expressID, type, Purpose, Description, UserDefinedPurpose, InternalLocation, AddressLines, PostalBox, Town, Region, PostalCode, Country); + } + ToTape() { + let args = []; + args.push(this.Purpose); + args.push(this.Description); + args.push(this.UserDefinedPurpose); + args.push(this.InternalLocation); + args.push(this.AddressLines); + args.push(this.PostalBox); + args.push(this.Town); + args.push(this.Region); + args.push(this.PostalCode); + args.push(this.Country); + return args; + } +}; +var IfcPreDefinedColour = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcPreDefinedColour(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcPreDefinedCurveFont = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcPreDefinedCurveFont(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcPreDefinedItem = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcPreDefinedItem(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcPreDefinedProperties = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcPreDefinedProperties(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcPreDefinedPropertySet = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcPreDefinedPropertySet(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcPreDefinedTextFont = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcPreDefinedTextFont(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcPresentationItem = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcPresentationItem(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcPresentationLayerAssignment = class { + constructor(expressID, type, Name, Description, AssignedItems, Identifier) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.AssignedItems = AssignedItems; + this.Identifier = Identifier; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let AssignedItems = tape[ptr++]; + let Identifier = tape[ptr++]; + return new IfcPresentationLayerAssignment(expressID, type, Name, Description, AssignedItems, Identifier); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.AssignedItems); + args.push(this.Identifier); + return args; + } +}; +var IfcPresentationLayerWithStyle = class { + constructor(expressID, type, Name, Description, AssignedItems, Identifier, LayerOn, LayerFrozen, LayerBlocked, LayerStyles) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.AssignedItems = AssignedItems; + this.Identifier = Identifier; + this.LayerOn = LayerOn; + this.LayerFrozen = LayerFrozen; + this.LayerBlocked = LayerBlocked; + this.LayerStyles = LayerStyles; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let AssignedItems = tape[ptr++]; + let Identifier = tape[ptr++]; + let LayerOn = tape[ptr++]; + let LayerFrozen = tape[ptr++]; + let LayerBlocked = tape[ptr++]; + let LayerStyles = tape[ptr++]; + return new IfcPresentationLayerWithStyle(expressID, type, Name, Description, AssignedItems, Identifier, LayerOn, LayerFrozen, LayerBlocked, LayerStyles); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.AssignedItems); + args.push(this.Identifier); + args.push(this.LayerOn); + args.push(this.LayerFrozen); + args.push(this.LayerBlocked); + args.push(this.LayerStyles); + return args; + } +}; +var IfcPresentationStyle = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcPresentationStyle(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcPresentationStyleAssignment = class { + constructor(expressID, type, Styles) { + this.expressID = expressID; + this.type = type; + this.Styles = Styles; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Styles = tape[ptr++]; + return new IfcPresentationStyleAssignment(expressID, type, Styles); + } + ToTape() { + let args = []; + args.push(this.Styles); + return args; + } +}; +var IfcProcedure = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProcedure(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProcedureType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ProcessType = ProcessType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ProcessType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProcedureType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ProcessType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProcess = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + return new IfcProcess(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + return args; + } +}; +var IfcProduct = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + return new IfcProduct(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + return args; + } +}; +var IfcProductDefinitionShape = class { + constructor(expressID, type, Name, Description, Representations) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Representations = Representations; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Representations = tape[ptr++]; + return new IfcProductDefinitionShape(expressID, type, Name, Description, Representations); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Representations); + return args; + } +}; +var IfcProductRepresentation = class { + constructor(expressID, type, Name, Description, Representations) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Representations = Representations; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Representations = tape[ptr++]; + return new IfcProductRepresentation(expressID, type, Name, Description, Representations); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Representations); + return args; + } +}; +var IfcProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + return new IfcProfileDef(expressID, type, ProfileType, ProfileName); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + return args; + } +}; +var IfcProfileProperties = class { + constructor(expressID, type, Name, Description, Properties2, ProfileDefinition) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Properties = Properties2; + this.ProfileDefinition = ProfileDefinition; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Properties2 = tape[ptr++]; + let ProfileDefinition = tape[ptr++]; + return new IfcProfileProperties(expressID, type, Name, Description, Properties2, ProfileDefinition); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Properties); + args.push(this.ProfileDefinition); + return args; + } +}; +var IfcProject = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.LongName = LongName; + this.Phase = Phase; + this.RepresentationContexts = RepresentationContexts; + this.UnitsInContext = UnitsInContext; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let LongName = tape[ptr++]; + let Phase = tape[ptr++]; + let RepresentationContexts = tape[ptr++]; + let UnitsInContext = tape[ptr++]; + return new IfcProject(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.LongName); + args.push(this.Phase); + args.push(this.RepresentationContexts); + args.push(this.UnitsInContext); + return args; + } +}; +var IfcProjectLibrary = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.LongName = LongName; + this.Phase = Phase; + this.RepresentationContexts = RepresentationContexts; + this.UnitsInContext = UnitsInContext; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let LongName = tape[ptr++]; + let Phase = tape[ptr++]; + let RepresentationContexts = tape[ptr++]; + let UnitsInContext = tape[ptr++]; + return new IfcProjectLibrary(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName, Phase, RepresentationContexts, UnitsInContext); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.LongName); + args.push(this.Phase); + args.push(this.RepresentationContexts); + args.push(this.UnitsInContext); + return args; + } +}; +var IfcProjectOrder = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.PredefinedType = PredefinedType; + this.Status = Status; + this.LongDescription = LongDescription; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Status = tape[ptr++]; + let LongDescription = tape[ptr++]; + return new IfcProjectOrder(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, PredefinedType, Status, LongDescription); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.PredefinedType); + args.push(this.Status); + args.push(this.LongDescription); + return args; + } +}; +var IfcProjectedCRS = class { + constructor(expressID, type, Name, Description, GeodeticDatum, VerticalDatum, MapProjection, MapZone, MapUnit) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.GeodeticDatum = GeodeticDatum; + this.VerticalDatum = VerticalDatum; + this.MapProjection = MapProjection; + this.MapZone = MapZone; + this.MapUnit = MapUnit; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let GeodeticDatum = tape[ptr++]; + let VerticalDatum = tape[ptr++]; + let MapProjection = tape[ptr++]; + let MapZone = tape[ptr++]; + let MapUnit = tape[ptr++]; + return new IfcProjectedCRS(expressID, type, Name, Description, GeodeticDatum, VerticalDatum, MapProjection, MapZone, MapUnit); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.GeodeticDatum); + args.push(this.VerticalDatum); + args.push(this.MapProjection); + args.push(this.MapZone); + args.push(this.MapUnit); + return args; + } +}; +var IfcProjectionElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProjectionElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProperty = class { + constructor(expressID, type, Name, Description) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcProperty(expressID, type, Name, Description); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcPropertyAbstraction = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcPropertyAbstraction(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcPropertyBoundedValue = class { + constructor(expressID, type, Name, Description, UpperBoundValue, LowerBoundValue, Unit, SetPointValue) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.UpperBoundValue = UpperBoundValue; + this.LowerBoundValue = LowerBoundValue; + this.Unit = Unit; + this.SetPointValue = SetPointValue; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let UpperBoundValue = tape[ptr++]; + let LowerBoundValue = tape[ptr++]; + let Unit = tape[ptr++]; + let SetPointValue = tape[ptr++]; + return new IfcPropertyBoundedValue(expressID, type, Name, Description, UpperBoundValue, LowerBoundValue, Unit, SetPointValue); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.UpperBoundValue); + args.push(this.LowerBoundValue); + args.push(this.Unit); + args.push(this.SetPointValue); + return args; + } +}; +var IfcPropertyDefinition = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcPropertyDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcPropertyDependencyRelationship = class { + constructor(expressID, type, Name, Description, DependingProperty, DependantProperty, Expression) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.DependingProperty = DependingProperty; + this.DependantProperty = DependantProperty; + this.Expression = Expression; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let DependingProperty = tape[ptr++]; + let DependantProperty = tape[ptr++]; + let Expression = tape[ptr++]; + return new IfcPropertyDependencyRelationship(expressID, type, Name, Description, DependingProperty, DependantProperty, Expression); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.DependingProperty); + args.push(this.DependantProperty); + args.push(this.Expression); + return args; + } +}; +var IfcPropertyEnumeratedValue = class { + constructor(expressID, type, Name, Description, EnumerationValues, EnumerationReference) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.EnumerationValues = EnumerationValues; + this.EnumerationReference = EnumerationReference; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let EnumerationValues = tape[ptr++]; + let EnumerationReference = tape[ptr++]; + return new IfcPropertyEnumeratedValue(expressID, type, Name, Description, EnumerationValues, EnumerationReference); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.EnumerationValues); + args.push(this.EnumerationReference); + return args; + } +}; +var IfcPropertyEnumeration = class { + constructor(expressID, type, Name, EnumerationValues, Unit) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.EnumerationValues = EnumerationValues; + this.Unit = Unit; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let EnumerationValues = tape[ptr++]; + let Unit = tape[ptr++]; + return new IfcPropertyEnumeration(expressID, type, Name, EnumerationValues, Unit); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.EnumerationValues); + args.push(this.Unit); + return args; + } +}; +var IfcPropertyListValue = class { + constructor(expressID, type, Name, Description, ListValues, Unit) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.ListValues = ListValues; + this.Unit = Unit; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ListValues = tape[ptr++]; + let Unit = tape[ptr++]; + return new IfcPropertyListValue(expressID, type, Name, Description, ListValues, Unit); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.ListValues); + args.push(this.Unit); + return args; + } +}; +var IfcPropertyReferenceValue = class { + constructor(expressID, type, Name, Description, UsageName, PropertyReference) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.UsageName = UsageName; + this.PropertyReference = PropertyReference; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let UsageName = tape[ptr++]; + let PropertyReference = tape[ptr++]; + return new IfcPropertyReferenceValue(expressID, type, Name, Description, UsageName, PropertyReference); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.UsageName); + args.push(this.PropertyReference); + return args; + } +}; +var IfcPropertySet = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, HasProperties) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.HasProperties = HasProperties; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let HasProperties = tape[ptr++]; + return new IfcPropertySet(expressID, type, GlobalId, OwnerHistory, Name, Description, HasProperties); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.HasProperties); + return args; + } +}; +var IfcPropertySetDefinition = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcPropertySetDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcPropertySetTemplate = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, ApplicableEntity, HasPropertyTemplates) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.TemplateType = TemplateType; + this.ApplicableEntity = ApplicableEntity; + this.HasPropertyTemplates = HasPropertyTemplates; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let TemplateType = tape[ptr++]; + let ApplicableEntity = tape[ptr++]; + let HasPropertyTemplates = tape[ptr++]; + return new IfcPropertySetTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, ApplicableEntity, HasPropertyTemplates); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.TemplateType); + args.push(this.ApplicableEntity); + args.push(this.HasPropertyTemplates); + return args; + } +}; +var IfcPropertySingleValue = class { + constructor(expressID, type, Name, Description, NominalValue, Unit) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.NominalValue = NominalValue; + this.Unit = Unit; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let NominalValue = tape[ptr++]; + let Unit = tape[ptr++]; + return new IfcPropertySingleValue(expressID, type, Name, Description, NominalValue, Unit); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.NominalValue); + args.push(this.Unit); + return args; + } +}; +var IfcPropertyTableValue = class { + constructor(expressID, type, Name, Description, DefiningValues, DefinedValues, Expression, DefiningUnit, DefinedUnit, CurveInterpolation) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.DefiningValues = DefiningValues; + this.DefinedValues = DefinedValues; + this.Expression = Expression; + this.DefiningUnit = DefiningUnit; + this.DefinedUnit = DefinedUnit; + this.CurveInterpolation = CurveInterpolation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let DefiningValues = tape[ptr++]; + let DefinedValues = tape[ptr++]; + let Expression = tape[ptr++]; + let DefiningUnit = tape[ptr++]; + let DefinedUnit = tape[ptr++]; + let CurveInterpolation = tape[ptr++]; + return new IfcPropertyTableValue(expressID, type, Name, Description, DefiningValues, DefinedValues, Expression, DefiningUnit, DefinedUnit, CurveInterpolation); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.DefiningValues); + args.push(this.DefinedValues); + args.push(this.Expression); + args.push(this.DefiningUnit); + args.push(this.DefinedUnit); + args.push(this.CurveInterpolation); + return args; + } +}; +var IfcPropertyTemplate = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcPropertyTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcPropertyTemplateDefinition = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcPropertyTemplateDefinition(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcProtectiveDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProtectiveDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProtectiveDeviceTrippingUnit = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProtectiveDeviceTrippingUnit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProtectiveDeviceTrippingUnitType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProtectiveDeviceTrippingUnitType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProtectiveDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcProtectiveDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcProxy = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, ProxyType, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.ProxyType = ProxyType; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let ProxyType = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcProxy(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, ProxyType, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.ProxyType); + args.push(this.Tag); + return args; + } +}; +var IfcPump = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPump(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcPumpType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcPumpType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcQuantityArea = class { + constructor(expressID, type, Name, Description, Unit, AreaValue, Formula) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.AreaValue = AreaValue; + this.Formula = Formula; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let AreaValue = tape[ptr++]; + let Formula = tape[ptr++]; + return new IfcQuantityArea(expressID, type, Name, Description, Unit, AreaValue, Formula); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.AreaValue); + args.push(this.Formula); + return args; + } +}; +var IfcQuantityCount = class { + constructor(expressID, type, Name, Description, Unit, CountValue, Formula) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.CountValue = CountValue; + this.Formula = Formula; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let CountValue = tape[ptr++]; + let Formula = tape[ptr++]; + return new IfcQuantityCount(expressID, type, Name, Description, Unit, CountValue, Formula); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.CountValue); + args.push(this.Formula); + return args; + } +}; +var IfcQuantityLength = class { + constructor(expressID, type, Name, Description, Unit, LengthValue, Formula) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.LengthValue = LengthValue; + this.Formula = Formula; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let LengthValue = tape[ptr++]; + let Formula = tape[ptr++]; + return new IfcQuantityLength(expressID, type, Name, Description, Unit, LengthValue, Formula); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.LengthValue); + args.push(this.Formula); + return args; + } +}; +var IfcQuantitySet = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcQuantitySet(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcQuantityTime = class { + constructor(expressID, type, Name, Description, Unit, TimeValue, Formula) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.TimeValue = TimeValue; + this.Formula = Formula; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let TimeValue = tape[ptr++]; + let Formula = tape[ptr++]; + return new IfcQuantityTime(expressID, type, Name, Description, Unit, TimeValue, Formula); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.TimeValue); + args.push(this.Formula); + return args; + } +}; +var IfcQuantityVolume = class { + constructor(expressID, type, Name, Description, Unit, VolumeValue, Formula) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.VolumeValue = VolumeValue; + this.Formula = Formula; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let VolumeValue = tape[ptr++]; + let Formula = tape[ptr++]; + return new IfcQuantityVolume(expressID, type, Name, Description, Unit, VolumeValue, Formula); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.VolumeValue); + args.push(this.Formula); + return args; + } +}; +var IfcQuantityWeight = class { + constructor(expressID, type, Name, Description, Unit, WeightValue, Formula) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.WeightValue = WeightValue; + this.Formula = Formula; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let WeightValue = tape[ptr++]; + let Formula = tape[ptr++]; + return new IfcQuantityWeight(expressID, type, Name, Description, Unit, WeightValue, Formula); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.WeightValue); + args.push(this.Formula); + return args; + } +}; +var IfcRailing = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRailing(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRailingType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRailingType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRamp = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRamp(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRampFlight = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRampFlight(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRampFlightType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRampFlightType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRampType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRampType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRationalBSplineCurveWithKnots = class { + constructor(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec, WeightsData) { + this.expressID = expressID; + this.type = type; + this.Degree = Degree; + this.ControlPointsList = ControlPointsList; + this.CurveForm = CurveForm; + this.ClosedCurve = ClosedCurve; + this.SelfIntersect = SelfIntersect; + this.KnotMultiplicities = KnotMultiplicities; + this.Knots = Knots; + this.KnotSpec = KnotSpec; + this.WeightsData = WeightsData; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Degree = tape[ptr++]; + let ControlPointsList = tape[ptr++]; + let CurveForm = tape[ptr++]; + let ClosedCurve = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + let KnotMultiplicities = tape[ptr++]; + let Knots = tape[ptr++]; + let KnotSpec = tape[ptr++]; + let WeightsData = tape[ptr++]; + return new IfcRationalBSplineCurveWithKnots(expressID, type, Degree, ControlPointsList, CurveForm, ClosedCurve, SelfIntersect, KnotMultiplicities, Knots, KnotSpec, WeightsData); + } + ToTape() { + let args = []; + args.push(this.Degree); + args.push(this.ControlPointsList); + args.push(this.CurveForm); + args.push(this.ClosedCurve); + args.push(this.SelfIntersect); + args.push(this.KnotMultiplicities); + args.push(this.Knots); + args.push(this.KnotSpec); + args.push(this.WeightsData); + return args; + } +}; +var IfcRationalBSplineSurfaceWithKnots = class { + constructor(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec, WeightsData) { + this.expressID = expressID; + this.type = type; + this.UDegree = UDegree; + this.VDegree = VDegree; + this.ControlPointsList = ControlPointsList; + this.SurfaceForm = SurfaceForm; + this.UClosed = UClosed; + this.VClosed = VClosed; + this.SelfIntersect = SelfIntersect; + this.UMultiplicities = UMultiplicities; + this.VMultiplicities = VMultiplicities; + this.UKnots = UKnots; + this.VKnots = VKnots; + this.KnotSpec = KnotSpec; + this.WeightsData = WeightsData; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let UDegree = tape[ptr++]; + let VDegree = tape[ptr++]; + let ControlPointsList = tape[ptr++]; + let SurfaceForm = tape[ptr++]; + let UClosed = tape[ptr++]; + let VClosed = tape[ptr++]; + let SelfIntersect = tape[ptr++]; + let UMultiplicities = tape[ptr++]; + let VMultiplicities = tape[ptr++]; + let UKnots = tape[ptr++]; + let VKnots = tape[ptr++]; + let KnotSpec = tape[ptr++]; + let WeightsData = tape[ptr++]; + return new IfcRationalBSplineSurfaceWithKnots(expressID, type, UDegree, VDegree, ControlPointsList, SurfaceForm, UClosed, VClosed, SelfIntersect, UMultiplicities, VMultiplicities, UKnots, VKnots, KnotSpec, WeightsData); + } + ToTape() { + let args = []; + args.push(this.UDegree); + args.push(this.VDegree); + args.push(this.ControlPointsList); + args.push(this.SurfaceForm); + args.push(this.UClosed); + args.push(this.VClosed); + args.push(this.SelfIntersect); + args.push(this.UMultiplicities); + args.push(this.VMultiplicities); + args.push(this.UKnots); + args.push(this.VKnots); + args.push(this.KnotSpec); + args.push(this.WeightsData); + return args; + } +}; +var IfcRectangleHollowProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, WallThickness, InnerFilletRadius, OuterFilletRadius) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.XDim = XDim; + this.YDim = YDim; + this.WallThickness = WallThickness; + this.InnerFilletRadius = InnerFilletRadius; + this.OuterFilletRadius = OuterFilletRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let XDim = tape[ptr++]; + let YDim = tape[ptr++]; + let WallThickness = tape[ptr++]; + let InnerFilletRadius = tape[ptr++]; + let OuterFilletRadius = tape[ptr++]; + return new IfcRectangleHollowProfileDef(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, WallThickness, InnerFilletRadius, OuterFilletRadius); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.XDim); + args.push(this.YDim); + args.push(this.WallThickness); + args.push(this.InnerFilletRadius); + args.push(this.OuterFilletRadius); + return args; + } +}; +var IfcRectangleProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, XDim, YDim) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.XDim = XDim; + this.YDim = YDim; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let XDim = tape[ptr++]; + let YDim = tape[ptr++]; + return new IfcRectangleProfileDef(expressID, type, ProfileType, ProfileName, Position, XDim, YDim); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.XDim); + args.push(this.YDim); + return args; + } +}; +var IfcRectangularPyramid = class { + constructor(expressID, type, Position, XLength, YLength, Height) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.XLength = XLength; + this.YLength = YLength; + this.Height = Height; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let XLength = tape[ptr++]; + let YLength = tape[ptr++]; + let Height = tape[ptr++]; + return new IfcRectangularPyramid(expressID, type, Position, XLength, YLength, Height); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.XLength); + args.push(this.YLength); + args.push(this.Height); + return args; + } +}; +var IfcRectangularTrimmedSurface = class { + constructor(expressID, type, BasisSurface, U1, V1, U2, V2, Usense, Vsense) { + this.expressID = expressID; + this.type = type; + this.BasisSurface = BasisSurface; + this.U1 = U1; + this.V1 = V1; + this.U2 = U2; + this.V2 = V2; + this.Usense = Usense; + this.Vsense = Vsense; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisSurface = tape[ptr++]; + let U1 = tape[ptr++]; + let V1 = tape[ptr++]; + let U2 = tape[ptr++]; + let V2 = tape[ptr++]; + let Usense = tape[ptr++]; + let Vsense = tape[ptr++]; + return new IfcRectangularTrimmedSurface(expressID, type, BasisSurface, U1, V1, U2, V2, Usense, Vsense); + } + ToTape() { + let args = []; + args.push(this.BasisSurface); + args.push(this.U1); + args.push(this.V1); + args.push(this.U2); + args.push(this.V2); + args.push(this.Usense); + args.push(this.Vsense); + return args; + } +}; +var IfcRecurrencePattern = class { + constructor(expressID, type, RecurrenceType, DayComponent, WeekdayComponent, MonthComponent, Position, Interval, Occurrences, TimePeriods) { + this.expressID = expressID; + this.type = type; + this.RecurrenceType = RecurrenceType; + this.DayComponent = DayComponent; + this.WeekdayComponent = WeekdayComponent; + this.MonthComponent = MonthComponent; + this.Position = Position; + this.Interval = Interval; + this.Occurrences = Occurrences; + this.TimePeriods = TimePeriods; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RecurrenceType = tape[ptr++]; + let DayComponent = tape[ptr++]; + let WeekdayComponent = tape[ptr++]; + let MonthComponent = tape[ptr++]; + let Position = tape[ptr++]; + let Interval = tape[ptr++]; + let Occurrences = tape[ptr++]; + let TimePeriods = tape[ptr++]; + return new IfcRecurrencePattern(expressID, type, RecurrenceType, DayComponent, WeekdayComponent, MonthComponent, Position, Interval, Occurrences, TimePeriods); + } + ToTape() { + let args = []; + args.push(this.RecurrenceType); + args.push(this.DayComponent); + args.push(this.WeekdayComponent); + args.push(this.MonthComponent); + args.push(this.Position); + args.push(this.Interval); + args.push(this.Occurrences); + args.push(this.TimePeriods); + return args; + } +}; +var IfcReference = class { + constructor(expressID, type, TypeIdentifier, AttributeIdentifier, InstanceName, ListPositions, InnerReference) { + this.expressID = expressID; + this.type = type; + this.TypeIdentifier = TypeIdentifier; + this.AttributeIdentifier = AttributeIdentifier; + this.InstanceName = InstanceName; + this.ListPositions = ListPositions; + this.InnerReference = InnerReference; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TypeIdentifier = tape[ptr++]; + let AttributeIdentifier = tape[ptr++]; + let InstanceName = tape[ptr++]; + let ListPositions = tape[ptr++]; + let InnerReference = tape[ptr++]; + return new IfcReference(expressID, type, TypeIdentifier, AttributeIdentifier, InstanceName, ListPositions, InnerReference); + } + ToTape() { + let args = []; + args.push(this.TypeIdentifier); + args.push(this.AttributeIdentifier); + args.push(this.InstanceName); + args.push(this.ListPositions); + args.push(this.InnerReference); + return args; + } +}; +var IfcReferent = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, RestartDistance) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.PredefinedType = PredefinedType; + this.RestartDistance = RestartDistance; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let RestartDistance = tape[ptr++]; + return new IfcReferent(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, RestartDistance); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.PredefinedType); + args.push(this.RestartDistance); + return args; + } +}; +var IfcRegularTimeSeries = class { + constructor(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, TimeStep, Values) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.StartTime = StartTime; + this.EndTime = EndTime; + this.TimeSeriesDataType = TimeSeriesDataType; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.Unit = Unit; + this.TimeStep = TimeStep; + this.Values = Values; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let StartTime = tape[ptr++]; + let EndTime = tape[ptr++]; + let TimeSeriesDataType = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let Unit = tape[ptr++]; + let TimeStep = tape[ptr++]; + let Values = tape[ptr++]; + return new IfcRegularTimeSeries(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit, TimeStep, Values); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.StartTime); + args.push(this.EndTime); + args.push(this.TimeSeriesDataType); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.Unit); + args.push(this.TimeStep); + args.push(this.Values); + return args; + } +}; +var IfcReinforcementBarProperties = class { + constructor(expressID, type, TotalCrossSectionArea, SteelGrade, BarSurface, EffectiveDepth, NominalBarDiameter, BarCount) { + this.expressID = expressID; + this.type = type; + this.TotalCrossSectionArea = TotalCrossSectionArea; + this.SteelGrade = SteelGrade; + this.BarSurface = BarSurface; + this.EffectiveDepth = EffectiveDepth; + this.NominalBarDiameter = NominalBarDiameter; + this.BarCount = BarCount; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TotalCrossSectionArea = tape[ptr++]; + let SteelGrade = tape[ptr++]; + let BarSurface = tape[ptr++]; + let EffectiveDepth = tape[ptr++]; + let NominalBarDiameter = tape[ptr++]; + let BarCount = tape[ptr++]; + return new IfcReinforcementBarProperties(expressID, type, TotalCrossSectionArea, SteelGrade, BarSurface, EffectiveDepth, NominalBarDiameter, BarCount); + } + ToTape() { + let args = []; + args.push(this.TotalCrossSectionArea); + args.push(this.SteelGrade); + args.push(this.BarSurface); + args.push(this.EffectiveDepth); + args.push(this.NominalBarDiameter); + args.push(this.BarCount); + return args; + } +}; +var IfcReinforcementDefinitionProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, DefinitionType, ReinforcementSectionDefinitions) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.DefinitionType = DefinitionType; + this.ReinforcementSectionDefinitions = ReinforcementSectionDefinitions; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let DefinitionType = tape[ptr++]; + let ReinforcementSectionDefinitions = tape[ptr++]; + return new IfcReinforcementDefinitionProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, DefinitionType, ReinforcementSectionDefinitions); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.DefinitionType); + args.push(this.ReinforcementSectionDefinitions); + return args; + } +}; +var IfcReinforcingBar = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, NominalDiameter, CrossSectionArea, BarLength, PredefinedType, BarSurface) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.SteelGrade = SteelGrade; + this.NominalDiameter = NominalDiameter; + this.CrossSectionArea = CrossSectionArea; + this.BarLength = BarLength; + this.PredefinedType = PredefinedType; + this.BarSurface = BarSurface; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let SteelGrade = tape[ptr++]; + let NominalDiameter = tape[ptr++]; + let CrossSectionArea = tape[ptr++]; + let BarLength = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let BarSurface = tape[ptr++]; + return new IfcReinforcingBar(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, NominalDiameter, CrossSectionArea, BarLength, PredefinedType, BarSurface); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.SteelGrade); + args.push(this.NominalDiameter); + args.push(this.CrossSectionArea); + args.push(this.BarLength); + args.push(this.PredefinedType); + args.push(this.BarSurface); + return args; + } +}; +var IfcReinforcingBarType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, BarLength, BarSurface, BendingShapeCode, BendingParameters) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.NominalDiameter = NominalDiameter; + this.CrossSectionArea = CrossSectionArea; + this.BarLength = BarLength; + this.BarSurface = BarSurface; + this.BendingShapeCode = BendingShapeCode; + this.BendingParameters = BendingParameters; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let NominalDiameter = tape[ptr++]; + let CrossSectionArea = tape[ptr++]; + let BarLength = tape[ptr++]; + let BarSurface = tape[ptr++]; + let BendingShapeCode = tape[ptr++]; + let BendingParameters = tape[ptr++]; + return new IfcReinforcingBarType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, BarLength, BarSurface, BendingShapeCode, BendingParameters); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.NominalDiameter); + args.push(this.CrossSectionArea); + args.push(this.BarLength); + args.push(this.BarSurface); + args.push(this.BendingShapeCode); + args.push(this.BendingParameters); + return args; + } +}; +var IfcReinforcingElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.SteelGrade = SteelGrade; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let SteelGrade = tape[ptr++]; + return new IfcReinforcingElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.SteelGrade); + return args; + } +}; +var IfcReinforcingElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcReinforcingElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcReinforcingMesh = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.SteelGrade = SteelGrade; + this.MeshLength = MeshLength; + this.MeshWidth = MeshWidth; + this.LongitudinalBarNominalDiameter = LongitudinalBarNominalDiameter; + this.TransverseBarNominalDiameter = TransverseBarNominalDiameter; + this.LongitudinalBarCrossSectionArea = LongitudinalBarCrossSectionArea; + this.TransverseBarCrossSectionArea = TransverseBarCrossSectionArea; + this.LongitudinalBarSpacing = LongitudinalBarSpacing; + this.TransverseBarSpacing = TransverseBarSpacing; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let SteelGrade = tape[ptr++]; + let MeshLength = tape[ptr++]; + let MeshWidth = tape[ptr++]; + let LongitudinalBarNominalDiameter = tape[ptr++]; + let TransverseBarNominalDiameter = tape[ptr++]; + let LongitudinalBarCrossSectionArea = tape[ptr++]; + let TransverseBarCrossSectionArea = tape[ptr++]; + let LongitudinalBarSpacing = tape[ptr++]; + let TransverseBarSpacing = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcReinforcingMesh(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.SteelGrade); + args.push(this.MeshLength); + args.push(this.MeshWidth); + args.push(this.LongitudinalBarNominalDiameter); + args.push(this.TransverseBarNominalDiameter); + args.push(this.LongitudinalBarCrossSectionArea); + args.push(this.TransverseBarCrossSectionArea); + args.push(this.LongitudinalBarSpacing); + args.push(this.TransverseBarSpacing); + args.push(this.PredefinedType); + return args; + } +}; +var IfcReinforcingMeshType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, BendingShapeCode, BendingParameters) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.MeshLength = MeshLength; + this.MeshWidth = MeshWidth; + this.LongitudinalBarNominalDiameter = LongitudinalBarNominalDiameter; + this.TransverseBarNominalDiameter = TransverseBarNominalDiameter; + this.LongitudinalBarCrossSectionArea = LongitudinalBarCrossSectionArea; + this.TransverseBarCrossSectionArea = TransverseBarCrossSectionArea; + this.LongitudinalBarSpacing = LongitudinalBarSpacing; + this.TransverseBarSpacing = TransverseBarSpacing; + this.BendingShapeCode = BendingShapeCode; + this.BendingParameters = BendingParameters; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let MeshLength = tape[ptr++]; + let MeshWidth = tape[ptr++]; + let LongitudinalBarNominalDiameter = tape[ptr++]; + let TransverseBarNominalDiameter = tape[ptr++]; + let LongitudinalBarCrossSectionArea = tape[ptr++]; + let TransverseBarCrossSectionArea = tape[ptr++]; + let LongitudinalBarSpacing = tape[ptr++]; + let TransverseBarSpacing = tape[ptr++]; + let BendingShapeCode = tape[ptr++]; + let BendingParameters = tape[ptr++]; + return new IfcReinforcingMeshType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, MeshLength, MeshWidth, LongitudinalBarNominalDiameter, TransverseBarNominalDiameter, LongitudinalBarCrossSectionArea, TransverseBarCrossSectionArea, LongitudinalBarSpacing, TransverseBarSpacing, BendingShapeCode, BendingParameters); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.MeshLength); + args.push(this.MeshWidth); + args.push(this.LongitudinalBarNominalDiameter); + args.push(this.TransverseBarNominalDiameter); + args.push(this.LongitudinalBarCrossSectionArea); + args.push(this.TransverseBarCrossSectionArea); + args.push(this.LongitudinalBarSpacing); + args.push(this.TransverseBarSpacing); + args.push(this.BendingShapeCode); + args.push(this.BendingParameters); + return args; + } +}; +var IfcRelAggregates = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingObject = RelatingObject; + this.RelatedObjects = RelatedObjects; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingObject = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + return new IfcRelAggregates(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingObject); + args.push(this.RelatedObjects); + return args; + } +}; +var IfcRelAssigns = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + return new IfcRelAssigns(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + return args; + } +}; +var IfcRelAssignsToActor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingActor, ActingRole) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingActor = RelatingActor; + this.ActingRole = ActingRole; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingActor = tape[ptr++]; + let ActingRole = tape[ptr++]; + return new IfcRelAssignsToActor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingActor, ActingRole); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingActor); + args.push(this.ActingRole); + return args; + } +}; +var IfcRelAssignsToControl = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingControl) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingControl = RelatingControl; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingControl = tape[ptr++]; + return new IfcRelAssignsToControl(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingControl); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingControl); + return args; + } +}; +var IfcRelAssignsToGroup = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingGroup = RelatingGroup; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingGroup = tape[ptr++]; + return new IfcRelAssignsToGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingGroup); + return args; + } +}; +var IfcRelAssignsToGroupByFactor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup, Factor) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingGroup = RelatingGroup; + this.Factor = Factor; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingGroup = tape[ptr++]; + let Factor = tape[ptr++]; + return new IfcRelAssignsToGroupByFactor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingGroup, Factor); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingGroup); + args.push(this.Factor); + return args; + } +}; +var IfcRelAssignsToProcess = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProcess, QuantityInProcess) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingProcess = RelatingProcess; + this.QuantityInProcess = QuantityInProcess; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingProcess = tape[ptr++]; + let QuantityInProcess = tape[ptr++]; + return new IfcRelAssignsToProcess(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProcess, QuantityInProcess); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingProcess); + args.push(this.QuantityInProcess); + return args; + } +}; +var IfcRelAssignsToProduct = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProduct) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingProduct = RelatingProduct; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingProduct = tape[ptr++]; + return new IfcRelAssignsToProduct(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingProduct); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingProduct); + return args; + } +}; +var IfcRelAssignsToResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingResource) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatedObjectsType = RelatedObjectsType; + this.RelatingResource = RelatingResource; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatedObjectsType = tape[ptr++]; + let RelatingResource = tape[ptr++]; + return new IfcRelAssignsToResource(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatedObjectsType, RelatingResource); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatedObjectsType); + args.push(this.RelatingResource); + return args; + } +}; +var IfcRelAssociates = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + return new IfcRelAssociates(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + return args; + } +}; +var IfcRelAssociatesApproval = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingApproval) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingApproval = RelatingApproval; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingApproval = tape[ptr++]; + return new IfcRelAssociatesApproval(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingApproval); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingApproval); + return args; + } +}; +var IfcRelAssociatesClassification = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingClassification) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingClassification = RelatingClassification; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingClassification = tape[ptr++]; + return new IfcRelAssociatesClassification(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingClassification); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingClassification); + return args; + } +}; +var IfcRelAssociatesConstraint = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, Intent, RelatingConstraint) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.Intent = Intent; + this.RelatingConstraint = RelatingConstraint; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let Intent = tape[ptr++]; + let RelatingConstraint = tape[ptr++]; + return new IfcRelAssociatesConstraint(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, Intent, RelatingConstraint); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.Intent); + args.push(this.RelatingConstraint); + return args; + } +}; +var IfcRelAssociatesDocument = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingDocument) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingDocument = RelatingDocument; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingDocument = tape[ptr++]; + return new IfcRelAssociatesDocument(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingDocument); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingDocument); + return args; + } +}; +var IfcRelAssociatesLibrary = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingLibrary) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingLibrary = RelatingLibrary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingLibrary = tape[ptr++]; + return new IfcRelAssociatesLibrary(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingLibrary); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingLibrary); + return args; + } +}; +var IfcRelAssociatesMaterial = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingMaterial) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingMaterial = RelatingMaterial; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingMaterial = tape[ptr++]; + return new IfcRelAssociatesMaterial(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingMaterial); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingMaterial); + return args; + } +}; +var IfcRelConnects = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcRelConnects(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcRelConnectsElements = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ConnectionGeometry = ConnectionGeometry; + this.RelatingElement = RelatingElement; + this.RelatedElement = RelatedElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ConnectionGeometry = tape[ptr++]; + let RelatingElement = tape[ptr++]; + let RelatedElement = tape[ptr++]; + return new IfcRelConnectsElements(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ConnectionGeometry); + args.push(this.RelatingElement); + args.push(this.RelatedElement); + return args; + } +}; +var IfcRelConnectsPathElements = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RelatingPriorities, RelatedPriorities, RelatedConnectionType, RelatingConnectionType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ConnectionGeometry = ConnectionGeometry; + this.RelatingElement = RelatingElement; + this.RelatedElement = RelatedElement; + this.RelatingPriorities = RelatingPriorities; + this.RelatedPriorities = RelatedPriorities; + this.RelatedConnectionType = RelatedConnectionType; + this.RelatingConnectionType = RelatingConnectionType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ConnectionGeometry = tape[ptr++]; + let RelatingElement = tape[ptr++]; + let RelatedElement = tape[ptr++]; + let RelatingPriorities = tape[ptr++]; + let RelatedPriorities = tape[ptr++]; + let RelatedConnectionType = tape[ptr++]; + let RelatingConnectionType = tape[ptr++]; + return new IfcRelConnectsPathElements(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RelatingPriorities, RelatedPriorities, RelatedConnectionType, RelatingConnectionType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ConnectionGeometry); + args.push(this.RelatingElement); + args.push(this.RelatedElement); + args.push(this.RelatingPriorities); + args.push(this.RelatedPriorities); + args.push(this.RelatedConnectionType); + args.push(this.RelatingConnectionType); + return args; + } +}; +var IfcRelConnectsPortToElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingPort = RelatingPort; + this.RelatedElement = RelatedElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingPort = tape[ptr++]; + let RelatedElement = tape[ptr++]; + return new IfcRelConnectsPortToElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingPort); + args.push(this.RelatedElement); + return args; + } +}; +var IfcRelConnectsPorts = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedPort, RealizingElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingPort = RelatingPort; + this.RelatedPort = RelatedPort; + this.RealizingElement = RealizingElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingPort = tape[ptr++]; + let RelatedPort = tape[ptr++]; + let RealizingElement = tape[ptr++]; + return new IfcRelConnectsPorts(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPort, RelatedPort, RealizingElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingPort); + args.push(this.RelatedPort); + args.push(this.RealizingElement); + return args; + } +}; +var IfcRelConnectsStructuralActivity = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedStructuralActivity) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingElement = RelatingElement; + this.RelatedStructuralActivity = RelatedStructuralActivity; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingElement = tape[ptr++]; + let RelatedStructuralActivity = tape[ptr++]; + return new IfcRelConnectsStructuralActivity(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedStructuralActivity); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingElement); + args.push(this.RelatedStructuralActivity); + return args; + } +}; +var IfcRelConnectsStructuralMember = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingStructuralMember = RelatingStructuralMember; + this.RelatedStructuralConnection = RelatedStructuralConnection; + this.AppliedCondition = AppliedCondition; + this.AdditionalConditions = AdditionalConditions; + this.SupportedLength = SupportedLength; + this.ConditionCoordinateSystem = ConditionCoordinateSystem; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingStructuralMember = tape[ptr++]; + let RelatedStructuralConnection = tape[ptr++]; + let AppliedCondition = tape[ptr++]; + let AdditionalConditions = tape[ptr++]; + let SupportedLength = tape[ptr++]; + let ConditionCoordinateSystem = tape[ptr++]; + return new IfcRelConnectsStructuralMember(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingStructuralMember); + args.push(this.RelatedStructuralConnection); + args.push(this.AppliedCondition); + args.push(this.AdditionalConditions); + args.push(this.SupportedLength); + args.push(this.ConditionCoordinateSystem); + return args; + } +}; +var IfcRelConnectsWithEccentricity = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem, ConnectionConstraint) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingStructuralMember = RelatingStructuralMember; + this.RelatedStructuralConnection = RelatedStructuralConnection; + this.AppliedCondition = AppliedCondition; + this.AdditionalConditions = AdditionalConditions; + this.SupportedLength = SupportedLength; + this.ConditionCoordinateSystem = ConditionCoordinateSystem; + this.ConnectionConstraint = ConnectionConstraint; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingStructuralMember = tape[ptr++]; + let RelatedStructuralConnection = tape[ptr++]; + let AppliedCondition = tape[ptr++]; + let AdditionalConditions = tape[ptr++]; + let SupportedLength = tape[ptr++]; + let ConditionCoordinateSystem = tape[ptr++]; + let ConnectionConstraint = tape[ptr++]; + return new IfcRelConnectsWithEccentricity(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingStructuralMember, RelatedStructuralConnection, AppliedCondition, AdditionalConditions, SupportedLength, ConditionCoordinateSystem, ConnectionConstraint); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingStructuralMember); + args.push(this.RelatedStructuralConnection); + args.push(this.AppliedCondition); + args.push(this.AdditionalConditions); + args.push(this.SupportedLength); + args.push(this.ConditionCoordinateSystem); + args.push(this.ConnectionConstraint); + return args; + } +}; +var IfcRelConnectsWithRealizingElements = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RealizingElements, ConnectionType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ConnectionGeometry = ConnectionGeometry; + this.RelatingElement = RelatingElement; + this.RelatedElement = RelatedElement; + this.RealizingElements = RealizingElements; + this.ConnectionType = ConnectionType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ConnectionGeometry = tape[ptr++]; + let RelatingElement = tape[ptr++]; + let RelatedElement = tape[ptr++]; + let RealizingElements = tape[ptr++]; + let ConnectionType = tape[ptr++]; + return new IfcRelConnectsWithRealizingElements(expressID, type, GlobalId, OwnerHistory, Name, Description, ConnectionGeometry, RelatingElement, RelatedElement, RealizingElements, ConnectionType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ConnectionGeometry); + args.push(this.RelatingElement); + args.push(this.RelatedElement); + args.push(this.RealizingElements); + args.push(this.ConnectionType); + return args; + } +}; +var IfcRelContainedInSpatialStructure = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedElements = RelatedElements; + this.RelatingStructure = RelatingStructure; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedElements = tape[ptr++]; + let RelatingStructure = tape[ptr++]; + return new IfcRelContainedInSpatialStructure(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedElements); + args.push(this.RelatingStructure); + return args; + } +}; +var IfcRelCoversBldgElements = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedCoverings) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingBuildingElement = RelatingBuildingElement; + this.RelatedCoverings = RelatedCoverings; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingBuildingElement = tape[ptr++]; + let RelatedCoverings = tape[ptr++]; + return new IfcRelCoversBldgElements(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedCoverings); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingBuildingElement); + args.push(this.RelatedCoverings); + return args; + } +}; +var IfcRelCoversSpaces = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedCoverings) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingSpace = RelatingSpace; + this.RelatedCoverings = RelatedCoverings; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingSpace = tape[ptr++]; + let RelatedCoverings = tape[ptr++]; + return new IfcRelCoversSpaces(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedCoverings); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingSpace); + args.push(this.RelatedCoverings); + return args; + } +}; +var IfcRelDeclares = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingContext, RelatedDefinitions) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingContext = RelatingContext; + this.RelatedDefinitions = RelatedDefinitions; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingContext = tape[ptr++]; + let RelatedDefinitions = tape[ptr++]; + return new IfcRelDeclares(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingContext, RelatedDefinitions); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingContext); + args.push(this.RelatedDefinitions); + return args; + } +}; +var IfcRelDecomposes = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcRelDecomposes(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcRelDefines = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcRelDefines(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcRelDefinesByObject = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingObject) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingObject = RelatingObject; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingObject = tape[ptr++]; + return new IfcRelDefinesByObject(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingObject); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingObject); + return args; + } +}; +var IfcRelDefinesByProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingPropertyDefinition) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingPropertyDefinition = RelatingPropertyDefinition; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingPropertyDefinition = tape[ptr++]; + return new IfcRelDefinesByProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingPropertyDefinition); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingPropertyDefinition); + return args; + } +}; +var IfcRelDefinesByTemplate = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedPropertySets, RelatingTemplate) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedPropertySets = RelatedPropertySets; + this.RelatingTemplate = RelatingTemplate; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedPropertySets = tape[ptr++]; + let RelatingTemplate = tape[ptr++]; + return new IfcRelDefinesByTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedPropertySets, RelatingTemplate); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedPropertySets); + args.push(this.RelatingTemplate); + return args; + } +}; +var IfcRelDefinesByType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedObjects = RelatedObjects; + this.RelatingType = RelatingType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + let RelatingType = tape[ptr++]; + return new IfcRelDefinesByType(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedObjects, RelatingType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedObjects); + args.push(this.RelatingType); + return args; + } +}; +var IfcRelFillsElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingOpeningElement, RelatedBuildingElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingOpeningElement = RelatingOpeningElement; + this.RelatedBuildingElement = RelatedBuildingElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingOpeningElement = tape[ptr++]; + let RelatedBuildingElement = tape[ptr++]; + return new IfcRelFillsElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingOpeningElement, RelatedBuildingElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingOpeningElement); + args.push(this.RelatedBuildingElement); + return args; + } +}; +var IfcRelFlowControlElements = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedControlElements, RelatingFlowElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedControlElements = RelatedControlElements; + this.RelatingFlowElement = RelatingFlowElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedControlElements = tape[ptr++]; + let RelatingFlowElement = tape[ptr++]; + return new IfcRelFlowControlElements(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedControlElements, RelatingFlowElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedControlElements); + args.push(this.RelatingFlowElement); + return args; + } +}; +var IfcRelInterferesElements = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedElement, InterferenceGeometry, InterferenceType, ImpliedOrder) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingElement = RelatingElement; + this.RelatedElement = RelatedElement; + this.InterferenceGeometry = InterferenceGeometry; + this.InterferenceType = InterferenceType; + this.ImpliedOrder = ImpliedOrder; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingElement = tape[ptr++]; + let RelatedElement = tape[ptr++]; + let InterferenceGeometry = tape[ptr++]; + let InterferenceType = tape[ptr++]; + let ImpliedOrder = tape[ptr++]; + return new IfcRelInterferesElements(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedElement, InterferenceGeometry, InterferenceType, ImpliedOrder); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingElement); + args.push(this.RelatedElement); + args.push(this.InterferenceGeometry); + args.push(this.InterferenceType); + args.push(this.ImpliedOrder); + return args; + } +}; +var IfcRelNests = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingObject = RelatingObject; + this.RelatedObjects = RelatedObjects; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingObject = tape[ptr++]; + let RelatedObjects = tape[ptr++]; + return new IfcRelNests(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingObject, RelatedObjects); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingObject); + args.push(this.RelatedObjects); + return args; + } +}; +var IfcRelPositions = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPositioningElement, RelatedProducts) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingPositioningElement = RelatingPositioningElement; + this.RelatedProducts = RelatedProducts; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingPositioningElement = tape[ptr++]; + let RelatedProducts = tape[ptr++]; + return new IfcRelPositions(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingPositioningElement, RelatedProducts); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingPositioningElement); + args.push(this.RelatedProducts); + return args; + } +}; +var IfcRelProjectsElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedFeatureElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingElement = RelatingElement; + this.RelatedFeatureElement = RelatedFeatureElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingElement = tape[ptr++]; + let RelatedFeatureElement = tape[ptr++]; + return new IfcRelProjectsElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingElement, RelatedFeatureElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingElement); + args.push(this.RelatedFeatureElement); + return args; + } +}; +var IfcRelReferencedInSpatialStructure = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatedElements = RelatedElements; + this.RelatingStructure = RelatingStructure; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedElements = tape[ptr++]; + let RelatingStructure = tape[ptr++]; + return new IfcRelReferencedInSpatialStructure(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatedElements, RelatingStructure); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedElements); + args.push(this.RelatingStructure); + return args; + } +}; +var IfcRelSequence = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingProcess, RelatedProcess, TimeLag, SequenceType, UserDefinedSequenceType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingProcess = RelatingProcess; + this.RelatedProcess = RelatedProcess; + this.TimeLag = TimeLag; + this.SequenceType = SequenceType; + this.UserDefinedSequenceType = UserDefinedSequenceType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingProcess = tape[ptr++]; + let RelatedProcess = tape[ptr++]; + let TimeLag = tape[ptr++]; + let SequenceType = tape[ptr++]; + let UserDefinedSequenceType = tape[ptr++]; + return new IfcRelSequence(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingProcess, RelatedProcess, TimeLag, SequenceType, UserDefinedSequenceType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingProcess); + args.push(this.RelatedProcess); + args.push(this.TimeLag); + args.push(this.SequenceType); + args.push(this.UserDefinedSequenceType); + return args; + } +}; +var IfcRelServicesBuildings = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSystem, RelatedBuildings) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingSystem = RelatingSystem; + this.RelatedBuildings = RelatedBuildings; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingSystem = tape[ptr++]; + let RelatedBuildings = tape[ptr++]; + return new IfcRelServicesBuildings(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSystem, RelatedBuildings); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingSystem); + args.push(this.RelatedBuildings); + return args; + } +}; +var IfcRelSpaceBoundary = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingSpace = RelatingSpace; + this.RelatedBuildingElement = RelatedBuildingElement; + this.ConnectionGeometry = ConnectionGeometry; + this.PhysicalOrVirtualBoundary = PhysicalOrVirtualBoundary; + this.InternalOrExternalBoundary = InternalOrExternalBoundary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingSpace = tape[ptr++]; + let RelatedBuildingElement = tape[ptr++]; + let ConnectionGeometry = tape[ptr++]; + let PhysicalOrVirtualBoundary = tape[ptr++]; + let InternalOrExternalBoundary = tape[ptr++]; + return new IfcRelSpaceBoundary(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingSpace); + args.push(this.RelatedBuildingElement); + args.push(this.ConnectionGeometry); + args.push(this.PhysicalOrVirtualBoundary); + args.push(this.InternalOrExternalBoundary); + return args; + } +}; +var IfcRelSpaceBoundary1stLevel = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingSpace = RelatingSpace; + this.RelatedBuildingElement = RelatedBuildingElement; + this.ConnectionGeometry = ConnectionGeometry; + this.PhysicalOrVirtualBoundary = PhysicalOrVirtualBoundary; + this.InternalOrExternalBoundary = InternalOrExternalBoundary; + this.ParentBoundary = ParentBoundary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingSpace = tape[ptr++]; + let RelatedBuildingElement = tape[ptr++]; + let ConnectionGeometry = tape[ptr++]; + let PhysicalOrVirtualBoundary = tape[ptr++]; + let InternalOrExternalBoundary = tape[ptr++]; + let ParentBoundary = tape[ptr++]; + return new IfcRelSpaceBoundary1stLevel(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingSpace); + args.push(this.RelatedBuildingElement); + args.push(this.ConnectionGeometry); + args.push(this.PhysicalOrVirtualBoundary); + args.push(this.InternalOrExternalBoundary); + args.push(this.ParentBoundary); + return args; + } +}; +var IfcRelSpaceBoundary2ndLevel = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary, CorrespondingBoundary) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingSpace = RelatingSpace; + this.RelatedBuildingElement = RelatedBuildingElement; + this.ConnectionGeometry = ConnectionGeometry; + this.PhysicalOrVirtualBoundary = PhysicalOrVirtualBoundary; + this.InternalOrExternalBoundary = InternalOrExternalBoundary; + this.ParentBoundary = ParentBoundary; + this.CorrespondingBoundary = CorrespondingBoundary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingSpace = tape[ptr++]; + let RelatedBuildingElement = tape[ptr++]; + let ConnectionGeometry = tape[ptr++]; + let PhysicalOrVirtualBoundary = tape[ptr++]; + let InternalOrExternalBoundary = tape[ptr++]; + let ParentBoundary = tape[ptr++]; + let CorrespondingBoundary = tape[ptr++]; + return new IfcRelSpaceBoundary2ndLevel(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingSpace, RelatedBuildingElement, ConnectionGeometry, PhysicalOrVirtualBoundary, InternalOrExternalBoundary, ParentBoundary, CorrespondingBoundary); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingSpace); + args.push(this.RelatedBuildingElement); + args.push(this.ConnectionGeometry); + args.push(this.PhysicalOrVirtualBoundary); + args.push(this.InternalOrExternalBoundary); + args.push(this.ParentBoundary); + args.push(this.CorrespondingBoundary); + return args; + } +}; +var IfcRelVoidsElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedOpeningElement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.RelatingBuildingElement = RelatingBuildingElement; + this.RelatedOpeningElement = RelatedOpeningElement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingBuildingElement = tape[ptr++]; + let RelatedOpeningElement = tape[ptr++]; + return new IfcRelVoidsElement(expressID, type, GlobalId, OwnerHistory, Name, Description, RelatingBuildingElement, RelatedOpeningElement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingBuildingElement); + args.push(this.RelatedOpeningElement); + return args; + } +}; +var IfcRelationship = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcRelationship(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcReparametrisedCompositeCurveSegment = class { + constructor(expressID, type, Transition, SameSense, ParentCurve, ParamLength) { + this.expressID = expressID; + this.type = type; + this.Transition = Transition; + this.SameSense = SameSense; + this.ParentCurve = ParentCurve; + this.ParamLength = ParamLength; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Transition = tape[ptr++]; + let SameSense = tape[ptr++]; + let ParentCurve = tape[ptr++]; + let ParamLength = tape[ptr++]; + return new IfcReparametrisedCompositeCurveSegment(expressID, type, Transition, SameSense, ParentCurve, ParamLength); + } + ToTape() { + let args = []; + args.push(this.Transition); + args.push(this.SameSense); + args.push(this.ParentCurve); + args.push(this.ParamLength); + return args; + } +}; +var IfcRepresentation = class { + constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { + this.expressID = expressID; + this.type = type; + this.ContextOfItems = ContextOfItems; + this.RepresentationIdentifier = RepresentationIdentifier; + this.RepresentationType = RepresentationType; + this.Items = Items; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextOfItems = tape[ptr++]; + let RepresentationIdentifier = tape[ptr++]; + let RepresentationType = tape[ptr++]; + let Items = tape[ptr++]; + return new IfcRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); + } + ToTape() { + let args = []; + args.push(this.ContextOfItems); + args.push(this.RepresentationIdentifier); + args.push(this.RepresentationType); + args.push(this.Items); + return args; + } +}; +var IfcRepresentationContext = class { + constructor(expressID, type, ContextIdentifier, ContextType) { + this.expressID = expressID; + this.type = type; + this.ContextIdentifier = ContextIdentifier; + this.ContextType = ContextType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextIdentifier = tape[ptr++]; + let ContextType = tape[ptr++]; + return new IfcRepresentationContext(expressID, type, ContextIdentifier, ContextType); + } + ToTape() { + let args = []; + args.push(this.ContextIdentifier); + args.push(this.ContextType); + return args; + } +}; +var IfcRepresentationItem = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcRepresentationItem(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcRepresentationMap = class { + constructor(expressID, type, MappingOrigin, MappedRepresentation) { + this.expressID = expressID; + this.type = type; + this.MappingOrigin = MappingOrigin; + this.MappedRepresentation = MappedRepresentation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let MappingOrigin = tape[ptr++]; + let MappedRepresentation = tape[ptr++]; + return new IfcRepresentationMap(expressID, type, MappingOrigin, MappedRepresentation); + } + ToTape() { + let args = []; + args.push(this.MappingOrigin); + args.push(this.MappedRepresentation); + return args; + } +}; +var IfcResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + return new IfcResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + return args; + } +}; +var IfcResourceApprovalRelationship = class { + constructor(expressID, type, Name, Description, RelatedResourceObjects, RelatingApproval) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatedResourceObjects = RelatedResourceObjects; + this.RelatingApproval = RelatingApproval; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatedResourceObjects = tape[ptr++]; + let RelatingApproval = tape[ptr++]; + return new IfcResourceApprovalRelationship(expressID, type, Name, Description, RelatedResourceObjects, RelatingApproval); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatedResourceObjects); + args.push(this.RelatingApproval); + return args; + } +}; +var IfcResourceConstraintRelationship = class { + constructor(expressID, type, Name, Description, RelatingConstraint, RelatedResourceObjects) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.RelatingConstraint = RelatingConstraint; + this.RelatedResourceObjects = RelatedResourceObjects; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let RelatingConstraint = tape[ptr++]; + let RelatedResourceObjects = tape[ptr++]; + return new IfcResourceConstraintRelationship(expressID, type, Name, Description, RelatingConstraint, RelatedResourceObjects); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.RelatingConstraint); + args.push(this.RelatedResourceObjects); + return args; + } +}; +var IfcResourceLevelRelationship = class { + constructor(expressID, type, Name, Description) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcResourceLevelRelationship(expressID, type, Name, Description); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcResourceTime = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ScheduleWork, ScheduleUsage, ScheduleStart, ScheduleFinish, ScheduleContour, LevelingDelay, IsOverAllocated, StatusTime, ActualWork, ActualUsage, ActualStart, ActualFinish, RemainingWork, RemainingUsage, Completion) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.ScheduleWork = ScheduleWork; + this.ScheduleUsage = ScheduleUsage; + this.ScheduleStart = ScheduleStart; + this.ScheduleFinish = ScheduleFinish; + this.ScheduleContour = ScheduleContour; + this.LevelingDelay = LevelingDelay; + this.IsOverAllocated = IsOverAllocated; + this.StatusTime = StatusTime; + this.ActualWork = ActualWork; + this.ActualUsage = ActualUsage; + this.ActualStart = ActualStart; + this.ActualFinish = ActualFinish; + this.RemainingWork = RemainingWork; + this.RemainingUsage = RemainingUsage; + this.Completion = Completion; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let ScheduleWork = tape[ptr++]; + let ScheduleUsage = tape[ptr++]; + let ScheduleStart = tape[ptr++]; + let ScheduleFinish = tape[ptr++]; + let ScheduleContour = tape[ptr++]; + let LevelingDelay = tape[ptr++]; + let IsOverAllocated = tape[ptr++]; + let StatusTime = tape[ptr++]; + let ActualWork = tape[ptr++]; + let ActualUsage = tape[ptr++]; + let ActualStart = tape[ptr++]; + let ActualFinish = tape[ptr++]; + let RemainingWork = tape[ptr++]; + let RemainingUsage = tape[ptr++]; + let Completion = tape[ptr++]; + return new IfcResourceTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, ScheduleWork, ScheduleUsage, ScheduleStart, ScheduleFinish, ScheduleContour, LevelingDelay, IsOverAllocated, StatusTime, ActualWork, ActualUsage, ActualStart, ActualFinish, RemainingWork, RemainingUsage, Completion); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.ScheduleWork); + args.push(this.ScheduleUsage); + args.push(this.ScheduleStart); + args.push(this.ScheduleFinish); + args.push(this.ScheduleContour); + args.push(this.LevelingDelay); + args.push(this.IsOverAllocated); + args.push(this.StatusTime); + args.push(this.ActualWork); + args.push(this.ActualUsage); + args.push(this.ActualStart); + args.push(this.ActualFinish); + args.push(this.RemainingWork); + args.push(this.RemainingUsage); + args.push(this.Completion); + return args; + } +}; +var IfcRevolvedAreaSolid = class { + constructor(expressID, type, SweptArea, Position, Axis, Angle) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + this.Axis = Axis; + this.Angle = Angle; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + let Axis = tape[ptr++]; + let Angle = tape[ptr++]; + return new IfcRevolvedAreaSolid(expressID, type, SweptArea, Position, Axis, Angle); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + args.push(this.Axis); + args.push(this.Angle); + return args; + } +}; +var IfcRevolvedAreaSolidTapered = class { + constructor(expressID, type, SweptArea, Position, Axis, Angle, EndSweptArea) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + this.Axis = Axis; + this.Angle = Angle; + this.EndSweptArea = EndSweptArea; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + let Axis = tape[ptr++]; + let Angle = tape[ptr++]; + let EndSweptArea = tape[ptr++]; + return new IfcRevolvedAreaSolidTapered(expressID, type, SweptArea, Position, Axis, Angle, EndSweptArea); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + args.push(this.Axis); + args.push(this.Angle); + args.push(this.EndSweptArea); + return args; + } +}; +var IfcRightCircularCone = class { + constructor(expressID, type, Position, Height, BottomRadius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.Height = Height; + this.BottomRadius = BottomRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let Height = tape[ptr++]; + let BottomRadius = tape[ptr++]; + return new IfcRightCircularCone(expressID, type, Position, Height, BottomRadius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.Height); + args.push(this.BottomRadius); + return args; + } +}; +var IfcRightCircularCylinder = class { + constructor(expressID, type, Position, Height, Radius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.Height = Height; + this.Radius = Radius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let Height = tape[ptr++]; + let Radius = tape[ptr++]; + return new IfcRightCircularCylinder(expressID, type, Position, Height, Radius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.Height); + args.push(this.Radius); + return args; + } +}; +var IfcRoof = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRoof(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRoofType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcRoofType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcRoot = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcRoot(expressID, type, GlobalId, OwnerHistory, Name, Description); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcRoundedRectangleProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, RoundingRadius) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.XDim = XDim; + this.YDim = YDim; + this.RoundingRadius = RoundingRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let XDim = tape[ptr++]; + let YDim = tape[ptr++]; + let RoundingRadius = tape[ptr++]; + return new IfcRoundedRectangleProfileDef(expressID, type, ProfileType, ProfileName, Position, XDim, YDim, RoundingRadius); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.XDim); + args.push(this.YDim); + args.push(this.RoundingRadius); + return args; + } +}; +var IfcSIUnit = class { + constructor(expressID, type, Dimensions, UnitType, Prefix, Name) { + this.expressID = expressID; + this.type = type; + this.Dimensions = Dimensions; + this.UnitType = UnitType; + this.Prefix = Prefix; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Dimensions = tape[ptr++]; + let UnitType = tape[ptr++]; + let Prefix = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcSIUnit(expressID, type, Dimensions, UnitType, Prefix, Name); + } + ToTape() { + let args = []; + args.push(this.Dimensions); + args.push(this.UnitType); + args.push(this.Prefix); + args.push(this.Name); + return args; + } +}; +var IfcSanitaryTerminal = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSanitaryTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSanitaryTerminalType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSanitaryTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSchedulingTime = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + return new IfcSchedulingTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + return args; + } +}; +var IfcSeamCurve = class { + constructor(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation) { + this.expressID = expressID; + this.type = type; + this.Curve3D = Curve3D; + this.AssociatedGeometry = AssociatedGeometry; + this.MasterRepresentation = MasterRepresentation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Curve3D = tape[ptr++]; + let AssociatedGeometry = tape[ptr++]; + let MasterRepresentation = tape[ptr++]; + return new IfcSeamCurve(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation); + } + ToTape() { + let args = []; + args.push(this.Curve3D); + args.push(this.AssociatedGeometry); + args.push(this.MasterRepresentation); + return args; + } +}; +var IfcSectionProperties = class { + constructor(expressID, type, SectionType, StartProfile, EndProfile) { + this.expressID = expressID; + this.type = type; + this.SectionType = SectionType; + this.StartProfile = StartProfile; + this.EndProfile = EndProfile; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SectionType = tape[ptr++]; + let StartProfile = tape[ptr++]; + let EndProfile = tape[ptr++]; + return new IfcSectionProperties(expressID, type, SectionType, StartProfile, EndProfile); + } + ToTape() { + let args = []; + args.push(this.SectionType); + args.push(this.StartProfile); + args.push(this.EndProfile); + return args; + } +}; +var IfcSectionReinforcementProperties = class { + constructor(expressID, type, LongitudinalStartPosition, LongitudinalEndPosition, TransversePosition, ReinforcementRole, SectionDefinition, CrossSectionReinforcementDefinitions) { + this.expressID = expressID; + this.type = type; + this.LongitudinalStartPosition = LongitudinalStartPosition; + this.LongitudinalEndPosition = LongitudinalEndPosition; + this.TransversePosition = TransversePosition; + this.ReinforcementRole = ReinforcementRole; + this.SectionDefinition = SectionDefinition; + this.CrossSectionReinforcementDefinitions = CrossSectionReinforcementDefinitions; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let LongitudinalStartPosition = tape[ptr++]; + let LongitudinalEndPosition = tape[ptr++]; + let TransversePosition = tape[ptr++]; + let ReinforcementRole = tape[ptr++]; + let SectionDefinition = tape[ptr++]; + let CrossSectionReinforcementDefinitions = tape[ptr++]; + return new IfcSectionReinforcementProperties(expressID, type, LongitudinalStartPosition, LongitudinalEndPosition, TransversePosition, ReinforcementRole, SectionDefinition, CrossSectionReinforcementDefinitions); + } + ToTape() { + let args = []; + args.push(this.LongitudinalStartPosition); + args.push(this.LongitudinalEndPosition); + args.push(this.TransversePosition); + args.push(this.ReinforcementRole); + args.push(this.SectionDefinition); + args.push(this.CrossSectionReinforcementDefinitions); + return args; + } +}; +var IfcSectionedSolid = class { + constructor(expressID, type, Directrix, CrossSections) { + this.expressID = expressID; + this.type = type; + this.Directrix = Directrix; + this.CrossSections = CrossSections; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Directrix = tape[ptr++]; + let CrossSections = tape[ptr++]; + return new IfcSectionedSolid(expressID, type, Directrix, CrossSections); + } + ToTape() { + let args = []; + args.push(this.Directrix); + args.push(this.CrossSections); + return args; + } +}; +var IfcSectionedSolidHorizontal = class { + constructor(expressID, type, Directrix, CrossSections, CrossSectionPositions, FixedAxisVertical) { + this.expressID = expressID; + this.type = type; + this.Directrix = Directrix; + this.CrossSections = CrossSections; + this.CrossSectionPositions = CrossSectionPositions; + this.FixedAxisVertical = FixedAxisVertical; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Directrix = tape[ptr++]; + let CrossSections = tape[ptr++]; + let CrossSectionPositions = tape[ptr++]; + let FixedAxisVertical = tape[ptr++]; + return new IfcSectionedSolidHorizontal(expressID, type, Directrix, CrossSections, CrossSectionPositions, FixedAxisVertical); + } + ToTape() { + let args = []; + args.push(this.Directrix); + args.push(this.CrossSections); + args.push(this.CrossSectionPositions); + args.push(this.FixedAxisVertical); + return args; + } +}; +var IfcSectionedSpine = class { + constructor(expressID, type, SpineCurve, CrossSections, CrossSectionPositions) { + this.expressID = expressID; + this.type = type; + this.SpineCurve = SpineCurve; + this.CrossSections = CrossSections; + this.CrossSectionPositions = CrossSectionPositions; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SpineCurve = tape[ptr++]; + let CrossSections = tape[ptr++]; + let CrossSectionPositions = tape[ptr++]; + return new IfcSectionedSpine(expressID, type, SpineCurve, CrossSections, CrossSectionPositions); + } + ToTape() { + let args = []; + args.push(this.SpineCurve); + args.push(this.CrossSections); + args.push(this.CrossSectionPositions); + return args; + } +}; +var IfcSensor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSensor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSensorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSensorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcShadingDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcShadingDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcShadingDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcShadingDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcShapeAspect = class { + constructor(expressID, type, ShapeRepresentations, Name, Description, ProductDefinitional, PartOfProductDefinitionShape) { + this.expressID = expressID; + this.type = type; + this.ShapeRepresentations = ShapeRepresentations; + this.Name = Name; + this.Description = Description; + this.ProductDefinitional = ProductDefinitional; + this.PartOfProductDefinitionShape = PartOfProductDefinitionShape; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ShapeRepresentations = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ProductDefinitional = tape[ptr++]; + let PartOfProductDefinitionShape = tape[ptr++]; + return new IfcShapeAspect(expressID, type, ShapeRepresentations, Name, Description, ProductDefinitional, PartOfProductDefinitionShape); + } + ToTape() { + let args = []; + args.push(this.ShapeRepresentations); + args.push(this.Name); + args.push(this.Description); + args.push(this.ProductDefinitional); + args.push(this.PartOfProductDefinitionShape); + return args; + } +}; +var IfcShapeModel = class { + constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { + this.expressID = expressID; + this.type = type; + this.ContextOfItems = ContextOfItems; + this.RepresentationIdentifier = RepresentationIdentifier; + this.RepresentationType = RepresentationType; + this.Items = Items; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextOfItems = tape[ptr++]; + let RepresentationIdentifier = tape[ptr++]; + let RepresentationType = tape[ptr++]; + let Items = tape[ptr++]; + return new IfcShapeModel(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); + } + ToTape() { + let args = []; + args.push(this.ContextOfItems); + args.push(this.RepresentationIdentifier); + args.push(this.RepresentationType); + args.push(this.Items); + return args; + } +}; +var IfcShapeRepresentation = class { + constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { + this.expressID = expressID; + this.type = type; + this.ContextOfItems = ContextOfItems; + this.RepresentationIdentifier = RepresentationIdentifier; + this.RepresentationType = RepresentationType; + this.Items = Items; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextOfItems = tape[ptr++]; + let RepresentationIdentifier = tape[ptr++]; + let RepresentationType = tape[ptr++]; + let Items = tape[ptr++]; + return new IfcShapeRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); + } + ToTape() { + let args = []; + args.push(this.ContextOfItems); + args.push(this.RepresentationIdentifier); + args.push(this.RepresentationType); + args.push(this.Items); + return args; + } +}; +var IfcShellBasedSurfaceModel = class { + constructor(expressID, type, SbsmBoundary) { + this.expressID = expressID; + this.type = type; + this.SbsmBoundary = SbsmBoundary; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SbsmBoundary = tape[ptr++]; + return new IfcShellBasedSurfaceModel(expressID, type, SbsmBoundary); + } + ToTape() { + let args = []; + args.push(this.SbsmBoundary); + return args; + } +}; +var IfcSimpleProperty = class { + constructor(expressID, type, Name, Description) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + return new IfcSimpleProperty(expressID, type, Name, Description); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + return args; + } +}; +var IfcSimplePropertyTemplate = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, PrimaryMeasureType, SecondaryMeasureType, Enumerators, PrimaryUnit, SecondaryUnit, Expression, AccessState) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.TemplateType = TemplateType; + this.PrimaryMeasureType = PrimaryMeasureType; + this.SecondaryMeasureType = SecondaryMeasureType; + this.Enumerators = Enumerators; + this.PrimaryUnit = PrimaryUnit; + this.SecondaryUnit = SecondaryUnit; + this.Expression = Expression; + this.AccessState = AccessState; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let TemplateType = tape[ptr++]; + let PrimaryMeasureType = tape[ptr++]; + let SecondaryMeasureType = tape[ptr++]; + let Enumerators = tape[ptr++]; + let PrimaryUnit = tape[ptr++]; + let SecondaryUnit = tape[ptr++]; + let Expression = tape[ptr++]; + let AccessState = tape[ptr++]; + return new IfcSimplePropertyTemplate(expressID, type, GlobalId, OwnerHistory, Name, Description, TemplateType, PrimaryMeasureType, SecondaryMeasureType, Enumerators, PrimaryUnit, SecondaryUnit, Expression, AccessState); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.TemplateType); + args.push(this.PrimaryMeasureType); + args.push(this.SecondaryMeasureType); + args.push(this.Enumerators); + args.push(this.PrimaryUnit); + args.push(this.SecondaryUnit); + args.push(this.Expression); + args.push(this.AccessState); + return args; + } +}; +var IfcSite = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, RefLatitude, RefLongitude, RefElevation, LandTitleNumber, SiteAddress) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + this.RefLatitude = RefLatitude; + this.RefLongitude = RefLongitude; + this.RefElevation = RefElevation; + this.LandTitleNumber = LandTitleNumber; + this.SiteAddress = SiteAddress; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + let RefLatitude = tape[ptr++]; + let RefLongitude = tape[ptr++]; + let RefElevation = tape[ptr++]; + let LandTitleNumber = tape[ptr++]; + let SiteAddress = tape[ptr++]; + return new IfcSite(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, RefLatitude, RefLongitude, RefElevation, LandTitleNumber, SiteAddress); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + args.push(this.RefLatitude); + args.push(this.RefLongitude); + args.push(this.RefElevation); + args.push(this.LandTitleNumber); + args.push(this.SiteAddress); + return args; + } +}; +var IfcSlab = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSlab(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSlabElementedCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSlabElementedCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSlabStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSlabStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSlabType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSlabType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSlippageConnectionCondition = class { + constructor(expressID, type, Name, SlippageX, SlippageY, SlippageZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.SlippageX = SlippageX; + this.SlippageY = SlippageY; + this.SlippageZ = SlippageZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let SlippageX = tape[ptr++]; + let SlippageY = tape[ptr++]; + let SlippageZ = tape[ptr++]; + return new IfcSlippageConnectionCondition(expressID, type, Name, SlippageX, SlippageY, SlippageZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.SlippageX); + args.push(this.SlippageY); + args.push(this.SlippageZ); + return args; + } +}; +var IfcSolarDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSolarDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSolarDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSolarDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSolidModel = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcSolidModel(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcSpace = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType, ElevationWithFlooring) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + this.PredefinedType = PredefinedType; + this.ElevationWithFlooring = ElevationWithFlooring; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let ElevationWithFlooring = tape[ptr++]; + return new IfcSpace(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType, PredefinedType, ElevationWithFlooring); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + args.push(this.PredefinedType); + args.push(this.ElevationWithFlooring); + return args; + } +}; +var IfcSpaceHeater = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSpaceHeater(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSpaceHeaterType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSpaceHeaterType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSpaceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.LongName = LongName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let LongName = tape[ptr++]; + return new IfcSpaceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.LongName); + return args; + } +}; +var IfcSpatialElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + return new IfcSpatialElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + return args; + } +}; +var IfcSpatialElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcSpatialElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcSpatialStructureElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.CompositionType = CompositionType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let CompositionType = tape[ptr++]; + return new IfcSpatialStructureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, CompositionType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.CompositionType); + return args; + } +}; +var IfcSpatialStructureElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + return new IfcSpatialStructureElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + return args; + } +}; +var IfcSpatialZone = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.LongName = LongName; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let LongName = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSpatialZone(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, LongName, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.LongName); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSpatialZoneType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.LongName = LongName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let LongName = tape[ptr++]; + return new IfcSpatialZoneType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, LongName); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.LongName); + return args; + } +}; +var IfcSphere = class { + constructor(expressID, type, Position, Radius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.Radius = Radius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + return new IfcSphere(expressID, type, Position, Radius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.Radius); + return args; + } +}; +var IfcSphericalSurface = class { + constructor(expressID, type, Position, Radius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.Radius = Radius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let Radius = tape[ptr++]; + return new IfcSphericalSurface(expressID, type, Position, Radius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.Radius); + return args; + } +}; +var IfcStackTerminal = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStackTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStackTerminalType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStackTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStair = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStair(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStairFlight = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NumberOfRisers, NumberOfTreads, RiserHeight, TreadLength, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.NumberOfRisers = NumberOfRisers; + this.NumberOfTreads = NumberOfTreads; + this.RiserHeight = RiserHeight; + this.TreadLength = TreadLength; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let NumberOfRisers = tape[ptr++]; + let NumberOfTreads = tape[ptr++]; + let RiserHeight = tape[ptr++]; + let TreadLength = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStairFlight(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, NumberOfRisers, NumberOfTreads, RiserHeight, TreadLength, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.NumberOfRisers); + args.push(this.NumberOfTreads); + args.push(this.RiserHeight); + args.push(this.TreadLength); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStairFlightType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStairFlightType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStairType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStairType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStructuralAction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.DestabilizingLoad = DestabilizingLoad; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let DestabilizingLoad = tape[ptr++]; + return new IfcStructuralAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.DestabilizingLoad); + return args; + } +}; +var IfcStructuralActivity = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + return new IfcStructuralActivity(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + return args; + } +}; +var IfcStructuralAnalysisModel = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, OrientationOf2DPlane, LoadedBy, HasResults, SharedPlacement) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.PredefinedType = PredefinedType; + this.OrientationOf2DPlane = OrientationOf2DPlane; + this.LoadedBy = LoadedBy; + this.HasResults = HasResults; + this.SharedPlacement = SharedPlacement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let OrientationOf2DPlane = tape[ptr++]; + let LoadedBy = tape[ptr++]; + let HasResults = tape[ptr++]; + let SharedPlacement = tape[ptr++]; + return new IfcStructuralAnalysisModel(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, OrientationOf2DPlane, LoadedBy, HasResults, SharedPlacement); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.PredefinedType); + args.push(this.OrientationOf2DPlane); + args.push(this.LoadedBy); + args.push(this.HasResults); + args.push(this.SharedPlacement); + return args; + } +}; +var IfcStructuralConnection = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedCondition = AppliedCondition; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedCondition = tape[ptr++]; + return new IfcStructuralConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedCondition); + return args; + } +}; +var IfcStructuralConnectionCondition = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcStructuralConnectionCondition(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcStructuralCurveAction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.DestabilizingLoad = DestabilizingLoad; + this.ProjectedOrTrue = ProjectedOrTrue; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let DestabilizingLoad = tape[ptr++]; + let ProjectedOrTrue = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStructuralCurveAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.DestabilizingLoad); + args.push(this.ProjectedOrTrue); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStructuralCurveConnection = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, Axis) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedCondition = AppliedCondition; + this.Axis = Axis; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedCondition = tape[ptr++]; + let Axis = tape[ptr++]; + return new IfcStructuralCurveConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, Axis); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedCondition); + args.push(this.Axis); + return args; + } +}; +var IfcStructuralCurveMember = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.PredefinedType = PredefinedType; + this.Axis = Axis; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Axis = tape[ptr++]; + return new IfcStructuralCurveMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.PredefinedType); + args.push(this.Axis); + return args; + } +}; +var IfcStructuralCurveMemberVarying = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.PredefinedType = PredefinedType; + this.Axis = Axis; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Axis = tape[ptr++]; + return new IfcStructuralCurveMemberVarying(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Axis); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.PredefinedType); + args.push(this.Axis); + return args; + } +}; +var IfcStructuralCurveReaction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStructuralCurveReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStructuralItem = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + return new IfcStructuralItem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + return args; + } +}; +var IfcStructuralLinearAction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.DestabilizingLoad = DestabilizingLoad; + this.ProjectedOrTrue = ProjectedOrTrue; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let DestabilizingLoad = tape[ptr++]; + let ProjectedOrTrue = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStructuralLinearAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.DestabilizingLoad); + args.push(this.ProjectedOrTrue); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStructuralLoad = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcStructuralLoad(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcStructuralLoadCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose, SelfWeightCoefficients) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.PredefinedType = PredefinedType; + this.ActionType = ActionType; + this.ActionSource = ActionSource; + this.Coefficient = Coefficient; + this.Purpose = Purpose; + this.SelfWeightCoefficients = SelfWeightCoefficients; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let ActionType = tape[ptr++]; + let ActionSource = tape[ptr++]; + let Coefficient = tape[ptr++]; + let Purpose = tape[ptr++]; + let SelfWeightCoefficients = tape[ptr++]; + return new IfcStructuralLoadCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose, SelfWeightCoefficients); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.PredefinedType); + args.push(this.ActionType); + args.push(this.ActionSource); + args.push(this.Coefficient); + args.push(this.Purpose); + args.push(this.SelfWeightCoefficients); + return args; + } +}; +var IfcStructuralLoadConfiguration = class { + constructor(expressID, type, Name, Values, Locations) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Values = Values; + this.Locations = Locations; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Values = tape[ptr++]; + let Locations = tape[ptr++]; + return new IfcStructuralLoadConfiguration(expressID, type, Name, Values, Locations); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Values); + args.push(this.Locations); + return args; + } +}; +var IfcStructuralLoadGroup = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.PredefinedType = PredefinedType; + this.ActionType = ActionType; + this.ActionSource = ActionSource; + this.Coefficient = Coefficient; + this.Purpose = Purpose; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let ActionType = tape[ptr++]; + let ActionSource = tape[ptr++]; + let Coefficient = tape[ptr++]; + let Purpose = tape[ptr++]; + return new IfcStructuralLoadGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, PredefinedType, ActionType, ActionSource, Coefficient, Purpose); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.PredefinedType); + args.push(this.ActionType); + args.push(this.ActionSource); + args.push(this.Coefficient); + args.push(this.Purpose); + return args; + } +}; +var IfcStructuralLoadLinearForce = class { + constructor(expressID, type, Name, LinearForceX, LinearForceY, LinearForceZ, LinearMomentX, LinearMomentY, LinearMomentZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.LinearForceX = LinearForceX; + this.LinearForceY = LinearForceY; + this.LinearForceZ = LinearForceZ; + this.LinearMomentX = LinearMomentX; + this.LinearMomentY = LinearMomentY; + this.LinearMomentZ = LinearMomentZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let LinearForceX = tape[ptr++]; + let LinearForceY = tape[ptr++]; + let LinearForceZ = tape[ptr++]; + let LinearMomentX = tape[ptr++]; + let LinearMomentY = tape[ptr++]; + let LinearMomentZ = tape[ptr++]; + return new IfcStructuralLoadLinearForce(expressID, type, Name, LinearForceX, LinearForceY, LinearForceZ, LinearMomentX, LinearMomentY, LinearMomentZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.LinearForceX); + args.push(this.LinearForceY); + args.push(this.LinearForceZ); + args.push(this.LinearMomentX); + args.push(this.LinearMomentY); + args.push(this.LinearMomentZ); + return args; + } +}; +var IfcStructuralLoadOrResult = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcStructuralLoadOrResult(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcStructuralLoadPlanarForce = class { + constructor(expressID, type, Name, PlanarForceX, PlanarForceY, PlanarForceZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.PlanarForceX = PlanarForceX; + this.PlanarForceY = PlanarForceY; + this.PlanarForceZ = PlanarForceZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let PlanarForceX = tape[ptr++]; + let PlanarForceY = tape[ptr++]; + let PlanarForceZ = tape[ptr++]; + return new IfcStructuralLoadPlanarForce(expressID, type, Name, PlanarForceX, PlanarForceY, PlanarForceZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.PlanarForceX); + args.push(this.PlanarForceY); + args.push(this.PlanarForceZ); + return args; + } +}; +var IfcStructuralLoadSingleDisplacement = class { + constructor(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DisplacementX = DisplacementX; + this.DisplacementY = DisplacementY; + this.DisplacementZ = DisplacementZ; + this.RotationalDisplacementRX = RotationalDisplacementRX; + this.RotationalDisplacementRY = RotationalDisplacementRY; + this.RotationalDisplacementRZ = RotationalDisplacementRZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DisplacementX = tape[ptr++]; + let DisplacementY = tape[ptr++]; + let DisplacementZ = tape[ptr++]; + let RotationalDisplacementRX = tape[ptr++]; + let RotationalDisplacementRY = tape[ptr++]; + let RotationalDisplacementRZ = tape[ptr++]; + return new IfcStructuralLoadSingleDisplacement(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DisplacementX); + args.push(this.DisplacementY); + args.push(this.DisplacementZ); + args.push(this.RotationalDisplacementRX); + args.push(this.RotationalDisplacementRY); + args.push(this.RotationalDisplacementRZ); + return args; + } +}; +var IfcStructuralLoadSingleDisplacementDistortion = class { + constructor(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ, Distortion) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DisplacementX = DisplacementX; + this.DisplacementY = DisplacementY; + this.DisplacementZ = DisplacementZ; + this.RotationalDisplacementRX = RotationalDisplacementRX; + this.RotationalDisplacementRY = RotationalDisplacementRY; + this.RotationalDisplacementRZ = RotationalDisplacementRZ; + this.Distortion = Distortion; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DisplacementX = tape[ptr++]; + let DisplacementY = tape[ptr++]; + let DisplacementZ = tape[ptr++]; + let RotationalDisplacementRX = tape[ptr++]; + let RotationalDisplacementRY = tape[ptr++]; + let RotationalDisplacementRZ = tape[ptr++]; + let Distortion = tape[ptr++]; + return new IfcStructuralLoadSingleDisplacementDistortion(expressID, type, Name, DisplacementX, DisplacementY, DisplacementZ, RotationalDisplacementRX, RotationalDisplacementRY, RotationalDisplacementRZ, Distortion); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DisplacementX); + args.push(this.DisplacementY); + args.push(this.DisplacementZ); + args.push(this.RotationalDisplacementRX); + args.push(this.RotationalDisplacementRY); + args.push(this.RotationalDisplacementRZ); + args.push(this.Distortion); + return args; + } +}; +var IfcStructuralLoadSingleForce = class { + constructor(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.ForceX = ForceX; + this.ForceY = ForceY; + this.ForceZ = ForceZ; + this.MomentX = MomentX; + this.MomentY = MomentY; + this.MomentZ = MomentZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let ForceX = tape[ptr++]; + let ForceY = tape[ptr++]; + let ForceZ = tape[ptr++]; + let MomentX = tape[ptr++]; + let MomentY = tape[ptr++]; + let MomentZ = tape[ptr++]; + return new IfcStructuralLoadSingleForce(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.ForceX); + args.push(this.ForceY); + args.push(this.ForceZ); + args.push(this.MomentX); + args.push(this.MomentY); + args.push(this.MomentZ); + return args; + } +}; +var IfcStructuralLoadSingleForceWarping = class { + constructor(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ, WarpingMoment) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.ForceX = ForceX; + this.ForceY = ForceY; + this.ForceZ = ForceZ; + this.MomentX = MomentX; + this.MomentY = MomentY; + this.MomentZ = MomentZ; + this.WarpingMoment = WarpingMoment; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let ForceX = tape[ptr++]; + let ForceY = tape[ptr++]; + let ForceZ = tape[ptr++]; + let MomentX = tape[ptr++]; + let MomentY = tape[ptr++]; + let MomentZ = tape[ptr++]; + let WarpingMoment = tape[ptr++]; + return new IfcStructuralLoadSingleForceWarping(expressID, type, Name, ForceX, ForceY, ForceZ, MomentX, MomentY, MomentZ, WarpingMoment); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.ForceX); + args.push(this.ForceY); + args.push(this.ForceZ); + args.push(this.MomentX); + args.push(this.MomentY); + args.push(this.MomentZ); + args.push(this.WarpingMoment); + return args; + } +}; +var IfcStructuralLoadStatic = class { + constructor(expressID, type, Name) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + return new IfcStructuralLoadStatic(expressID, type, Name); + } + ToTape() { + let args = []; + args.push(this.Name); + return args; + } +}; +var IfcStructuralLoadTemperature = class { + constructor(expressID, type, Name, DeltaTConstant, DeltaTY, DeltaTZ) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DeltaTConstant = DeltaTConstant; + this.DeltaTY = DeltaTY; + this.DeltaTZ = DeltaTZ; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DeltaTConstant = tape[ptr++]; + let DeltaTY = tape[ptr++]; + let DeltaTZ = tape[ptr++]; + return new IfcStructuralLoadTemperature(expressID, type, Name, DeltaTConstant, DeltaTY, DeltaTZ); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DeltaTConstant); + args.push(this.DeltaTY); + args.push(this.DeltaTZ); + return args; + } +}; +var IfcStructuralMember = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + return new IfcStructuralMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + return args; + } +}; +var IfcStructuralPlanarAction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.DestabilizingLoad = DestabilizingLoad; + this.ProjectedOrTrue = ProjectedOrTrue; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let DestabilizingLoad = tape[ptr++]; + let ProjectedOrTrue = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStructuralPlanarAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.DestabilizingLoad); + args.push(this.ProjectedOrTrue); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStructuralPointAction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.DestabilizingLoad = DestabilizingLoad; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let DestabilizingLoad = tape[ptr++]; + return new IfcStructuralPointAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.DestabilizingLoad); + return args; + } +}; +var IfcStructuralPointConnection = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, ConditionCoordinateSystem) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedCondition = AppliedCondition; + this.ConditionCoordinateSystem = ConditionCoordinateSystem; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedCondition = tape[ptr++]; + let ConditionCoordinateSystem = tape[ptr++]; + return new IfcStructuralPointConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition, ConditionCoordinateSystem); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedCondition); + args.push(this.ConditionCoordinateSystem); + return args; + } +}; +var IfcStructuralPointReaction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + return new IfcStructuralPointReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + return args; + } +}; +var IfcStructuralReaction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + return new IfcStructuralReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + return args; + } +}; +var IfcStructuralResultGroup = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheoryType, ResultForLoadGroup, IsLinear) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.TheoryType = TheoryType; + this.ResultForLoadGroup = ResultForLoadGroup; + this.IsLinear = IsLinear; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let TheoryType = tape[ptr++]; + let ResultForLoadGroup = tape[ptr++]; + let IsLinear = tape[ptr++]; + return new IfcStructuralResultGroup(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, TheoryType, ResultForLoadGroup, IsLinear); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.TheoryType); + args.push(this.ResultForLoadGroup); + args.push(this.IsLinear); + return args; + } +}; +var IfcStructuralSurfaceAction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.DestabilizingLoad = DestabilizingLoad; + this.ProjectedOrTrue = ProjectedOrTrue; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let DestabilizingLoad = tape[ptr++]; + let ProjectedOrTrue = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStructuralSurfaceAction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, DestabilizingLoad, ProjectedOrTrue, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.DestabilizingLoad); + args.push(this.ProjectedOrTrue); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStructuralSurfaceConnection = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedCondition = AppliedCondition; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedCondition = tape[ptr++]; + return new IfcStructuralSurfaceConnection(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedCondition); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedCondition); + return args; + } +}; +var IfcStructuralSurfaceMember = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.PredefinedType = PredefinedType; + this.Thickness = Thickness; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Thickness = tape[ptr++]; + return new IfcStructuralSurfaceMember(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.PredefinedType); + args.push(this.Thickness); + return args; + } +}; +var IfcStructuralSurfaceMemberVarying = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.PredefinedType = PredefinedType; + this.Thickness = Thickness; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let Thickness = tape[ptr++]; + return new IfcStructuralSurfaceMemberVarying(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, PredefinedType, Thickness); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.PredefinedType); + args.push(this.Thickness); + return args; + } +}; +var IfcStructuralSurfaceReaction = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.AppliedLoad = AppliedLoad; + this.GlobalOrLocal = GlobalOrLocal; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let AppliedLoad = tape[ptr++]; + let GlobalOrLocal = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcStructuralSurfaceReaction(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, AppliedLoad, GlobalOrLocal, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.AppliedLoad); + args.push(this.GlobalOrLocal); + args.push(this.PredefinedType); + return args; + } +}; +var IfcStyleModel = class { + constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { + this.expressID = expressID; + this.type = type; + this.ContextOfItems = ContextOfItems; + this.RepresentationIdentifier = RepresentationIdentifier; + this.RepresentationType = RepresentationType; + this.Items = Items; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextOfItems = tape[ptr++]; + let RepresentationIdentifier = tape[ptr++]; + let RepresentationType = tape[ptr++]; + let Items = tape[ptr++]; + return new IfcStyleModel(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); + } + ToTape() { + let args = []; + args.push(this.ContextOfItems); + args.push(this.RepresentationIdentifier); + args.push(this.RepresentationType); + args.push(this.Items); + return args; + } +}; +var IfcStyledItem = class { + constructor(expressID, type, Item, Styles, Name) { + this.expressID = expressID; + this.type = type; + this.Item = Item; + this.Styles = Styles; + this.Name = Name; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Item = tape[ptr++]; + let Styles = tape[ptr++]; + let Name = tape[ptr++]; + return new IfcStyledItem(expressID, type, Item, Styles, Name); + } + ToTape() { + let args = []; + args.push(this.Item); + args.push(this.Styles); + args.push(this.Name); + return args; + } +}; +var IfcStyledRepresentation = class { + constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { + this.expressID = expressID; + this.type = type; + this.ContextOfItems = ContextOfItems; + this.RepresentationIdentifier = RepresentationIdentifier; + this.RepresentationType = RepresentationType; + this.Items = Items; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextOfItems = tape[ptr++]; + let RepresentationIdentifier = tape[ptr++]; + let RepresentationType = tape[ptr++]; + let Items = tape[ptr++]; + return new IfcStyledRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); + } + ToTape() { + let args = []; + args.push(this.ContextOfItems); + args.push(this.RepresentationIdentifier); + args.push(this.RepresentationType); + args.push(this.Items); + return args; + } +}; +var IfcSubContractResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Usage = Usage; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Usage = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSubContractResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Usage, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Usage); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSubContractResourceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + this.BaseCosts = BaseCosts; + this.BaseQuantity = BaseQuantity; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + let BaseCosts = tape[ptr++]; + let BaseQuantity = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSubContractResourceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType, BaseCosts, BaseQuantity, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + args.push(this.BaseCosts); + args.push(this.BaseQuantity); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSubedge = class { + constructor(expressID, type, EdgeStart, EdgeEnd, ParentEdge) { + this.expressID = expressID; + this.type = type; + this.EdgeStart = EdgeStart; + this.EdgeEnd = EdgeEnd; + this.ParentEdge = ParentEdge; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let EdgeStart = tape[ptr++]; + let EdgeEnd = tape[ptr++]; + let ParentEdge = tape[ptr++]; + return new IfcSubedge(expressID, type, EdgeStart, EdgeEnd, ParentEdge); + } + ToTape() { + let args = []; + args.push(this.EdgeStart); + args.push(this.EdgeEnd); + args.push(this.ParentEdge); + return args; + } +}; +var IfcSurface = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcSurface(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcSurfaceCurve = class { + constructor(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation) { + this.expressID = expressID; + this.type = type; + this.Curve3D = Curve3D; + this.AssociatedGeometry = AssociatedGeometry; + this.MasterRepresentation = MasterRepresentation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Curve3D = tape[ptr++]; + let AssociatedGeometry = tape[ptr++]; + let MasterRepresentation = tape[ptr++]; + return new IfcSurfaceCurve(expressID, type, Curve3D, AssociatedGeometry, MasterRepresentation); + } + ToTape() { + let args = []; + args.push(this.Curve3D); + args.push(this.AssociatedGeometry); + args.push(this.MasterRepresentation); + return args; + } +}; +var IfcSurfaceCurveSweptAreaSolid = class { + constructor(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, ReferenceSurface) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + this.Directrix = Directrix; + this.StartParam = StartParam; + this.EndParam = EndParam; + this.ReferenceSurface = ReferenceSurface; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + let Directrix = tape[ptr++]; + let StartParam = tape[ptr++]; + let EndParam = tape[ptr++]; + let ReferenceSurface = tape[ptr++]; + return new IfcSurfaceCurveSweptAreaSolid(expressID, type, SweptArea, Position, Directrix, StartParam, EndParam, ReferenceSurface); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + args.push(this.Directrix); + args.push(this.StartParam); + args.push(this.EndParam); + args.push(this.ReferenceSurface); + return args; + } +}; +var IfcSurfaceFeature = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSurfaceFeature(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSurfaceOfLinearExtrusion = class { + constructor(expressID, type, SweptCurve, Position, ExtrudedDirection, Depth) { + this.expressID = expressID; + this.type = type; + this.SweptCurve = SweptCurve; + this.Position = Position; + this.ExtrudedDirection = ExtrudedDirection; + this.Depth = Depth; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptCurve = tape[ptr++]; + let Position = tape[ptr++]; + let ExtrudedDirection = tape[ptr++]; + let Depth = tape[ptr++]; + return new IfcSurfaceOfLinearExtrusion(expressID, type, SweptCurve, Position, ExtrudedDirection, Depth); + } + ToTape() { + let args = []; + args.push(this.SweptCurve); + args.push(this.Position); + args.push(this.ExtrudedDirection); + args.push(this.Depth); + return args; + } +}; +var IfcSurfaceOfRevolution = class { + constructor(expressID, type, SweptCurve, Position, AxisPosition) { + this.expressID = expressID; + this.type = type; + this.SweptCurve = SweptCurve; + this.Position = Position; + this.AxisPosition = AxisPosition; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptCurve = tape[ptr++]; + let Position = tape[ptr++]; + let AxisPosition = tape[ptr++]; + return new IfcSurfaceOfRevolution(expressID, type, SweptCurve, Position, AxisPosition); + } + ToTape() { + let args = []; + args.push(this.SweptCurve); + args.push(this.Position); + args.push(this.AxisPosition); + return args; + } +}; +var IfcSurfaceReinforcementArea = class { + constructor(expressID, type, Name, SurfaceReinforcement1, SurfaceReinforcement2, ShearReinforcement) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.SurfaceReinforcement1 = SurfaceReinforcement1; + this.SurfaceReinforcement2 = SurfaceReinforcement2; + this.ShearReinforcement = ShearReinforcement; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let SurfaceReinforcement1 = tape[ptr++]; + let SurfaceReinforcement2 = tape[ptr++]; + let ShearReinforcement = tape[ptr++]; + return new IfcSurfaceReinforcementArea(expressID, type, Name, SurfaceReinforcement1, SurfaceReinforcement2, ShearReinforcement); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.SurfaceReinforcement1); + args.push(this.SurfaceReinforcement2); + args.push(this.ShearReinforcement); + return args; + } +}; +var IfcSurfaceStyle = class { + constructor(expressID, type, Name, Side, Styles) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Side = Side; + this.Styles = Styles; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Side = tape[ptr++]; + let Styles = tape[ptr++]; + return new IfcSurfaceStyle(expressID, type, Name, Side, Styles); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Side); + args.push(this.Styles); + return args; + } +}; +var IfcSurfaceStyleLighting = class { + constructor(expressID, type, DiffuseTransmissionColour, DiffuseReflectionColour, TransmissionColour, ReflectanceColour) { + this.expressID = expressID; + this.type = type; + this.DiffuseTransmissionColour = DiffuseTransmissionColour; + this.DiffuseReflectionColour = DiffuseReflectionColour; + this.TransmissionColour = TransmissionColour; + this.ReflectanceColour = ReflectanceColour; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let DiffuseTransmissionColour = tape[ptr++]; + let DiffuseReflectionColour = tape[ptr++]; + let TransmissionColour = tape[ptr++]; + let ReflectanceColour = tape[ptr++]; + return new IfcSurfaceStyleLighting(expressID, type, DiffuseTransmissionColour, DiffuseReflectionColour, TransmissionColour, ReflectanceColour); + } + ToTape() { + let args = []; + args.push(this.DiffuseTransmissionColour); + args.push(this.DiffuseReflectionColour); + args.push(this.TransmissionColour); + args.push(this.ReflectanceColour); + return args; + } +}; +var IfcSurfaceStyleRefraction = class { + constructor(expressID, type, RefractionIndex, DispersionFactor) { + this.expressID = expressID; + this.type = type; + this.RefractionIndex = RefractionIndex; + this.DispersionFactor = DispersionFactor; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RefractionIndex = tape[ptr++]; + let DispersionFactor = tape[ptr++]; + return new IfcSurfaceStyleRefraction(expressID, type, RefractionIndex, DispersionFactor); + } + ToTape() { + let args = []; + args.push(this.RefractionIndex); + args.push(this.DispersionFactor); + return args; + } +}; +var IfcSurfaceStyleRendering = class { + constructor(expressID, type, SurfaceColour, Transparency, DiffuseColour, TransmissionColour, DiffuseTransmissionColour, ReflectionColour, SpecularColour, SpecularHighlight, ReflectanceMethod) { + this.expressID = expressID; + this.type = type; + this.SurfaceColour = SurfaceColour; + this.Transparency = Transparency; + this.DiffuseColour = DiffuseColour; + this.TransmissionColour = TransmissionColour; + this.DiffuseTransmissionColour = DiffuseTransmissionColour; + this.ReflectionColour = ReflectionColour; + this.SpecularColour = SpecularColour; + this.SpecularHighlight = SpecularHighlight; + this.ReflectanceMethod = ReflectanceMethod; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SurfaceColour = tape[ptr++]; + let Transparency = tape[ptr++]; + let DiffuseColour = tape[ptr++]; + let TransmissionColour = tape[ptr++]; + let DiffuseTransmissionColour = tape[ptr++]; + let ReflectionColour = tape[ptr++]; + let SpecularColour = tape[ptr++]; + let SpecularHighlight = tape[ptr++]; + let ReflectanceMethod = tape[ptr++]; + return new IfcSurfaceStyleRendering(expressID, type, SurfaceColour, Transparency, DiffuseColour, TransmissionColour, DiffuseTransmissionColour, ReflectionColour, SpecularColour, SpecularHighlight, ReflectanceMethod); + } + ToTape() { + let args = []; + args.push(this.SurfaceColour); + args.push(this.Transparency); + args.push(this.DiffuseColour); + args.push(this.TransmissionColour); + args.push(this.DiffuseTransmissionColour); + args.push(this.ReflectionColour); + args.push(this.SpecularColour); + args.push(this.SpecularHighlight); + args.push(this.ReflectanceMethod); + return args; + } +}; +var IfcSurfaceStyleShading = class { + constructor(expressID, type, SurfaceColour, Transparency) { + this.expressID = expressID; + this.type = type; + this.SurfaceColour = SurfaceColour; + this.Transparency = Transparency; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SurfaceColour = tape[ptr++]; + let Transparency = tape[ptr++]; + return new IfcSurfaceStyleShading(expressID, type, SurfaceColour, Transparency); + } + ToTape() { + let args = []; + args.push(this.SurfaceColour); + args.push(this.Transparency); + return args; + } +}; +var IfcSurfaceStyleWithTextures = class { + constructor(expressID, type, Textures) { + this.expressID = expressID; + this.type = type; + this.Textures = Textures; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Textures = tape[ptr++]; + return new IfcSurfaceStyleWithTextures(expressID, type, Textures); + } + ToTape() { + let args = []; + args.push(this.Textures); + return args; + } +}; +var IfcSurfaceTexture = class { + constructor(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter) { + this.expressID = expressID; + this.type = type; + this.RepeatS = RepeatS; + this.RepeatT = RepeatT; + this.Mode = Mode; + this.TextureTransform = TextureTransform; + this.Parameter = Parameter; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RepeatS = tape[ptr++]; + let RepeatT = tape[ptr++]; + let Mode = tape[ptr++]; + let TextureTransform = tape[ptr++]; + let Parameter = tape[ptr++]; + return new IfcSurfaceTexture(expressID, type, RepeatS, RepeatT, Mode, TextureTransform, Parameter); + } + ToTape() { + let args = []; + args.push(this.RepeatS); + args.push(this.RepeatT); + args.push(this.Mode); + args.push(this.TextureTransform); + args.push(this.Parameter); + return args; + } +}; +var IfcSweptAreaSolid = class { + constructor(expressID, type, SweptArea, Position) { + this.expressID = expressID; + this.type = type; + this.SweptArea = SweptArea; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptArea = tape[ptr++]; + let Position = tape[ptr++]; + return new IfcSweptAreaSolid(expressID, type, SweptArea, Position); + } + ToTape() { + let args = []; + args.push(this.SweptArea); + args.push(this.Position); + return args; + } +}; +var IfcSweptDiskSolid = class { + constructor(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam) { + this.expressID = expressID; + this.type = type; + this.Directrix = Directrix; + this.Radius = Radius; + this.InnerRadius = InnerRadius; + this.StartParam = StartParam; + this.EndParam = EndParam; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Directrix = tape[ptr++]; + let Radius = tape[ptr++]; + let InnerRadius = tape[ptr++]; + let StartParam = tape[ptr++]; + let EndParam = tape[ptr++]; + return new IfcSweptDiskSolid(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam); + } + ToTape() { + let args = []; + args.push(this.Directrix); + args.push(this.Radius); + args.push(this.InnerRadius); + args.push(this.StartParam); + args.push(this.EndParam); + return args; + } +}; +var IfcSweptDiskSolidPolygonal = class { + constructor(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam, FilletRadius) { + this.expressID = expressID; + this.type = type; + this.Directrix = Directrix; + this.Radius = Radius; + this.InnerRadius = InnerRadius; + this.StartParam = StartParam; + this.EndParam = EndParam; + this.FilletRadius = FilletRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Directrix = tape[ptr++]; + let Radius = tape[ptr++]; + let InnerRadius = tape[ptr++]; + let StartParam = tape[ptr++]; + let EndParam = tape[ptr++]; + let FilletRadius = tape[ptr++]; + return new IfcSweptDiskSolidPolygonal(expressID, type, Directrix, Radius, InnerRadius, StartParam, EndParam, FilletRadius); + } + ToTape() { + let args = []; + args.push(this.Directrix); + args.push(this.Radius); + args.push(this.InnerRadius); + args.push(this.StartParam); + args.push(this.EndParam); + args.push(this.FilletRadius); + return args; + } +}; +var IfcSweptSurface = class { + constructor(expressID, type, SweptCurve, Position) { + this.expressID = expressID; + this.type = type; + this.SweptCurve = SweptCurve; + this.Position = Position; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let SweptCurve = tape[ptr++]; + let Position = tape[ptr++]; + return new IfcSweptSurface(expressID, type, SweptCurve, Position); + } + ToTape() { + let args = []; + args.push(this.SweptCurve); + args.push(this.Position); + return args; + } +}; +var IfcSwitchingDevice = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSwitchingDevice(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSwitchingDeviceType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSwitchingDeviceType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSystem = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + return new IfcSystem(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + return args; + } +}; +var IfcSystemFurnitureElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSystemFurnitureElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcSystemFurnitureElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcSystemFurnitureElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, WebEdgeRadius, WebSlope, FlangeSlope) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Depth = Depth; + this.FlangeWidth = FlangeWidth; + this.WebThickness = WebThickness; + this.FlangeThickness = FlangeThickness; + this.FilletRadius = FilletRadius; + this.FlangeEdgeRadius = FlangeEdgeRadius; + this.WebEdgeRadius = WebEdgeRadius; + this.WebSlope = WebSlope; + this.FlangeSlope = FlangeSlope; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Depth = tape[ptr++]; + let FlangeWidth = tape[ptr++]; + let WebThickness = tape[ptr++]; + let FlangeThickness = tape[ptr++]; + let FilletRadius = tape[ptr++]; + let FlangeEdgeRadius = tape[ptr++]; + let WebEdgeRadius = tape[ptr++]; + let WebSlope = tape[ptr++]; + let FlangeSlope = tape[ptr++]; + return new IfcTShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, FlangeEdgeRadius, WebEdgeRadius, WebSlope, FlangeSlope); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Depth); + args.push(this.FlangeWidth); + args.push(this.WebThickness); + args.push(this.FlangeThickness); + args.push(this.FilletRadius); + args.push(this.FlangeEdgeRadius); + args.push(this.WebEdgeRadius); + args.push(this.WebSlope); + args.push(this.FlangeSlope); + return args; + } +}; +var IfcTable = class { + constructor(expressID, type, Name, Rows, Columns) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Rows = Rows; + this.Columns = Columns; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Rows = tape[ptr++]; + let Columns = tape[ptr++]; + return new IfcTable(expressID, type, Name, Rows, Columns); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Rows); + args.push(this.Columns); + return args; + } +}; +var IfcTableColumn = class { + constructor(expressID, type, Identifier, Name, Description, Unit, ReferencePath) { + this.expressID = expressID; + this.type = type; + this.Identifier = Identifier; + this.Name = Name; + this.Description = Description; + this.Unit = Unit; + this.ReferencePath = ReferencePath; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Identifier = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let Unit = tape[ptr++]; + let ReferencePath = tape[ptr++]; + return new IfcTableColumn(expressID, type, Identifier, Name, Description, Unit, ReferencePath); + } + ToTape() { + let args = []; + args.push(this.Identifier); + args.push(this.Name); + args.push(this.Description); + args.push(this.Unit); + args.push(this.ReferencePath); + return args; + } +}; +var IfcTableRow = class { + constructor(expressID, type, RowCells, IsHeading) { + this.expressID = expressID; + this.type = type; + this.RowCells = RowCells; + this.IsHeading = IsHeading; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let RowCells = tape[ptr++]; + let IsHeading = tape[ptr++]; + return new IfcTableRow(expressID, type, RowCells, IsHeading); + } + ToTape() { + let args = []; + args.push(this.RowCells); + args.push(this.IsHeading); + return args; + } +}; +var IfcTank = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTank(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTankType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTankType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTask = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Status, WorkMethod, IsMilestone, Priority, TaskTime, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.Status = Status; + this.WorkMethod = WorkMethod; + this.IsMilestone = IsMilestone; + this.Priority = Priority; + this.TaskTime = TaskTime; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let Status = tape[ptr++]; + let WorkMethod = tape[ptr++]; + let IsMilestone = tape[ptr++]; + let Priority = tape[ptr++]; + let TaskTime = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTask(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, LongDescription, Status, WorkMethod, IsMilestone, Priority, TaskTime, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.Status); + args.push(this.WorkMethod); + args.push(this.IsMilestone); + args.push(this.Priority); + args.push(this.TaskTime); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTaskTime = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.DurationType = DurationType; + this.ScheduleDuration = ScheduleDuration; + this.ScheduleStart = ScheduleStart; + this.ScheduleFinish = ScheduleFinish; + this.EarlyStart = EarlyStart; + this.EarlyFinish = EarlyFinish; + this.LateStart = LateStart; + this.LateFinish = LateFinish; + this.FreeFloat = FreeFloat; + this.TotalFloat = TotalFloat; + this.IsCritical = IsCritical; + this.StatusTime = StatusTime; + this.ActualDuration = ActualDuration; + this.ActualStart = ActualStart; + this.ActualFinish = ActualFinish; + this.RemainingTime = RemainingTime; + this.Completion = Completion; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let DurationType = tape[ptr++]; + let ScheduleDuration = tape[ptr++]; + let ScheduleStart = tape[ptr++]; + let ScheduleFinish = tape[ptr++]; + let EarlyStart = tape[ptr++]; + let EarlyFinish = tape[ptr++]; + let LateStart = tape[ptr++]; + let LateFinish = tape[ptr++]; + let FreeFloat = tape[ptr++]; + let TotalFloat = tape[ptr++]; + let IsCritical = tape[ptr++]; + let StatusTime = tape[ptr++]; + let ActualDuration = tape[ptr++]; + let ActualStart = tape[ptr++]; + let ActualFinish = tape[ptr++]; + let RemainingTime = tape[ptr++]; + let Completion = tape[ptr++]; + return new IfcTaskTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.DurationType); + args.push(this.ScheduleDuration); + args.push(this.ScheduleStart); + args.push(this.ScheduleFinish); + args.push(this.EarlyStart); + args.push(this.EarlyFinish); + args.push(this.LateStart); + args.push(this.LateFinish); + args.push(this.FreeFloat); + args.push(this.TotalFloat); + args.push(this.IsCritical); + args.push(this.StatusTime); + args.push(this.ActualDuration); + args.push(this.ActualStart); + args.push(this.ActualFinish); + args.push(this.RemainingTime); + args.push(this.Completion); + return args; + } +}; +var IfcTaskTimeRecurring = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion, Recurrence) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.DurationType = DurationType; + this.ScheduleDuration = ScheduleDuration; + this.ScheduleStart = ScheduleStart; + this.ScheduleFinish = ScheduleFinish; + this.EarlyStart = EarlyStart; + this.EarlyFinish = EarlyFinish; + this.LateStart = LateStart; + this.LateFinish = LateFinish; + this.FreeFloat = FreeFloat; + this.TotalFloat = TotalFloat; + this.IsCritical = IsCritical; + this.StatusTime = StatusTime; + this.ActualDuration = ActualDuration; + this.ActualStart = ActualStart; + this.ActualFinish = ActualFinish; + this.RemainingTime = RemainingTime; + this.Completion = Completion; + this.Recurrence = Recurrence; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let DurationType = tape[ptr++]; + let ScheduleDuration = tape[ptr++]; + let ScheduleStart = tape[ptr++]; + let ScheduleFinish = tape[ptr++]; + let EarlyStart = tape[ptr++]; + let EarlyFinish = tape[ptr++]; + let LateStart = tape[ptr++]; + let LateFinish = tape[ptr++]; + let FreeFloat = tape[ptr++]; + let TotalFloat = tape[ptr++]; + let IsCritical = tape[ptr++]; + let StatusTime = tape[ptr++]; + let ActualDuration = tape[ptr++]; + let ActualStart = tape[ptr++]; + let ActualFinish = tape[ptr++]; + let RemainingTime = tape[ptr++]; + let Completion = tape[ptr++]; + let Recurrence = tape[ptr++]; + return new IfcTaskTimeRecurring(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, DurationType, ScheduleDuration, ScheduleStart, ScheduleFinish, EarlyStart, EarlyFinish, LateStart, LateFinish, FreeFloat, TotalFloat, IsCritical, StatusTime, ActualDuration, ActualStart, ActualFinish, RemainingTime, Completion, Recurrence); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.DurationType); + args.push(this.ScheduleDuration); + args.push(this.ScheduleStart); + args.push(this.ScheduleFinish); + args.push(this.EarlyStart); + args.push(this.EarlyFinish); + args.push(this.LateStart); + args.push(this.LateFinish); + args.push(this.FreeFloat); + args.push(this.TotalFloat); + args.push(this.IsCritical); + args.push(this.StatusTime); + args.push(this.ActualDuration); + args.push(this.ActualStart); + args.push(this.ActualFinish); + args.push(this.RemainingTime); + args.push(this.Completion); + args.push(this.Recurrence); + return args; + } +}; +var IfcTaskType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, WorkMethod) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ProcessType = ProcessType; + this.PredefinedType = PredefinedType; + this.WorkMethod = WorkMethod; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ProcessType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let WorkMethod = tape[ptr++]; + return new IfcTaskType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType, PredefinedType, WorkMethod); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ProcessType); + args.push(this.PredefinedType); + args.push(this.WorkMethod); + return args; + } +}; +var IfcTelecomAddress = class { + constructor(expressID, type, Purpose, Description, UserDefinedPurpose, TelephoneNumbers, FacsimileNumbers, PagerNumber, ElectronicMailAddresses, WWWHomePageURL, MessagingIDs) { + this.expressID = expressID; + this.type = type; + this.Purpose = Purpose; + this.Description = Description; + this.UserDefinedPurpose = UserDefinedPurpose; + this.TelephoneNumbers = TelephoneNumbers; + this.FacsimileNumbers = FacsimileNumbers; + this.PagerNumber = PagerNumber; + this.ElectronicMailAddresses = ElectronicMailAddresses; + this.WWWHomePageURL = WWWHomePageURL; + this.MessagingIDs = MessagingIDs; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Purpose = tape[ptr++]; + let Description = tape[ptr++]; + let UserDefinedPurpose = tape[ptr++]; + let TelephoneNumbers = tape[ptr++]; + let FacsimileNumbers = tape[ptr++]; + let PagerNumber = tape[ptr++]; + let ElectronicMailAddresses = tape[ptr++]; + let WWWHomePageURL = tape[ptr++]; + let MessagingIDs = tape[ptr++]; + return new IfcTelecomAddress(expressID, type, Purpose, Description, UserDefinedPurpose, TelephoneNumbers, FacsimileNumbers, PagerNumber, ElectronicMailAddresses, WWWHomePageURL, MessagingIDs); + } + ToTape() { + let args = []; + args.push(this.Purpose); + args.push(this.Description); + args.push(this.UserDefinedPurpose); + args.push(this.TelephoneNumbers); + args.push(this.FacsimileNumbers); + args.push(this.PagerNumber); + args.push(this.ElectronicMailAddresses); + args.push(this.WWWHomePageURL); + args.push(this.MessagingIDs); + return args; + } +}; +var IfcTendon = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType, NominalDiameter, CrossSectionArea, TensionForce, PreStress, FrictionCoefficient, AnchorageSlip, MinCurvatureRadius) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.SteelGrade = SteelGrade; + this.PredefinedType = PredefinedType; + this.NominalDiameter = NominalDiameter; + this.CrossSectionArea = CrossSectionArea; + this.TensionForce = TensionForce; + this.PreStress = PreStress; + this.FrictionCoefficient = FrictionCoefficient; + this.AnchorageSlip = AnchorageSlip; + this.MinCurvatureRadius = MinCurvatureRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let SteelGrade = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let NominalDiameter = tape[ptr++]; + let CrossSectionArea = tape[ptr++]; + let TensionForce = tape[ptr++]; + let PreStress = tape[ptr++]; + let FrictionCoefficient = tape[ptr++]; + let AnchorageSlip = tape[ptr++]; + let MinCurvatureRadius = tape[ptr++]; + return new IfcTendon(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType, NominalDiameter, CrossSectionArea, TensionForce, PreStress, FrictionCoefficient, AnchorageSlip, MinCurvatureRadius); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.SteelGrade); + args.push(this.PredefinedType); + args.push(this.NominalDiameter); + args.push(this.CrossSectionArea); + args.push(this.TensionForce); + args.push(this.PreStress); + args.push(this.FrictionCoefficient); + args.push(this.AnchorageSlip); + args.push(this.MinCurvatureRadius); + return args; + } +}; +var IfcTendonAnchor = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.SteelGrade = SteelGrade; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let SteelGrade = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTendonAnchor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.SteelGrade); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTendonAnchorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTendonAnchorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTendonConduit = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.SteelGrade = SteelGrade; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let SteelGrade = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTendonConduit(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, SteelGrade, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.SteelGrade); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTendonConduitType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTendonConduitType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTendonType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, SheathDiameter) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.NominalDiameter = NominalDiameter; + this.CrossSectionArea = CrossSectionArea; + this.SheathDiameter = SheathDiameter; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let NominalDiameter = tape[ptr++]; + let CrossSectionArea = tape[ptr++]; + let SheathDiameter = tape[ptr++]; + return new IfcTendonType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, NominalDiameter, CrossSectionArea, SheathDiameter); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.NominalDiameter); + args.push(this.CrossSectionArea); + args.push(this.SheathDiameter); + return args; + } +}; +var IfcTessellatedFaceSet = class { + constructor(expressID, type, Coordinates) { + this.expressID = expressID; + this.type = type; + this.Coordinates = Coordinates; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Coordinates = tape[ptr++]; + return new IfcTessellatedFaceSet(expressID, type, Coordinates); + } + ToTape() { + let args = []; + args.push(this.Coordinates); + return args; + } +}; +var IfcTessellatedItem = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcTessellatedItem(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcTextLiteral = class { + constructor(expressID, type, Literal, Placement, Path) { + this.expressID = expressID; + this.type = type; + this.Literal = Literal; + this.Placement = Placement; + this.Path = Path; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Literal = tape[ptr++]; + let Placement = tape[ptr++]; + let Path = tape[ptr++]; + return new IfcTextLiteral(expressID, type, Literal, Placement, Path); + } + ToTape() { + let args = []; + args.push(this.Literal); + args.push(this.Placement); + args.push(this.Path); + return args; + } +}; +var IfcTextLiteralWithExtent = class { + constructor(expressID, type, Literal, Placement, Path, Extent, BoxAlignment) { + this.expressID = expressID; + this.type = type; + this.Literal = Literal; + this.Placement = Placement; + this.Path = Path; + this.Extent = Extent; + this.BoxAlignment = BoxAlignment; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Literal = tape[ptr++]; + let Placement = tape[ptr++]; + let Path = tape[ptr++]; + let Extent = tape[ptr++]; + let BoxAlignment = tape[ptr++]; + return new IfcTextLiteralWithExtent(expressID, type, Literal, Placement, Path, Extent, BoxAlignment); + } + ToTape() { + let args = []; + args.push(this.Literal); + args.push(this.Placement); + args.push(this.Path); + args.push(this.Extent); + args.push(this.BoxAlignment); + return args; + } +}; +var IfcTextStyle = class { + constructor(expressID, type, Name, TextCharacterAppearance, TextStyle, TextFontStyle, ModelOrDraughting) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.TextCharacterAppearance = TextCharacterAppearance; + this.TextStyle = TextStyle; + this.TextFontStyle = TextFontStyle; + this.ModelOrDraughting = ModelOrDraughting; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let TextCharacterAppearance = tape[ptr++]; + let TextStyle = tape[ptr++]; + let TextFontStyle = tape[ptr++]; + let ModelOrDraughting = tape[ptr++]; + return new IfcTextStyle(expressID, type, Name, TextCharacterAppearance, TextStyle, TextFontStyle, ModelOrDraughting); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.TextCharacterAppearance); + args.push(this.TextStyle); + args.push(this.TextFontStyle); + args.push(this.ModelOrDraughting); + return args; + } +}; +var IfcTextStyleFontModel = class { + constructor(expressID, type, Name, FontFamily, FontStyle, FontVariant, FontWeight, FontSize) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.FontFamily = FontFamily; + this.FontStyle = FontStyle; + this.FontVariant = FontVariant; + this.FontWeight = FontWeight; + this.FontSize = FontSize; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let FontFamily = tape[ptr++]; + let FontStyle = tape[ptr++]; + let FontVariant = tape[ptr++]; + let FontWeight = tape[ptr++]; + let FontSize = tape[ptr++]; + return new IfcTextStyleFontModel(expressID, type, Name, FontFamily, FontStyle, FontVariant, FontWeight, FontSize); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.FontFamily); + args.push(this.FontStyle); + args.push(this.FontVariant); + args.push(this.FontWeight); + args.push(this.FontSize); + return args; + } +}; +var IfcTextStyleForDefinedFont = class { + constructor(expressID, type, Colour, BackgroundColour) { + this.expressID = expressID; + this.type = type; + this.Colour = Colour; + this.BackgroundColour = BackgroundColour; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Colour = tape[ptr++]; + let BackgroundColour = tape[ptr++]; + return new IfcTextStyleForDefinedFont(expressID, type, Colour, BackgroundColour); + } + ToTape() { + let args = []; + args.push(this.Colour); + args.push(this.BackgroundColour); + return args; + } +}; +var IfcTextStyleTextModel = class { + constructor(expressID, type, TextIndent, TextAlign, TextDecoration, LetterSpacing, WordSpacing, TextTransform, LineHeight) { + this.expressID = expressID; + this.type = type; + this.TextIndent = TextIndent; + this.TextAlign = TextAlign; + this.TextDecoration = TextDecoration; + this.LetterSpacing = LetterSpacing; + this.WordSpacing = WordSpacing; + this.TextTransform = TextTransform; + this.LineHeight = LineHeight; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TextIndent = tape[ptr++]; + let TextAlign = tape[ptr++]; + let TextDecoration = tape[ptr++]; + let LetterSpacing = tape[ptr++]; + let WordSpacing = tape[ptr++]; + let TextTransform = tape[ptr++]; + let LineHeight = tape[ptr++]; + return new IfcTextStyleTextModel(expressID, type, TextIndent, TextAlign, TextDecoration, LetterSpacing, WordSpacing, TextTransform, LineHeight); + } + ToTape() { + let args = []; + args.push(this.TextIndent); + args.push(this.TextAlign); + args.push(this.TextDecoration); + args.push(this.LetterSpacing); + args.push(this.WordSpacing); + args.push(this.TextTransform); + args.push(this.LineHeight); + return args; + } +}; +var IfcTextureCoordinate = class { + constructor(expressID, type, Maps) { + this.expressID = expressID; + this.type = type; + this.Maps = Maps; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Maps = tape[ptr++]; + return new IfcTextureCoordinate(expressID, type, Maps); + } + ToTape() { + let args = []; + args.push(this.Maps); + return args; + } +}; +var IfcTextureCoordinateGenerator = class { + constructor(expressID, type, Maps, Mode, Parameter) { + this.expressID = expressID; + this.type = type; + this.Maps = Maps; + this.Mode = Mode; + this.Parameter = Parameter; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Maps = tape[ptr++]; + let Mode = tape[ptr++]; + let Parameter = tape[ptr++]; + return new IfcTextureCoordinateGenerator(expressID, type, Maps, Mode, Parameter); + } + ToTape() { + let args = []; + args.push(this.Maps); + args.push(this.Mode); + args.push(this.Parameter); + return args; + } +}; +var IfcTextureMap = class { + constructor(expressID, type, Maps, Vertices, MappedTo) { + this.expressID = expressID; + this.type = type; + this.Maps = Maps; + this.Vertices = Vertices; + this.MappedTo = MappedTo; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Maps = tape[ptr++]; + let Vertices = tape[ptr++]; + let MappedTo = tape[ptr++]; + return new IfcTextureMap(expressID, type, Maps, Vertices, MappedTo); + } + ToTape() { + let args = []; + args.push(this.Maps); + args.push(this.Vertices); + args.push(this.MappedTo); + return args; + } +}; +var IfcTextureVertex = class { + constructor(expressID, type, Coordinates) { + this.expressID = expressID; + this.type = type; + this.Coordinates = Coordinates; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Coordinates = tape[ptr++]; + return new IfcTextureVertex(expressID, type, Coordinates); + } + ToTape() { + let args = []; + args.push(this.Coordinates); + return args; + } +}; +var IfcTextureVertexList = class { + constructor(expressID, type, TexCoordsList) { + this.expressID = expressID; + this.type = type; + this.TexCoordsList = TexCoordsList; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let TexCoordsList = tape[ptr++]; + return new IfcTextureVertexList(expressID, type, TexCoordsList); + } + ToTape() { + let args = []; + args.push(this.TexCoordsList); + return args; + } +}; +var IfcTimePeriod = class { + constructor(expressID, type, StartTime, EndTime) { + this.expressID = expressID; + this.type = type; + this.StartTime = StartTime; + this.EndTime = EndTime; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let StartTime = tape[ptr++]; + let EndTime = tape[ptr++]; + return new IfcTimePeriod(expressID, type, StartTime, EndTime); + } + ToTape() { + let args = []; + args.push(this.StartTime); + args.push(this.EndTime); + return args; + } +}; +var IfcTimeSeries = class { + constructor(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.Description = Description; + this.StartTime = StartTime; + this.EndTime = EndTime; + this.TimeSeriesDataType = TimeSeriesDataType; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.Unit = Unit; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let StartTime = tape[ptr++]; + let EndTime = tape[ptr++]; + let TimeSeriesDataType = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let Unit = tape[ptr++]; + return new IfcTimeSeries(expressID, type, Name, Description, StartTime, EndTime, TimeSeriesDataType, DataOrigin, UserDefinedDataOrigin, Unit); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.Description); + args.push(this.StartTime); + args.push(this.EndTime); + args.push(this.TimeSeriesDataType); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.Unit); + return args; + } +}; +var IfcTimeSeriesValue = class { + constructor(expressID, type, ListValues) { + this.expressID = expressID; + this.type = type; + this.ListValues = ListValues; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ListValues = tape[ptr++]; + return new IfcTimeSeriesValue(expressID, type, ListValues); + } + ToTape() { + let args = []; + args.push(this.ListValues); + return args; + } +}; +var IfcTopologicalRepresentationItem = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcTopologicalRepresentationItem(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcTopologyRepresentation = class { + constructor(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items) { + this.expressID = expressID; + this.type = type; + this.ContextOfItems = ContextOfItems; + this.RepresentationIdentifier = RepresentationIdentifier; + this.RepresentationType = RepresentationType; + this.Items = Items; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ContextOfItems = tape[ptr++]; + let RepresentationIdentifier = tape[ptr++]; + let RepresentationType = tape[ptr++]; + let Items = tape[ptr++]; + return new IfcTopologyRepresentation(expressID, type, ContextOfItems, RepresentationIdentifier, RepresentationType, Items); + } + ToTape() { + let args = []; + args.push(this.ContextOfItems); + args.push(this.RepresentationIdentifier); + args.push(this.RepresentationType); + args.push(this.Items); + return args; + } +}; +var IfcToroidalSurface = class { + constructor(expressID, type, Position, MajorRadius, MinorRadius) { + this.expressID = expressID; + this.type = type; + this.Position = Position; + this.MajorRadius = MajorRadius; + this.MinorRadius = MinorRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Position = tape[ptr++]; + let MajorRadius = tape[ptr++]; + let MinorRadius = tape[ptr++]; + return new IfcToroidalSurface(expressID, type, Position, MajorRadius, MinorRadius); + } + ToTape() { + let args = []; + args.push(this.Position); + args.push(this.MajorRadius); + args.push(this.MinorRadius); + return args; + } +}; +var IfcTransformer = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTransformer(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTransformerType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTransformerType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTransitionCurveSegment2D = class { + constructor(expressID, type, StartPoint, StartDirection, SegmentLength, StartRadius, EndRadius, IsStartRadiusCCW, IsEndRadiusCCW, TransitionCurveType) { + this.expressID = expressID; + this.type = type; + this.StartPoint = StartPoint; + this.StartDirection = StartDirection; + this.SegmentLength = SegmentLength; + this.StartRadius = StartRadius; + this.EndRadius = EndRadius; + this.IsStartRadiusCCW = IsStartRadiusCCW; + this.IsEndRadiusCCW = IsEndRadiusCCW; + this.TransitionCurveType = TransitionCurveType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let StartPoint = tape[ptr++]; + let StartDirection = tape[ptr++]; + let SegmentLength = tape[ptr++]; + let StartRadius = tape[ptr++]; + let EndRadius = tape[ptr++]; + let IsStartRadiusCCW = tape[ptr++]; + let IsEndRadiusCCW = tape[ptr++]; + let TransitionCurveType = tape[ptr++]; + return new IfcTransitionCurveSegment2D(expressID, type, StartPoint, StartDirection, SegmentLength, StartRadius, EndRadius, IsStartRadiusCCW, IsEndRadiusCCW, TransitionCurveType); + } + ToTape() { + let args = []; + args.push(this.StartPoint); + args.push(this.StartDirection); + args.push(this.SegmentLength); + args.push(this.StartRadius); + args.push(this.EndRadius); + args.push(this.IsStartRadiusCCW); + args.push(this.IsEndRadiusCCW); + args.push(this.TransitionCurveType); + return args; + } +}; +var IfcTransportElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTransportElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTransportElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTransportElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTrapeziumProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, BottomXDim, TopXDim, YDim, TopXOffset) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.BottomXDim = BottomXDim; + this.TopXDim = TopXDim; + this.YDim = YDim; + this.TopXOffset = TopXOffset; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let BottomXDim = tape[ptr++]; + let TopXDim = tape[ptr++]; + let YDim = tape[ptr++]; + let TopXOffset = tape[ptr++]; + return new IfcTrapeziumProfileDef(expressID, type, ProfileType, ProfileName, Position, BottomXDim, TopXDim, YDim, TopXOffset); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.BottomXDim); + args.push(this.TopXDim); + args.push(this.YDim); + args.push(this.TopXOffset); + return args; + } +}; +var IfcTriangulatedFaceSet = class { + constructor(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex) { + this.expressID = expressID; + this.type = type; + this.Coordinates = Coordinates; + this.Normals = Normals; + this.Closed = Closed; + this.CoordIndex = CoordIndex; + this.PnIndex = PnIndex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Coordinates = tape[ptr++]; + let Normals = tape[ptr++]; + let Closed = tape[ptr++]; + let CoordIndex = tape[ptr++]; + let PnIndex = tape[ptr++]; + return new IfcTriangulatedFaceSet(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex); + } + ToTape() { + let args = []; + args.push(this.Coordinates); + args.push(this.Normals); + args.push(this.Closed); + args.push(this.CoordIndex); + args.push(this.PnIndex); + return args; + } +}; +var IfcTriangulatedIrregularNetwork = class { + constructor(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex, Flags) { + this.expressID = expressID; + this.type = type; + this.Coordinates = Coordinates; + this.Normals = Normals; + this.Closed = Closed; + this.CoordIndex = CoordIndex; + this.PnIndex = PnIndex; + this.Flags = Flags; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Coordinates = tape[ptr++]; + let Normals = tape[ptr++]; + let Closed = tape[ptr++]; + let CoordIndex = tape[ptr++]; + let PnIndex = tape[ptr++]; + let Flags = tape[ptr++]; + return new IfcTriangulatedIrregularNetwork(expressID, type, Coordinates, Normals, Closed, CoordIndex, PnIndex, Flags); + } + ToTape() { + let args = []; + args.push(this.Coordinates); + args.push(this.Normals); + args.push(this.Closed); + args.push(this.CoordIndex); + args.push(this.PnIndex); + args.push(this.Flags); + return args; + } +}; +var IfcTrimmedCurve = class { + constructor(expressID, type, BasisCurve, Trim1, Trim2, SenseAgreement, MasterRepresentation) { + this.expressID = expressID; + this.type = type; + this.BasisCurve = BasisCurve; + this.Trim1 = Trim1; + this.Trim2 = Trim2; + this.SenseAgreement = SenseAgreement; + this.MasterRepresentation = MasterRepresentation; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let BasisCurve = tape[ptr++]; + let Trim1 = tape[ptr++]; + let Trim2 = tape[ptr++]; + let SenseAgreement = tape[ptr++]; + let MasterRepresentation = tape[ptr++]; + return new IfcTrimmedCurve(expressID, type, BasisCurve, Trim1, Trim2, SenseAgreement, MasterRepresentation); + } + ToTape() { + let args = []; + args.push(this.BasisCurve); + args.push(this.Trim1); + args.push(this.Trim2); + args.push(this.SenseAgreement); + args.push(this.MasterRepresentation); + return args; + } +}; +var IfcTubeBundle = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTubeBundle(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTubeBundleType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcTubeBundleType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcTypeObject = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + return new IfcTypeObject(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + return args; + } +}; +var IfcTypeProcess = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ProcessType = ProcessType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ProcessType = tape[ptr++]; + return new IfcTypeProcess(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ProcessType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ProcessType); + return args; + } +}; +var IfcTypeProduct = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcTypeProduct(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + return args; + } +}; +var IfcTypeResource = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.Identification = Identification; + this.LongDescription = LongDescription; + this.ResourceType = ResourceType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let Identification = tape[ptr++]; + let LongDescription = tape[ptr++]; + let ResourceType = tape[ptr++]; + return new IfcTypeResource(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, Identification, LongDescription, ResourceType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.Identification); + args.push(this.LongDescription); + args.push(this.ResourceType); + return args; + } +}; +var IfcUShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius, FlangeSlope) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Depth = Depth; + this.FlangeWidth = FlangeWidth; + this.WebThickness = WebThickness; + this.FlangeThickness = FlangeThickness; + this.FilletRadius = FilletRadius; + this.EdgeRadius = EdgeRadius; + this.FlangeSlope = FlangeSlope; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Depth = tape[ptr++]; + let FlangeWidth = tape[ptr++]; + let WebThickness = tape[ptr++]; + let FlangeThickness = tape[ptr++]; + let FilletRadius = tape[ptr++]; + let EdgeRadius = tape[ptr++]; + let FlangeSlope = tape[ptr++]; + return new IfcUShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius, FlangeSlope); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Depth); + args.push(this.FlangeWidth); + args.push(this.WebThickness); + args.push(this.FlangeThickness); + args.push(this.FilletRadius); + args.push(this.EdgeRadius); + args.push(this.FlangeSlope); + return args; + } +}; +var IfcUnitAssignment = class { + constructor(expressID, type, Units) { + this.expressID = expressID; + this.type = type; + this.Units = Units; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Units = tape[ptr++]; + return new IfcUnitAssignment(expressID, type, Units); + } + ToTape() { + let args = []; + args.push(this.Units); + return args; + } +}; +var IfcUnitaryControlElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcUnitaryControlElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcUnitaryControlElementType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcUnitaryControlElementType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcUnitaryEquipment = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcUnitaryEquipment(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcUnitaryEquipmentType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcUnitaryEquipmentType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcValve = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcValve(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcValveType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcValveType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcVector = class { + constructor(expressID, type, Orientation, Magnitude) { + this.expressID = expressID; + this.type = type; + this.Orientation = Orientation; + this.Magnitude = Magnitude; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Orientation = tape[ptr++]; + let Magnitude = tape[ptr++]; + return new IfcVector(expressID, type, Orientation, Magnitude); + } + ToTape() { + let args = []; + args.push(this.Orientation); + args.push(this.Magnitude); + return args; + } +}; +var IfcVertex = class { + constructor(expressID, type) { + this.expressID = expressID; + this.type = type; + } + static FromTape(expressID, type, tape) { + return new IfcVertex(expressID, type); + } + ToTape() { + let args = []; + return args; + } +}; +var IfcVertexLoop = class { + constructor(expressID, type, LoopVertex) { + this.expressID = expressID; + this.type = type; + this.LoopVertex = LoopVertex; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let LoopVertex = tape[ptr++]; + return new IfcVertexLoop(expressID, type, LoopVertex); + } + ToTape() { + let args = []; + args.push(this.LoopVertex); + return args; + } +}; +var IfcVertexPoint = class { + constructor(expressID, type, VertexGeometry) { + this.expressID = expressID; + this.type = type; + this.VertexGeometry = VertexGeometry; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let VertexGeometry = tape[ptr++]; + return new IfcVertexPoint(expressID, type, VertexGeometry); + } + ToTape() { + let args = []; + args.push(this.VertexGeometry); + return args; + } +}; +var IfcVibrationDamper = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcVibrationDamper(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcVibrationDamperType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcVibrationDamperType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcVibrationIsolator = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcVibrationIsolator(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcVibrationIsolatorType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcVibrationIsolatorType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcVirtualElement = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + return new IfcVirtualElement(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + return args; + } +}; +var IfcVirtualGridIntersection = class { + constructor(expressID, type, IntersectingAxes, OffsetDistances) { + this.expressID = expressID; + this.type = type; + this.IntersectingAxes = IntersectingAxes; + this.OffsetDistances = OffsetDistances; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let IntersectingAxes = tape[ptr++]; + let OffsetDistances = tape[ptr++]; + return new IfcVirtualGridIntersection(expressID, type, IntersectingAxes, OffsetDistances); + } + ToTape() { + let args = []; + args.push(this.IntersectingAxes); + args.push(this.OffsetDistances); + return args; + } +}; +var IfcVoidingFeature = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcVoidingFeature(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWall = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWall(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWallElementedCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWallElementedCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWallStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWallStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWallType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWallType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWasteTerminal = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWasteTerminal(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWasteTerminalType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWasteTerminalType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWindow = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.OverallHeight = OverallHeight; + this.OverallWidth = OverallWidth; + this.PredefinedType = PredefinedType; + this.PartitioningType = PartitioningType; + this.UserDefinedPartitioningType = UserDefinedPartitioningType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let OverallHeight = tape[ptr++]; + let OverallWidth = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let PartitioningType = tape[ptr++]; + let UserDefinedPartitioningType = tape[ptr++]; + return new IfcWindow(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.OverallHeight); + args.push(this.OverallWidth); + args.push(this.PredefinedType); + args.push(this.PartitioningType); + args.push(this.UserDefinedPartitioningType); + return args; + } +}; +var IfcWindowLiningProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, TransomThickness, MullionThickness, FirstTransomOffset, SecondTransomOffset, FirstMullionOffset, SecondMullionOffset, ShapeAspectStyle, LiningOffset, LiningToPanelOffsetX, LiningToPanelOffsetY) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.LiningDepth = LiningDepth; + this.LiningThickness = LiningThickness; + this.TransomThickness = TransomThickness; + this.MullionThickness = MullionThickness; + this.FirstTransomOffset = FirstTransomOffset; + this.SecondTransomOffset = SecondTransomOffset; + this.FirstMullionOffset = FirstMullionOffset; + this.SecondMullionOffset = SecondMullionOffset; + this.ShapeAspectStyle = ShapeAspectStyle; + this.LiningOffset = LiningOffset; + this.LiningToPanelOffsetX = LiningToPanelOffsetX; + this.LiningToPanelOffsetY = LiningToPanelOffsetY; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let LiningDepth = tape[ptr++]; + let LiningThickness = tape[ptr++]; + let TransomThickness = tape[ptr++]; + let MullionThickness = tape[ptr++]; + let FirstTransomOffset = tape[ptr++]; + let SecondTransomOffset = tape[ptr++]; + let FirstMullionOffset = tape[ptr++]; + let SecondMullionOffset = tape[ptr++]; + let ShapeAspectStyle = tape[ptr++]; + let LiningOffset = tape[ptr++]; + let LiningToPanelOffsetX = tape[ptr++]; + let LiningToPanelOffsetY = tape[ptr++]; + return new IfcWindowLiningProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, LiningDepth, LiningThickness, TransomThickness, MullionThickness, FirstTransomOffset, SecondTransomOffset, FirstMullionOffset, SecondMullionOffset, ShapeAspectStyle, LiningOffset, LiningToPanelOffsetX, LiningToPanelOffsetY); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.LiningDepth); + args.push(this.LiningThickness); + args.push(this.TransomThickness); + args.push(this.MullionThickness); + args.push(this.FirstTransomOffset); + args.push(this.SecondTransomOffset); + args.push(this.FirstMullionOffset); + args.push(this.SecondMullionOffset); + args.push(this.ShapeAspectStyle); + args.push(this.LiningOffset); + args.push(this.LiningToPanelOffsetX); + args.push(this.LiningToPanelOffsetY); + return args; + } +}; +var IfcWindowPanelProperties = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.OperationType = OperationType; + this.PanelPosition = PanelPosition; + this.FrameDepth = FrameDepth; + this.FrameThickness = FrameThickness; + this.ShapeAspectStyle = ShapeAspectStyle; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let OperationType = tape[ptr++]; + let PanelPosition = tape[ptr++]; + let FrameDepth = tape[ptr++]; + let FrameThickness = tape[ptr++]; + let ShapeAspectStyle = tape[ptr++]; + return new IfcWindowPanelProperties(expressID, type, GlobalId, OwnerHistory, Name, Description, OperationType, PanelPosition, FrameDepth, FrameThickness, ShapeAspectStyle); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.OperationType); + args.push(this.PanelPosition); + args.push(this.FrameDepth); + args.push(this.FrameThickness); + args.push(this.ShapeAspectStyle); + return args; + } +}; +var IfcWindowStandardCase = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.ObjectPlacement = ObjectPlacement; + this.Representation = Representation; + this.Tag = Tag; + this.OverallHeight = OverallHeight; + this.OverallWidth = OverallWidth; + this.PredefinedType = PredefinedType; + this.PartitioningType = PartitioningType; + this.UserDefinedPartitioningType = UserDefinedPartitioningType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let ObjectPlacement = tape[ptr++]; + let Representation = tape[ptr++]; + let Tag = tape[ptr++]; + let OverallHeight = tape[ptr++]; + let OverallWidth = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let PartitioningType = tape[ptr++]; + let UserDefinedPartitioningType = tape[ptr++]; + return new IfcWindowStandardCase(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, ObjectPlacement, Representation, Tag, OverallHeight, OverallWidth, PredefinedType, PartitioningType, UserDefinedPartitioningType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.ObjectPlacement); + args.push(this.Representation); + args.push(this.Tag); + args.push(this.OverallHeight); + args.push(this.OverallWidth); + args.push(this.PredefinedType); + args.push(this.PartitioningType); + args.push(this.UserDefinedPartitioningType); + return args; + } +}; +var IfcWindowStyle = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ConstructionType, OperationType, ParameterTakesPrecedence, Sizeable) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ConstructionType = ConstructionType; + this.OperationType = OperationType; + this.ParameterTakesPrecedence = ParameterTakesPrecedence; + this.Sizeable = Sizeable; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ConstructionType = tape[ptr++]; + let OperationType = tape[ptr++]; + let ParameterTakesPrecedence = tape[ptr++]; + let Sizeable = tape[ptr++]; + return new IfcWindowStyle(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ConstructionType, OperationType, ParameterTakesPrecedence, Sizeable); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ConstructionType); + args.push(this.OperationType); + args.push(this.ParameterTakesPrecedence); + args.push(this.Sizeable); + return args; + } +}; +var IfcWindowType = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, PartitioningType, ParameterTakesPrecedence, UserDefinedPartitioningType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ApplicableOccurrence = ApplicableOccurrence; + this.HasPropertySets = HasPropertySets; + this.RepresentationMaps = RepresentationMaps; + this.Tag = Tag; + this.ElementType = ElementType; + this.PredefinedType = PredefinedType; + this.PartitioningType = PartitioningType; + this.ParameterTakesPrecedence = ParameterTakesPrecedence; + this.UserDefinedPartitioningType = UserDefinedPartitioningType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ApplicableOccurrence = tape[ptr++]; + let HasPropertySets = tape[ptr++]; + let RepresentationMaps = tape[ptr++]; + let Tag = tape[ptr++]; + let ElementType = tape[ptr++]; + let PredefinedType = tape[ptr++]; + let PartitioningType = tape[ptr++]; + let ParameterTakesPrecedence = tape[ptr++]; + let UserDefinedPartitioningType = tape[ptr++]; + return new IfcWindowType(expressID, type, GlobalId, OwnerHistory, Name, Description, ApplicableOccurrence, HasPropertySets, RepresentationMaps, Tag, ElementType, PredefinedType, PartitioningType, ParameterTakesPrecedence, UserDefinedPartitioningType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ApplicableOccurrence); + args.push(this.HasPropertySets); + args.push(this.RepresentationMaps); + args.push(this.Tag); + args.push(this.ElementType); + args.push(this.PredefinedType); + args.push(this.PartitioningType); + args.push(this.ParameterTakesPrecedence); + args.push(this.UserDefinedPartitioningType); + return args; + } +}; +var IfcWorkCalendar = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, WorkingTimes, ExceptionTimes, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.WorkingTimes = WorkingTimes; + this.ExceptionTimes = ExceptionTimes; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let WorkingTimes = tape[ptr++]; + let ExceptionTimes = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWorkCalendar(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, WorkingTimes, ExceptionTimes, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.WorkingTimes); + args.push(this.ExceptionTimes); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWorkControl = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.CreationDate = CreationDate; + this.Creators = Creators; + this.Purpose = Purpose; + this.Duration = Duration; + this.TotalFloat = TotalFloat; + this.StartTime = StartTime; + this.FinishTime = FinishTime; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let CreationDate = tape[ptr++]; + let Creators = tape[ptr++]; + let Purpose = tape[ptr++]; + let Duration = tape[ptr++]; + let TotalFloat = tape[ptr++]; + let StartTime = tape[ptr++]; + let FinishTime = tape[ptr++]; + return new IfcWorkControl(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.CreationDate); + args.push(this.Creators); + args.push(this.Purpose); + args.push(this.Duration); + args.push(this.TotalFloat); + args.push(this.StartTime); + args.push(this.FinishTime); + return args; + } +}; +var IfcWorkPlan = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.CreationDate = CreationDate; + this.Creators = Creators; + this.Purpose = Purpose; + this.Duration = Duration; + this.TotalFloat = TotalFloat; + this.StartTime = StartTime; + this.FinishTime = FinishTime; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let CreationDate = tape[ptr++]; + let Creators = tape[ptr++]; + let Purpose = tape[ptr++]; + let Duration = tape[ptr++]; + let TotalFloat = tape[ptr++]; + let StartTime = tape[ptr++]; + let FinishTime = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWorkPlan(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.CreationDate); + args.push(this.Creators); + args.push(this.Purpose); + args.push(this.Duration); + args.push(this.TotalFloat); + args.push(this.StartTime); + args.push(this.FinishTime); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWorkSchedule = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.Identification = Identification; + this.CreationDate = CreationDate; + this.Creators = Creators; + this.Purpose = Purpose; + this.Duration = Duration; + this.TotalFloat = TotalFloat; + this.StartTime = StartTime; + this.FinishTime = FinishTime; + this.PredefinedType = PredefinedType; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let Identification = tape[ptr++]; + let CreationDate = tape[ptr++]; + let Creators = tape[ptr++]; + let Purpose = tape[ptr++]; + let Duration = tape[ptr++]; + let TotalFloat = tape[ptr++]; + let StartTime = tape[ptr++]; + let FinishTime = tape[ptr++]; + let PredefinedType = tape[ptr++]; + return new IfcWorkSchedule(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, Identification, CreationDate, Creators, Purpose, Duration, TotalFloat, StartTime, FinishTime, PredefinedType); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.Identification); + args.push(this.CreationDate); + args.push(this.Creators); + args.push(this.Purpose); + args.push(this.Duration); + args.push(this.TotalFloat); + args.push(this.StartTime); + args.push(this.FinishTime); + args.push(this.PredefinedType); + return args; + } +}; +var IfcWorkTime = class { + constructor(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, RecurrencePattern, Start, Finish) { + this.expressID = expressID; + this.type = type; + this.Name = Name; + this.DataOrigin = DataOrigin; + this.UserDefinedDataOrigin = UserDefinedDataOrigin; + this.RecurrencePattern = RecurrencePattern; + this.Start = Start; + this.Finish = Finish; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let Name = tape[ptr++]; + let DataOrigin = tape[ptr++]; + let UserDefinedDataOrigin = tape[ptr++]; + let RecurrencePattern = tape[ptr++]; + let Start = tape[ptr++]; + let Finish = tape[ptr++]; + return new IfcWorkTime(expressID, type, Name, DataOrigin, UserDefinedDataOrigin, RecurrencePattern, Start, Finish); + } + ToTape() { + let args = []; + args.push(this.Name); + args.push(this.DataOrigin); + args.push(this.UserDefinedDataOrigin); + args.push(this.RecurrencePattern); + args.push(this.Start); + args.push(this.Finish); + return args; + } +}; +var IfcZShapeProfileDef = class { + constructor(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius) { + this.expressID = expressID; + this.type = type; + this.ProfileType = ProfileType; + this.ProfileName = ProfileName; + this.Position = Position; + this.Depth = Depth; + this.FlangeWidth = FlangeWidth; + this.WebThickness = WebThickness; + this.FlangeThickness = FlangeThickness; + this.FilletRadius = FilletRadius; + this.EdgeRadius = EdgeRadius; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let ProfileType = tape[ptr++]; + let ProfileName = tape[ptr++]; + let Position = tape[ptr++]; + let Depth = tape[ptr++]; + let FlangeWidth = tape[ptr++]; + let WebThickness = tape[ptr++]; + let FlangeThickness = tape[ptr++]; + let FilletRadius = tape[ptr++]; + let EdgeRadius = tape[ptr++]; + return new IfcZShapeProfileDef(expressID, type, ProfileType, ProfileName, Position, Depth, FlangeWidth, WebThickness, FlangeThickness, FilletRadius, EdgeRadius); + } + ToTape() { + let args = []; + args.push(this.ProfileType); + args.push(this.ProfileName); + args.push(this.Position); + args.push(this.Depth); + args.push(this.FlangeWidth); + args.push(this.WebThickness); + args.push(this.FlangeThickness); + args.push(this.FilletRadius); + args.push(this.EdgeRadius); + return args; + } +}; +var IfcZone = class { + constructor(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName) { + this.expressID = expressID; + this.type = type; + this.GlobalId = GlobalId; + this.OwnerHistory = OwnerHistory; + this.Name = Name; + this.Description = Description; + this.ObjectType = ObjectType; + this.LongName = LongName; + } + static FromTape(expressID, type, tape) { + let ptr = 0; + let GlobalId = tape[ptr++]; + let OwnerHistory = tape[ptr++]; + let Name = tape[ptr++]; + let Description = tape[ptr++]; + let ObjectType = tape[ptr++]; + let LongName = tape[ptr++]; + return new IfcZone(expressID, type, GlobalId, OwnerHistory, Name, Description, ObjectType, LongName); + } + ToTape() { + let args = []; + args.push(this.GlobalId); + args.push(this.OwnerHistory); + args.push(this.Name); + args.push(this.Description); + args.push(this.ObjectType); + args.push(this.LongName); + return args; + } +}; - for (let i = 0, len = newObjects.length; i < len; i++) { - const newObject = newObjects[i]; - const type = newObject.type; - const objectId = options.globalizeObjectIds ? math.globalizeObjectId(modelId, newObject.id) : newObject.id; - const originalSystemId = newObject.id; - const name = newObject.name; - const propertySets = []; - if (newObject.propertySetIds && newObject.propertySetIds.length > 0) { - for (let j = 0, lenj = newObject.propertySetIds.length; j < lenj; j++) { - const propertySetId = newObject.propertySetIds[j]; - const propertySet = metaModel.propertySets[propertySetId]; - if (propertySet) { - propertySets.push(propertySet); - } - } - } - const parent = null; - const children = null; - const external = newObject.external; - const metaObject = new MetaObject(metaModel, objectId, originalSystemId, name, type, propertySets, parent, children, external); - this.metaObjects[objectId] = metaObject; - (this.metaObjectsByType[type] || (this.metaObjectsByType[type] = {}))[objectId] = metaObject; - if (this._typeCounts[type] === undefined) { - this._typeCounts[type] = 1; - } else { - this._typeCounts[type]++; - } - } +// dist/helpers/ifc-elements.ts +var IfcElements2 = { + 103090709: "IFCPROJECT", + 4097777520: "IFCSITE", + 4031249490: "IFCBUILDING", + 3124254112: "IFCBUILDINGSTOREY", + 3856911033: "IFCSPACE", + 1674181508: "IFCANNOTATION", + 25142252: "IFCCONTROLLER", + 32344328: "IFCBOILER", + 76236018: "IFCLAMP", + 90941305: "IFCPUMP", + 177149247: "IFCAIRTERMINALBOX", + 182646315: "IFCFLOWINSTRUMENT", + 263784265: "IFCFURNISHINGELEMENT", + 264262732: "IFCELECTRICGENERATOR", + 277319702: "IFCAUDIOVISUALAPPLIANCE", + 310824031: "IFCPIPEFITTING", + 331165859: "IFCSTAIR", + 342316401: "IFCDUCTFITTING", + 377706215: "IFCMECHANICALFASTENER", + 395920057: "IFCDOOR", + 402227799: "IFCELECTRICMOTOR", + 413509423: "IFCSYSTEMFURNITUREELEMENT", + 484807127: "IFCEVAPORATOR", + 486154966: "IFCWINDOWSTANDARDCASE", + 629592764: "IFCLIGHTFIXTURE", + 630975310: "IFCUNITARYCONTROLELEMENT", + 635142910: "IFCCABLECARRIERFITTING", + 639361253: "IFCCOIL", + 647756555: "IFCFASTENER", + 707683696: "IFCFLOWSTORAGEDEVICE", + 738039164: "IFCPROTECTIVEDEVICE", + 753842376: "IFCBEAM", + 812556717: "IFCTANK", + 819412036: "IFCFILTER", + 843113511: "IFCCOLUMN", + 862014818: "IFCELECTRICDISTRIBUTIONBOARD", + 900683007: "IFCFOOTING", + 905975707: "IFCCOLUMNSTANDARDCASE", + 926996030: "IFCVOIDINGFEATURE", + 979691226: "IFCREINFORCINGBAR", + 987401354: "IFCFLOWSEGMENT", + 1003880860: "IFCELECTRICTIMECONTROL", + 1051757585: "IFCCABLEFITTING", + 1052013943: "IFCDISTRIBUTIONCHAMBERELEMENT", + 1062813311: "IFCDISTRIBUTIONCONTROLELEMENT", + 1073191201: "IFCMEMBER", + 1095909175: "IFCBUILDINGELEMENTPROXY", + 1156407060: "IFCPLATESTANDARDCASE", + 1162798199: "IFCSWITCHINGDEVICE", + 1329646415: "IFCSHADINGDEVICE", + 1335981549: "IFCDISCRETEACCESSORY", + 1360408905: "IFCDUCTSILENCER", + 1404847402: "IFCSTACKTERMINAL", + 1426591983: "IFCFIRESUPPRESSIONTERMINAL", + 1437502449: "IFCMEDICALDEVICE", + 1509553395: "IFCFURNITURE", + 1529196076: "IFCSLAB", + 1620046519: "IFCTRANSPORTELEMENT", + 1634111441: "IFCAIRTERMINAL", + 1658829314: "IFCENERGYCONVERSIONDEVICE", + 1677625105: "IFCCIVILELEMENT", + 1687234759: "IFCPILE", + 1904799276: "IFCELECTRICAPPLIANCE", + 1911478936: "IFCMEMBERSTANDARDCASE", + 1945004755: "IFCDISTRIBUTIONELEMENT", + 1973544240: "IFCCOVERING", + 1999602285: "IFCSPACEHEATER", + 2016517767: "IFCROOF", + 2056796094: "IFCAIRTOAIRHEATRECOVERY", + 2058353004: "IFCFLOWCONTROLLER", + 2068733104: "IFCHUMIDIFIER", + 2176052936: "IFCJUNCTIONBOX", + 2188021234: "IFCFLOWMETER", + 2223149337: "IFCFLOWTERMINAL", + 2262370178: "IFCRAILING", + 2272882330: "IFCCONDENSER", + 2295281155: "IFCPROTECTIVEDEVICETRIPPINGUNIT", + 2320036040: "IFCREINFORCINGMESH", + 2347447852: "IFCTENDONANCHOR", + 2391383451: "IFCVIBRATIONISOLATOR", + 2391406946: "IFCWALL", + 2474470126: "IFCMOTORCONNECTION", + 2769231204: "IFCVIRTUALELEMENT", + 2814081492: "IFCENGINE", + 2906023776: "IFCBEAMSTANDARDCASE", + 2938176219: "IFCBURNER", + 2979338954: "IFCBUILDINGELEMENTPART", + 3024970846: "IFCRAMP", + 3026737570: "IFCTUBEBUNDLE", + 3027962421: "IFCSLABSTANDARDCASE", + 3040386961: "IFCDISTRIBUTIONFLOWELEMENT", + 3053780830: "IFCSANITARYTERMINAL", + 3079942009: "IFCOPENINGSTANDARDCASE", + 3087945054: "IFCALARM", + 3101698114: "IFCSURFACEFEATURE", + 3127900445: "IFCSLABELEMENTEDCASE", + 3132237377: "IFCFLOWMOVINGDEVICE", + 3171933400: "IFCPLATE", + 3221913625: "IFCCOMMUNICATIONSAPPLIANCE", + 3242481149: "IFCDOORSTANDARDCASE", + 3283111854: "IFCRAMPFLIGHT", + 3296154744: "IFCCHIMNEY", + 3304561284: "IFCWINDOW", + 3310460725: "IFCELECTRICFLOWSTORAGEDEVICE", + 3319311131: "IFCHEATEXCHANGER", + 3415622556: "IFCFAN", + 3420628829: "IFCSOLARDEVICE", + 3493046030: "IFCGEOGRAPHICELEMENT", + 3495092785: "IFCCURTAINWALL", + 3508470533: "IFCFLOWTREATMENTDEVICE", + 3512223829: "IFCWALLSTANDARDCASE", + 3518393246: "IFCDUCTSEGMENT", + 3571504051: "IFCCOMPRESSOR", + 3588315303: "IFCOPENINGELEMENT", + 3612865200: "IFCPIPESEGMENT", + 3640358203: "IFCCOOLINGTOWER", + 3651124850: "IFCPROJECTIONELEMENT", + 3694346114: "IFCOUTLET", + 3747195512: "IFCEVAPORATIVECOOLER", + 3758799889: "IFCCABLECARRIERSEGMENT", + 3824725483: "IFCTENDON", + 3825984169: "IFCTRANSFORMER", + 3902619387: "IFCCHILLER", + 4074379575: "IFCDAMPER", + 4086658281: "IFCSENSOR", + 4123344466: "IFCELEMENTASSEMBLY", + 4136498852: "IFCCOOLEDBEAM", + 4156078855: "IFCWALLELEMENTEDCASE", + 4175244083: "IFCINTERCEPTOR", + 4207607924: "IFCVALVE", + 4217484030: "IFCCABLESEGMENT", + 4237592921: "IFCWASTETERMINAL", + 4252922144: "IFCSTAIRFLIGHT", + 4278956645: "IFCFLOWFITTING", + 4288193352: "IFCACTUATOR", + 4292641817: "IFCUNITARYEQUIPMENT", + 3009204131: "IFCGRID" +}; - for (let i = 0, len = newObjects.length; i < len; i++) { - const newObject = newObjects[i]; - const objectId = options.globalizeObjectIds ? math.globalizeObjectId(modelId, newObject.id) : newObject.id; - const metaObject = this.metaObjects[objectId]; - if (!metaObject) { - continue; - } - if (newObject.parent === undefined || newObject.parent === null) { - metaModel.rootMetaObject = metaObject; - } else if (newObject.parent) { - const parentId = options.globalizeObjectIds ? math.globalizeObjectId(modelId, newObject.parent) : newObject.parent; - let parentMetaObject = this.metaObjects[parentId]; - if (parentMetaObject) { - metaObject.parent = parentMetaObject; - parentMetaObject.children = parentMetaObject.children || []; - parentMetaObject.children.push(metaObject); - } - } - } +// dist/helpers/types-map.ts +var IfcTypesMap = { + 3821786052: "IFCACTIONREQUEST", + 2296667514: "IFCACTOR", + 3630933823: "IFCACTORROLE", + 4288193352: "IFCACTUATOR", + 2874132201: "IFCACTUATORTYPE", + 618182010: "IFCADDRESS", + 1635779807: "IFCADVANCEDBREP", + 2603310189: "IFCADVANCEDBREPWITHVOIDS", + 3406155212: "IFCADVANCEDFACE", + 1634111441: "IFCAIRTERMINAL", + 177149247: "IFCAIRTERMINALBOX", + 1411407467: "IFCAIRTERMINALBOXTYPE", + 3352864051: "IFCAIRTERMINALTYPE", + 2056796094: "IFCAIRTOAIRHEATRECOVERY", + 1871374353: "IFCAIRTOAIRHEATRECOVERYTYPE", + 3087945054: "IFCALARM", + 3001207471: "IFCALARMTYPE", + 325726236: "IFCALIGNMENT", + 749761778: "IFCALIGNMENT2DHORIZONTAL", + 3199563722: "IFCALIGNMENT2DHORIZONTALSEGMENT", + 2483840362: "IFCALIGNMENT2DSEGMENT", + 3379348081: "IFCALIGNMENT2DVERSEGCIRCULARARC", + 3239324667: "IFCALIGNMENT2DVERSEGLINE", + 4263986512: "IFCALIGNMENT2DVERSEGPARABOLICARC", + 53199957: "IFCALIGNMENT2DVERTICAL", + 2029264950: "IFCALIGNMENT2DVERTICALSEGMENT", + 3512275521: "IFCALIGNMENTCURVE", + 1674181508: "IFCANNOTATION", + 669184980: "IFCANNOTATIONFILLAREA", + 639542469: "IFCAPPLICATION", + 411424972: "IFCAPPLIEDVALUE", + 130549933: "IFCAPPROVAL", + 3869604511: "IFCAPPROVALRELATIONSHIP", + 3798115385: "IFCARBITRARYCLOSEDPROFILEDEF", + 1310608509: "IFCARBITRARYOPENPROFILEDEF", + 2705031697: "IFCARBITRARYPROFILEDEFWITHVOIDS", + 3460190687: "IFCASSET", + 3207858831: "IFCASYMMETRICISHAPEPROFILEDEF", + 277319702: "IFCAUDIOVISUALAPPLIANCE", + 1532957894: "IFCAUDIOVISUALAPPLIANCETYPE", + 4261334040: "IFCAXIS1PLACEMENT", + 3125803723: "IFCAXIS2PLACEMENT2D", + 2740243338: "IFCAXIS2PLACEMENT3D", + 1967976161: "IFCBSPLINECURVE", + 2461110595: "IFCBSPLINECURVEWITHKNOTS", + 2887950389: "IFCBSPLINESURFACE", + 167062518: "IFCBSPLINESURFACEWITHKNOTS", + 753842376: "IFCBEAM", + 2906023776: "IFCBEAMSTANDARDCASE", + 819618141: "IFCBEAMTYPE", + 4196446775: "IFCBEARING", + 3649138523: "IFCBEARINGTYPE", + 616511568: "IFCBLOBTEXTURE", + 1334484129: "IFCBLOCK", + 32344328: "IFCBOILER", + 231477066: "IFCBOILERTYPE", + 3649129432: "IFCBOOLEANCLIPPINGRESULT", + 2736907675: "IFCBOOLEANRESULT", + 4037036970: "IFCBOUNDARYCONDITION", + 1136057603: "IFCBOUNDARYCURVE", + 1560379544: "IFCBOUNDARYEDGECONDITION", + 3367102660: "IFCBOUNDARYFACECONDITION", + 1387855156: "IFCBOUNDARYNODECONDITION", + 2069777674: "IFCBOUNDARYNODECONDITIONWARPING", + 1260505505: "IFCBOUNDEDCURVE", + 4182860854: "IFCBOUNDEDSURFACE", + 2581212453: "IFCBOUNDINGBOX", + 2713105998: "IFCBOXEDHALFSPACE", + 644574406: "IFCBRIDGE", + 963979645: "IFCBRIDGEPART", + 4031249490: "IFCBUILDING", + 3299480353: "IFCBUILDINGELEMENT", + 2979338954: "IFCBUILDINGELEMENTPART", + 39481116: "IFCBUILDINGELEMENTPARTTYPE", + 1095909175: "IFCBUILDINGELEMENTPROXY", + 1909888760: "IFCBUILDINGELEMENTPROXYTYPE", + 1950629157: "IFCBUILDINGELEMENTTYPE", + 3124254112: "IFCBUILDINGSTOREY", + 1177604601: "IFCBUILDINGSYSTEM", + 2938176219: "IFCBURNER", + 2188180465: "IFCBURNERTYPE", + 2898889636: "IFCCSHAPEPROFILEDEF", + 635142910: "IFCCABLECARRIERFITTING", + 395041908: "IFCCABLECARRIERFITTINGTYPE", + 3758799889: "IFCCABLECARRIERSEGMENT", + 3293546465: "IFCCABLECARRIERSEGMENTTYPE", + 1051757585: "IFCCABLEFITTING", + 2674252688: "IFCCABLEFITTINGTYPE", + 4217484030: "IFCCABLESEGMENT", + 1285652485: "IFCCABLESEGMENTTYPE", + 3999819293: "IFCCAISSONFOUNDATION", + 3203706013: "IFCCAISSONFOUNDATIONTYPE", + 1123145078: "IFCCARTESIANPOINT", + 574549367: "IFCCARTESIANPOINTLIST", + 1675464909: "IFCCARTESIANPOINTLIST2D", + 2059837836: "IFCCARTESIANPOINTLIST3D", + 59481748: "IFCCARTESIANTRANSFORMATIONOPERATOR", + 3749851601: "IFCCARTESIANTRANSFORMATIONOPERATOR2D", + 3486308946: "IFCCARTESIANTRANSFORMATIONOPERATOR2DNONUNIFORM", + 3331915920: "IFCCARTESIANTRANSFORMATIONOPERATOR3D", + 1416205885: "IFCCARTESIANTRANSFORMATIONOPERATOR3DNONUNIFORM", + 3150382593: "IFCCENTERLINEPROFILEDEF", + 3902619387: "IFCCHILLER", + 2951183804: "IFCCHILLERTYPE", + 3296154744: "IFCCHIMNEY", + 2197970202: "IFCCHIMNEYTYPE", + 2611217952: "IFCCIRCLE", + 2937912522: "IFCCIRCLEHOLLOWPROFILEDEF", + 1383045692: "IFCCIRCLEPROFILEDEF", + 1062206242: "IFCCIRCULARARCSEGMENT2D", + 1677625105: "IFCCIVILELEMENT", + 3893394355: "IFCCIVILELEMENTTYPE", + 747523909: "IFCCLASSIFICATION", + 647927063: "IFCCLASSIFICATIONREFERENCE", + 2205249479: "IFCCLOSEDSHELL", + 639361253: "IFCCOIL", + 2301859152: "IFCCOILTYPE", + 776857604: "IFCCOLOURRGB", + 3285139300: "IFCCOLOURRGBLIST", + 3264961684: "IFCCOLOURSPECIFICATION", + 843113511: "IFCCOLUMN", + 905975707: "IFCCOLUMNSTANDARDCASE", + 300633059: "IFCCOLUMNTYPE", + 3221913625: "IFCCOMMUNICATIONSAPPLIANCE", + 400855858: "IFCCOMMUNICATIONSAPPLIANCETYPE", + 2542286263: "IFCCOMPLEXPROPERTY", + 3875453745: "IFCCOMPLEXPROPERTYTEMPLATE", + 3732776249: "IFCCOMPOSITECURVE", + 15328376: "IFCCOMPOSITECURVEONSURFACE", + 2485617015: "IFCCOMPOSITECURVESEGMENT", + 1485152156: "IFCCOMPOSITEPROFILEDEF", + 3571504051: "IFCCOMPRESSOR", + 3850581409: "IFCCOMPRESSORTYPE", + 2272882330: "IFCCONDENSER", + 2816379211: "IFCCONDENSERTYPE", + 2510884976: "IFCCONIC", + 370225590: "IFCCONNECTEDFACESET", + 1981873012: "IFCCONNECTIONCURVEGEOMETRY", + 2859738748: "IFCCONNECTIONGEOMETRY", + 45288368: "IFCCONNECTIONPOINTECCENTRICITY", + 2614616156: "IFCCONNECTIONPOINTGEOMETRY", + 2732653382: "IFCCONNECTIONSURFACEGEOMETRY", + 775493141: "IFCCONNECTIONVOLUMEGEOMETRY", + 1959218052: "IFCCONSTRAINT", + 3898045240: "IFCCONSTRUCTIONEQUIPMENTRESOURCE", + 2185764099: "IFCCONSTRUCTIONEQUIPMENTRESOURCETYPE", + 1060000209: "IFCCONSTRUCTIONMATERIALRESOURCE", + 4105962743: "IFCCONSTRUCTIONMATERIALRESOURCETYPE", + 488727124: "IFCCONSTRUCTIONPRODUCTRESOURCE", + 1525564444: "IFCCONSTRUCTIONPRODUCTRESOURCETYPE", + 2559216714: "IFCCONSTRUCTIONRESOURCE", + 2574617495: "IFCCONSTRUCTIONRESOURCETYPE", + 3419103109: "IFCCONTEXT", + 3050246964: "IFCCONTEXTDEPENDENTUNIT", + 3293443760: "IFCCONTROL", + 25142252: "IFCCONTROLLER", + 578613899: "IFCCONTROLLERTYPE", + 2889183280: "IFCCONVERSIONBASEDUNIT", + 2713554722: "IFCCONVERSIONBASEDUNITWITHOFFSET", + 4136498852: "IFCCOOLEDBEAM", + 335055490: "IFCCOOLEDBEAMTYPE", + 3640358203: "IFCCOOLINGTOWER", + 2954562838: "IFCCOOLINGTOWERTYPE", + 1785450214: "IFCCOORDINATEOPERATION", + 1466758467: "IFCCOORDINATEREFERENCESYSTEM", + 3895139033: "IFCCOSTITEM", + 1419761937: "IFCCOSTSCHEDULE", + 602808272: "IFCCOSTVALUE", + 1973544240: "IFCCOVERING", + 1916426348: "IFCCOVERINGTYPE", + 3295246426: "IFCCREWRESOURCE", + 1815067380: "IFCCREWRESOURCETYPE", + 2506170314: "IFCCSGPRIMITIVE3D", + 2147822146: "IFCCSGSOLID", + 539742890: "IFCCURRENCYRELATIONSHIP", + 3495092785: "IFCCURTAINWALL", + 1457835157: "IFCCURTAINWALLTYPE", + 2601014836: "IFCCURVE", + 2827736869: "IFCCURVEBOUNDEDPLANE", + 2629017746: "IFCCURVEBOUNDEDSURFACE", + 1186437898: "IFCCURVESEGMENT2D", + 3800577675: "IFCCURVESTYLE", + 1105321065: "IFCCURVESTYLEFONT", + 2367409068: "IFCCURVESTYLEFONTANDSCALING", + 3510044353: "IFCCURVESTYLEFONTPATTERN", + 1213902940: "IFCCYLINDRICALSURFACE", + 4074379575: "IFCDAMPER", + 3961806047: "IFCDAMPERTYPE", + 3426335179: "IFCDEEPFOUNDATION", + 1306400036: "IFCDEEPFOUNDATIONTYPE", + 3632507154: "IFCDERIVEDPROFILEDEF", + 1765591967: "IFCDERIVEDUNIT", + 1045800335: "IFCDERIVEDUNITELEMENT", + 2949456006: "IFCDIMENSIONALEXPONENTS", + 32440307: "IFCDIRECTION", + 1335981549: "IFCDISCRETEACCESSORY", + 2635815018: "IFCDISCRETEACCESSORYTYPE", + 1945343521: "IFCDISTANCEEXPRESSION", + 1052013943: "IFCDISTRIBUTIONCHAMBERELEMENT", + 1599208980: "IFCDISTRIBUTIONCHAMBERELEMENTTYPE", + 562808652: "IFCDISTRIBUTIONCIRCUIT", + 1062813311: "IFCDISTRIBUTIONCONTROLELEMENT", + 2063403501: "IFCDISTRIBUTIONCONTROLELEMENTTYPE", + 1945004755: "IFCDISTRIBUTIONELEMENT", + 3256556792: "IFCDISTRIBUTIONELEMENTTYPE", + 3040386961: "IFCDISTRIBUTIONFLOWELEMENT", + 3849074793: "IFCDISTRIBUTIONFLOWELEMENTTYPE", + 3041715199: "IFCDISTRIBUTIONPORT", + 3205830791: "IFCDISTRIBUTIONSYSTEM", + 1154170062: "IFCDOCUMENTINFORMATION", + 770865208: "IFCDOCUMENTINFORMATIONRELATIONSHIP", + 3732053477: "IFCDOCUMENTREFERENCE", + 395920057: "IFCDOOR", + 2963535650: "IFCDOORLININGPROPERTIES", + 1714330368: "IFCDOORPANELPROPERTIES", + 3242481149: "IFCDOORSTANDARDCASE", + 526551008: "IFCDOORSTYLE", + 2323601079: "IFCDOORTYPE", + 445594917: "IFCDRAUGHTINGPREDEFINEDCOLOUR", + 4006246654: "IFCDRAUGHTINGPREDEFINEDCURVEFONT", + 342316401: "IFCDUCTFITTING", + 869906466: "IFCDUCTFITTINGTYPE", + 3518393246: "IFCDUCTSEGMENT", + 3760055223: "IFCDUCTSEGMENTTYPE", + 1360408905: "IFCDUCTSILENCER", + 2030761528: "IFCDUCTSILENCERTYPE", + 3900360178: "IFCEDGE", + 476780140: "IFCEDGECURVE", + 1472233963: "IFCEDGELOOP", + 1904799276: "IFCELECTRICAPPLIANCE", + 663422040: "IFCELECTRICAPPLIANCETYPE", + 862014818: "IFCELECTRICDISTRIBUTIONBOARD", + 2417008758: "IFCELECTRICDISTRIBUTIONBOARDTYPE", + 3310460725: "IFCELECTRICFLOWSTORAGEDEVICE", + 3277789161: "IFCELECTRICFLOWSTORAGEDEVICETYPE", + 264262732: "IFCELECTRICGENERATOR", + 1534661035: "IFCELECTRICGENERATORTYPE", + 402227799: "IFCELECTRICMOTOR", + 1217240411: "IFCELECTRICMOTORTYPE", + 1003880860: "IFCELECTRICTIMECONTROL", + 712377611: "IFCELECTRICTIMECONTROLTYPE", + 1758889154: "IFCELEMENT", + 4123344466: "IFCELEMENTASSEMBLY", + 2397081782: "IFCELEMENTASSEMBLYTYPE", + 1623761950: "IFCELEMENTCOMPONENT", + 2590856083: "IFCELEMENTCOMPONENTTYPE", + 1883228015: "IFCELEMENTQUANTITY", + 339256511: "IFCELEMENTTYPE", + 2777663545: "IFCELEMENTARYSURFACE", + 1704287377: "IFCELLIPSE", + 2835456948: "IFCELLIPSEPROFILEDEF", + 1658829314: "IFCENERGYCONVERSIONDEVICE", + 2107101300: "IFCENERGYCONVERSIONDEVICETYPE", + 2814081492: "IFCENGINE", + 132023988: "IFCENGINETYPE", + 3747195512: "IFCEVAPORATIVECOOLER", + 3174744832: "IFCEVAPORATIVECOOLERTYPE", + 484807127: "IFCEVAPORATOR", + 3390157468: "IFCEVAPORATORTYPE", + 4148101412: "IFCEVENT", + 211053100: "IFCEVENTTIME", + 4024345920: "IFCEVENTTYPE", + 297599258: "IFCEXTENDEDPROPERTIES", + 4294318154: "IFCEXTERNALINFORMATION", + 3200245327: "IFCEXTERNALREFERENCE", + 1437805879: "IFCEXTERNALREFERENCERELATIONSHIP", + 1209101575: "IFCEXTERNALSPATIALELEMENT", + 2853485674: "IFCEXTERNALSPATIALSTRUCTUREELEMENT", + 2242383968: "IFCEXTERNALLYDEFINEDHATCHSTYLE", + 1040185647: "IFCEXTERNALLYDEFINEDSURFACESTYLE", + 3548104201: "IFCEXTERNALLYDEFINEDTEXTFONT", + 477187591: "IFCEXTRUDEDAREASOLID", + 2804161546: "IFCEXTRUDEDAREASOLIDTAPERED", + 2556980723: "IFCFACE", + 2047409740: "IFCFACEBASEDSURFACEMODEL", + 1809719519: "IFCFACEBOUND", + 803316827: "IFCFACEOUTERBOUND", + 3008276851: "IFCFACESURFACE", + 807026263: "IFCFACETEDBREP", + 3737207727: "IFCFACETEDBREPWITHVOIDS", + 24185140: "IFCFACILITY", + 1310830890: "IFCFACILITYPART", + 4219587988: "IFCFAILURECONNECTIONCONDITION", + 3415622556: "IFCFAN", + 346874300: "IFCFANTYPE", + 647756555: "IFCFASTENER", + 2489546625: "IFCFASTENERTYPE", + 2827207264: "IFCFEATUREELEMENT", + 2143335405: "IFCFEATUREELEMENTADDITION", + 1287392070: "IFCFEATUREELEMENTSUBTRACTION", + 738692330: "IFCFILLAREASTYLE", + 374418227: "IFCFILLAREASTYLEHATCHING", + 315944413: "IFCFILLAREASTYLETILES", + 819412036: "IFCFILTER", + 1810631287: "IFCFILTERTYPE", + 1426591983: "IFCFIRESUPPRESSIONTERMINAL", + 4222183408: "IFCFIRESUPPRESSIONTERMINALTYPE", + 2652556860: "IFCFIXEDREFERENCESWEPTAREASOLID", + 2058353004: "IFCFLOWCONTROLLER", + 3907093117: "IFCFLOWCONTROLLERTYPE", + 4278956645: "IFCFLOWFITTING", + 3198132628: "IFCFLOWFITTINGTYPE", + 182646315: "IFCFLOWINSTRUMENT", + 4037862832: "IFCFLOWINSTRUMENTTYPE", + 2188021234: "IFCFLOWMETER", + 3815607619: "IFCFLOWMETERTYPE", + 3132237377: "IFCFLOWMOVINGDEVICE", + 1482959167: "IFCFLOWMOVINGDEVICETYPE", + 987401354: "IFCFLOWSEGMENT", + 1834744321: "IFCFLOWSEGMENTTYPE", + 707683696: "IFCFLOWSTORAGEDEVICE", + 1339347760: "IFCFLOWSTORAGEDEVICETYPE", + 2223149337: "IFCFLOWTERMINAL", + 2297155007: "IFCFLOWTERMINALTYPE", + 3508470533: "IFCFLOWTREATMENTDEVICE", + 3009222698: "IFCFLOWTREATMENTDEVICETYPE", + 900683007: "IFCFOOTING", + 1893162501: "IFCFOOTINGTYPE", + 263784265: "IFCFURNISHINGELEMENT", + 4238390223: "IFCFURNISHINGELEMENTTYPE", + 1509553395: "IFCFURNITURE", + 1268542332: "IFCFURNITURETYPE", + 3493046030: "IFCGEOGRAPHICELEMENT", + 4095422895: "IFCGEOGRAPHICELEMENTTYPE", + 987898635: "IFCGEOMETRICCURVESET", + 3448662350: "IFCGEOMETRICREPRESENTATIONCONTEXT", + 2453401579: "IFCGEOMETRICREPRESENTATIONITEM", + 4142052618: "IFCGEOMETRICREPRESENTATIONSUBCONTEXT", + 3590301190: "IFCGEOMETRICSET", + 3009204131: "IFCGRID", + 852622518: "IFCGRIDAXIS", + 178086475: "IFCGRIDPLACEMENT", + 2706460486: "IFCGROUP", + 812098782: "IFCHALFSPACESOLID", + 3319311131: "IFCHEATEXCHANGER", + 1251058090: "IFCHEATEXCHANGERTYPE", + 2068733104: "IFCHUMIDIFIER", + 1806887404: "IFCHUMIDIFIERTYPE", + 1484403080: "IFCISHAPEPROFILEDEF", + 3905492369: "IFCIMAGETEXTURE", + 3570813810: "IFCINDEXEDCOLOURMAP", + 2571569899: "IFCINDEXEDPOLYCURVE", + 178912537: "IFCINDEXEDPOLYGONALFACE", + 2294589976: "IFCINDEXEDPOLYGONALFACEWITHVOIDS", + 1437953363: "IFCINDEXEDTEXTUREMAP", + 2133299955: "IFCINDEXEDTRIANGLETEXTUREMAP", + 4175244083: "IFCINTERCEPTOR", + 3946677679: "IFCINTERCEPTORTYPE", + 3113134337: "IFCINTERSECTIONCURVE", + 2391368822: "IFCINVENTORY", + 3741457305: "IFCIRREGULARTIMESERIES", + 3020489413: "IFCIRREGULARTIMESERIESVALUE", + 2176052936: "IFCJUNCTIONBOX", + 4288270099: "IFCJUNCTIONBOXTYPE", + 572779678: "IFCLSHAPEPROFILEDEF", + 3827777499: "IFCLABORRESOURCE", + 428585644: "IFCLABORRESOURCETYPE", + 1585845231: "IFCLAGTIME", + 76236018: "IFCLAMP", + 1051575348: "IFCLAMPTYPE", + 2655187982: "IFCLIBRARYINFORMATION", + 3452421091: "IFCLIBRARYREFERENCE", + 4162380809: "IFCLIGHTDISTRIBUTIONDATA", + 629592764: "IFCLIGHTFIXTURE", + 1161773419: "IFCLIGHTFIXTURETYPE", + 1566485204: "IFCLIGHTINTENSITYDISTRIBUTION", + 1402838566: "IFCLIGHTSOURCE", + 125510826: "IFCLIGHTSOURCEAMBIENT", + 2604431987: "IFCLIGHTSOURCEDIRECTIONAL", + 4266656042: "IFCLIGHTSOURCEGONIOMETRIC", + 1520743889: "IFCLIGHTSOURCEPOSITIONAL", + 3422422726: "IFCLIGHTSOURCESPOT", + 1281925730: "IFCLINE", + 3092502836: "IFCLINESEGMENT2D", + 388784114: "IFCLINEARPLACEMENT", + 1154579445: "IFCLINEARPOSITIONINGELEMENT", + 2624227202: "IFCLOCALPLACEMENT", + 1008929658: "IFCLOOP", + 1425443689: "IFCMANIFOLDSOLIDBREP", + 3057273783: "IFCMAPCONVERSION", + 2347385850: "IFCMAPPEDITEM", + 1838606355: "IFCMATERIAL", + 1847130766: "IFCMATERIALCLASSIFICATIONRELATIONSHIP", + 3708119e3: "IFCMATERIALCONSTITUENT", + 2852063980: "IFCMATERIALCONSTITUENTSET", + 760658860: "IFCMATERIALDEFINITION", + 2022407955: "IFCMATERIALDEFINITIONREPRESENTATION", + 248100487: "IFCMATERIALLAYER", + 3303938423: "IFCMATERIALLAYERSET", + 1303795690: "IFCMATERIALLAYERSETUSAGE", + 1847252529: "IFCMATERIALLAYERWITHOFFSETS", + 2199411900: "IFCMATERIALLIST", + 2235152071: "IFCMATERIALPROFILE", + 164193824: "IFCMATERIALPROFILESET", + 3079605661: "IFCMATERIALPROFILESETUSAGE", + 3404854881: "IFCMATERIALPROFILESETUSAGETAPERING", + 552965576: "IFCMATERIALPROFILEWITHOFFSETS", + 3265635763: "IFCMATERIALPROPERTIES", + 853536259: "IFCMATERIALRELATIONSHIP", + 1507914824: "IFCMATERIALUSAGEDEFINITION", + 2597039031: "IFCMEASUREWITHUNIT", + 377706215: "IFCMECHANICALFASTENER", + 2108223431: "IFCMECHANICALFASTENERTYPE", + 1437502449: "IFCMEDICALDEVICE", + 1114901282: "IFCMEDICALDEVICETYPE", + 1073191201: "IFCMEMBER", + 1911478936: "IFCMEMBERSTANDARDCASE", + 3181161470: "IFCMEMBERTYPE", + 3368373690: "IFCMETRIC", + 2998442950: "IFCMIRROREDPROFILEDEF", + 2706619895: "IFCMONETARYUNIT", + 2474470126: "IFCMOTORCONNECTION", + 977012517: "IFCMOTORCONNECTIONTYPE", + 1918398963: "IFCNAMEDUNIT", + 3888040117: "IFCOBJECT", + 219451334: "IFCOBJECTDEFINITION", + 3701648758: "IFCOBJECTPLACEMENT", + 2251480897: "IFCOBJECTIVE", + 4143007308: "IFCOCCUPANT", + 590820931: "IFCOFFSETCURVE", + 3388369263: "IFCOFFSETCURVE2D", + 3505215534: "IFCOFFSETCURVE3D", + 2485787929: "IFCOFFSETCURVEBYDISTANCES", + 2665983363: "IFCOPENSHELL", + 3588315303: "IFCOPENINGELEMENT", + 3079942009: "IFCOPENINGSTANDARDCASE", + 4251960020: "IFCORGANIZATION", + 1411181986: "IFCORGANIZATIONRELATIONSHIP", + 643959842: "IFCORIENTATIONEXPRESSION", + 1029017970: "IFCORIENTEDEDGE", + 144952367: "IFCOUTERBOUNDARYCURVE", + 3694346114: "IFCOUTLET", + 2837617999: "IFCOUTLETTYPE", + 1207048766: "IFCOWNERHISTORY", + 2529465313: "IFCPARAMETERIZEDPROFILEDEF", + 2519244187: "IFCPATH", + 1682466193: "IFCPCURVE", + 2382730787: "IFCPERFORMANCEHISTORY", + 3566463478: "IFCPERMEABLECOVERINGPROPERTIES", + 3327091369: "IFCPERMIT", + 2077209135: "IFCPERSON", + 101040310: "IFCPERSONANDORGANIZATION", + 3021840470: "IFCPHYSICALCOMPLEXQUANTITY", + 2483315170: "IFCPHYSICALQUANTITY", + 2226359599: "IFCPHYSICALSIMPLEQUANTITY", + 1687234759: "IFCPILE", + 1158309216: "IFCPILETYPE", + 310824031: "IFCPIPEFITTING", + 804291784: "IFCPIPEFITTINGTYPE", + 3612865200: "IFCPIPESEGMENT", + 4231323485: "IFCPIPESEGMENTTYPE", + 597895409: "IFCPIXELTEXTURE", + 2004835150: "IFCPLACEMENT", + 603570806: "IFCPLANARBOX", + 1663979128: "IFCPLANAREXTENT", + 220341763: "IFCPLANE", + 3171933400: "IFCPLATE", + 1156407060: "IFCPLATESTANDARDCASE", + 4017108033: "IFCPLATETYPE", + 2067069095: "IFCPOINT", + 4022376103: "IFCPOINTONCURVE", + 1423911732: "IFCPOINTONSURFACE", + 2924175390: "IFCPOLYLOOP", + 2775532180: "IFCPOLYGONALBOUNDEDHALFSPACE", + 2839578677: "IFCPOLYGONALFACESET", + 3724593414: "IFCPOLYLINE", + 3740093272: "IFCPORT", + 1946335990: "IFCPOSITIONINGELEMENT", + 3355820592: "IFCPOSTALADDRESS", + 759155922: "IFCPREDEFINEDCOLOUR", + 2559016684: "IFCPREDEFINEDCURVEFONT", + 3727388367: "IFCPREDEFINEDITEM", + 3778827333: "IFCPREDEFINEDPROPERTIES", + 3967405729: "IFCPREDEFINEDPROPERTYSET", + 1775413392: "IFCPREDEFINEDTEXTFONT", + 677532197: "IFCPRESENTATIONITEM", + 2022622350: "IFCPRESENTATIONLAYERASSIGNMENT", + 1304840413: "IFCPRESENTATIONLAYERWITHSTYLE", + 3119450353: "IFCPRESENTATIONSTYLE", + 2417041796: "IFCPRESENTATIONSTYLEASSIGNMENT", + 2744685151: "IFCPROCEDURE", + 569719735: "IFCPROCEDURETYPE", + 2945172077: "IFCPROCESS", + 4208778838: "IFCPRODUCT", + 673634403: "IFCPRODUCTDEFINITIONSHAPE", + 2095639259: "IFCPRODUCTREPRESENTATION", + 3958567839: "IFCPROFILEDEF", + 2802850158: "IFCPROFILEPROPERTIES", + 103090709: "IFCPROJECT", + 653396225: "IFCPROJECTLIBRARY", + 2904328755: "IFCPROJECTORDER", + 3843373140: "IFCPROJECTEDCRS", + 3651124850: "IFCPROJECTIONELEMENT", + 2598011224: "IFCPROPERTY", + 986844984: "IFCPROPERTYABSTRACTION", + 871118103: "IFCPROPERTYBOUNDEDVALUE", + 1680319473: "IFCPROPERTYDEFINITION", + 148025276: "IFCPROPERTYDEPENDENCYRELATIONSHIP", + 4166981789: "IFCPROPERTYENUMERATEDVALUE", + 3710013099: "IFCPROPERTYENUMERATION", + 2752243245: "IFCPROPERTYLISTVALUE", + 941946838: "IFCPROPERTYREFERENCEVALUE", + 1451395588: "IFCPROPERTYSET", + 3357820518: "IFCPROPERTYSETDEFINITION", + 492091185: "IFCPROPERTYSETTEMPLATE", + 3650150729: "IFCPROPERTYSINGLEVALUE", + 110355661: "IFCPROPERTYTABLEVALUE", + 3521284610: "IFCPROPERTYTEMPLATE", + 1482703590: "IFCPROPERTYTEMPLATEDEFINITION", + 738039164: "IFCPROTECTIVEDEVICE", + 2295281155: "IFCPROTECTIVEDEVICETRIPPINGUNIT", + 655969474: "IFCPROTECTIVEDEVICETRIPPINGUNITTYPE", + 1842657554: "IFCPROTECTIVEDEVICETYPE", + 3219374653: "IFCPROXY", + 90941305: "IFCPUMP", + 2250791053: "IFCPUMPTYPE", + 2044713172: "IFCQUANTITYAREA", + 2093928680: "IFCQUANTITYCOUNT", + 931644368: "IFCQUANTITYLENGTH", + 2090586900: "IFCQUANTITYSET", + 3252649465: "IFCQUANTITYTIME", + 2405470396: "IFCQUANTITYVOLUME", + 825690147: "IFCQUANTITYWEIGHT", + 2262370178: "IFCRAILING", + 2893384427: "IFCRAILINGTYPE", + 3024970846: "IFCRAMP", + 3283111854: "IFCRAMPFLIGHT", + 2324767716: "IFCRAMPFLIGHTTYPE", + 1469900589: "IFCRAMPTYPE", + 1232101972: "IFCRATIONALBSPLINECURVEWITHKNOTS", + 683857671: "IFCRATIONALBSPLINESURFACEWITHKNOTS", + 2770003689: "IFCRECTANGLEHOLLOWPROFILEDEF", + 3615266464: "IFCRECTANGLEPROFILEDEF", + 2798486643: "IFCRECTANGULARPYRAMID", + 3454111270: "IFCRECTANGULARTRIMMEDSURFACE", + 3915482550: "IFCRECURRENCEPATTERN", + 2433181523: "IFCREFERENCE", + 4021432810: "IFCREFERENT", + 3413951693: "IFCREGULARTIMESERIES", + 1580146022: "IFCREINFORCEMENTBARPROPERTIES", + 3765753017: "IFCREINFORCEMENTDEFINITIONPROPERTIES", + 979691226: "IFCREINFORCINGBAR", + 2572171363: "IFCREINFORCINGBARTYPE", + 3027567501: "IFCREINFORCINGELEMENT", + 964333572: "IFCREINFORCINGELEMENTTYPE", + 2320036040: "IFCREINFORCINGMESH", + 2310774935: "IFCREINFORCINGMESHTYPE", + 160246688: "IFCRELAGGREGATES", + 3939117080: "IFCRELASSIGNS", + 1683148259: "IFCRELASSIGNSTOACTOR", + 2495723537: "IFCRELASSIGNSTOCONTROL", + 1307041759: "IFCRELASSIGNSTOGROUP", + 1027710054: "IFCRELASSIGNSTOGROUPBYFACTOR", + 4278684876: "IFCRELASSIGNSTOPROCESS", + 2857406711: "IFCRELASSIGNSTOPRODUCT", + 205026976: "IFCRELASSIGNSTORESOURCE", + 1865459582: "IFCRELASSOCIATES", + 4095574036: "IFCRELASSOCIATESAPPROVAL", + 919958153: "IFCRELASSOCIATESCLASSIFICATION", + 2728634034: "IFCRELASSOCIATESCONSTRAINT", + 982818633: "IFCRELASSOCIATESDOCUMENT", + 3840914261: "IFCRELASSOCIATESLIBRARY", + 2655215786: "IFCRELASSOCIATESMATERIAL", + 826625072: "IFCRELCONNECTS", + 1204542856: "IFCRELCONNECTSELEMENTS", + 3945020480: "IFCRELCONNECTSPATHELEMENTS", + 4201705270: "IFCRELCONNECTSPORTTOELEMENT", + 3190031847: "IFCRELCONNECTSPORTS", + 2127690289: "IFCRELCONNECTSSTRUCTURALACTIVITY", + 1638771189: "IFCRELCONNECTSSTRUCTURALMEMBER", + 504942748: "IFCRELCONNECTSWITHECCENTRICITY", + 3678494232: "IFCRELCONNECTSWITHREALIZINGELEMENTS", + 3242617779: "IFCRELCONTAINEDINSPATIALSTRUCTURE", + 886880790: "IFCRELCOVERSBLDGELEMENTS", + 2802773753: "IFCRELCOVERSSPACES", + 2565941209: "IFCRELDECLARES", + 2551354335: "IFCRELDECOMPOSES", + 693640335: "IFCRELDEFINES", + 1462361463: "IFCRELDEFINESBYOBJECT", + 4186316022: "IFCRELDEFINESBYPROPERTIES", + 307848117: "IFCRELDEFINESBYTEMPLATE", + 781010003: "IFCRELDEFINESBYTYPE", + 3940055652: "IFCRELFILLSELEMENT", + 279856033: "IFCRELFLOWCONTROLELEMENTS", + 427948657: "IFCRELINTERFERESELEMENTS", + 3268803585: "IFCRELNESTS", + 1441486842: "IFCRELPOSITIONS", + 750771296: "IFCRELPROJECTSELEMENT", + 1245217292: "IFCRELREFERENCEDINSPATIALSTRUCTURE", + 4122056220: "IFCRELSEQUENCE", + 366585022: "IFCRELSERVICESBUILDINGS", + 3451746338: "IFCRELSPACEBOUNDARY", + 3523091289: "IFCRELSPACEBOUNDARY1STLEVEL", + 1521410863: "IFCRELSPACEBOUNDARY2NDLEVEL", + 1401173127: "IFCRELVOIDSELEMENT", + 478536968: "IFCRELATIONSHIP", + 816062949: "IFCREPARAMETRISEDCOMPOSITECURVESEGMENT", + 1076942058: "IFCREPRESENTATION", + 3377609919: "IFCREPRESENTATIONCONTEXT", + 3008791417: "IFCREPRESENTATIONITEM", + 1660063152: "IFCREPRESENTATIONMAP", + 2914609552: "IFCRESOURCE", + 2943643501: "IFCRESOURCEAPPROVALRELATIONSHIP", + 1608871552: "IFCRESOURCECONSTRAINTRELATIONSHIP", + 2439245199: "IFCRESOURCELEVELRELATIONSHIP", + 1042787934: "IFCRESOURCETIME", + 1856042241: "IFCREVOLVEDAREASOLID", + 3243963512: "IFCREVOLVEDAREASOLIDTAPERED", + 4158566097: "IFCRIGHTCIRCULARCONE", + 3626867408: "IFCRIGHTCIRCULARCYLINDER", + 2016517767: "IFCROOF", + 2781568857: "IFCROOFTYPE", + 2341007311: "IFCROOT", + 2778083089: "IFCROUNDEDRECTANGLEPROFILEDEF", + 448429030: "IFCSIUNIT", + 3053780830: "IFCSANITARYTERMINAL", + 1768891740: "IFCSANITARYTERMINALTYPE", + 1054537805: "IFCSCHEDULINGTIME", + 2157484638: "IFCSEAMCURVE", + 2042790032: "IFCSECTIONPROPERTIES", + 4165799628: "IFCSECTIONREINFORCEMENTPROPERTIES", + 1862484736: "IFCSECTIONEDSOLID", + 1290935644: "IFCSECTIONEDSOLIDHORIZONTAL", + 1509187699: "IFCSECTIONEDSPINE", + 4086658281: "IFCSENSOR", + 1783015770: "IFCSENSORTYPE", + 1329646415: "IFCSHADINGDEVICE", + 4074543187: "IFCSHADINGDEVICETYPE", + 867548509: "IFCSHAPEASPECT", + 3982875396: "IFCSHAPEMODEL", + 4240577450: "IFCSHAPEREPRESENTATION", + 4124623270: "IFCSHELLBASEDSURFACEMODEL", + 3692461612: "IFCSIMPLEPROPERTY", + 3663146110: "IFCSIMPLEPROPERTYTEMPLATE", + 4097777520: "IFCSITE", + 1529196076: "IFCSLAB", + 3127900445: "IFCSLABELEMENTEDCASE", + 3027962421: "IFCSLABSTANDARDCASE", + 2533589738: "IFCSLABTYPE", + 2609359061: "IFCSLIPPAGECONNECTIONCONDITION", + 3420628829: "IFCSOLARDEVICE", + 1072016465: "IFCSOLARDEVICETYPE", + 723233188: "IFCSOLIDMODEL", + 3856911033: "IFCSPACE", + 1999602285: "IFCSPACEHEATER", + 1305183839: "IFCSPACEHEATERTYPE", + 3812236995: "IFCSPACETYPE", + 1412071761: "IFCSPATIALELEMENT", + 710998568: "IFCSPATIALELEMENTTYPE", + 2706606064: "IFCSPATIALSTRUCTUREELEMENT", + 3893378262: "IFCSPATIALSTRUCTUREELEMENTTYPE", + 463610769: "IFCSPATIALZONE", + 2481509218: "IFCSPATIALZONETYPE", + 451544542: "IFCSPHERE", + 4015995234: "IFCSPHERICALSURFACE", + 1404847402: "IFCSTACKTERMINAL", + 3112655638: "IFCSTACKTERMINALTYPE", + 331165859: "IFCSTAIR", + 4252922144: "IFCSTAIRFLIGHT", + 1039846685: "IFCSTAIRFLIGHTTYPE", + 338393293: "IFCSTAIRTYPE", + 682877961: "IFCSTRUCTURALACTION", + 3544373492: "IFCSTRUCTURALACTIVITY", + 2515109513: "IFCSTRUCTURALANALYSISMODEL", + 1179482911: "IFCSTRUCTURALCONNECTION", + 2273995522: "IFCSTRUCTURALCONNECTIONCONDITION", + 1004757350: "IFCSTRUCTURALCURVEACTION", + 4243806635: "IFCSTRUCTURALCURVECONNECTION", + 214636428: "IFCSTRUCTURALCURVEMEMBER", + 2445595289: "IFCSTRUCTURALCURVEMEMBERVARYING", + 2757150158: "IFCSTRUCTURALCURVEREACTION", + 3136571912: "IFCSTRUCTURALITEM", + 1807405624: "IFCSTRUCTURALLINEARACTION", + 2162789131: "IFCSTRUCTURALLOAD", + 385403989: "IFCSTRUCTURALLOADCASE", + 3478079324: "IFCSTRUCTURALLOADCONFIGURATION", + 1252848954: "IFCSTRUCTURALLOADGROUP", + 1595516126: "IFCSTRUCTURALLOADLINEARFORCE", + 609421318: "IFCSTRUCTURALLOADORRESULT", + 2668620305: "IFCSTRUCTURALLOADPLANARFORCE", + 2473145415: "IFCSTRUCTURALLOADSINGLEDISPLACEMENT", + 1973038258: "IFCSTRUCTURALLOADSINGLEDISPLACEMENTDISTORTION", + 1597423693: "IFCSTRUCTURALLOADSINGLEFORCE", + 1190533807: "IFCSTRUCTURALLOADSINGLEFORCEWARPING", + 2525727697: "IFCSTRUCTURALLOADSTATIC", + 3408363356: "IFCSTRUCTURALLOADTEMPERATURE", + 530289379: "IFCSTRUCTURALMEMBER", + 1621171031: "IFCSTRUCTURALPLANARACTION", + 2082059205: "IFCSTRUCTURALPOINTACTION", + 734778138: "IFCSTRUCTURALPOINTCONNECTION", + 1235345126: "IFCSTRUCTURALPOINTREACTION", + 3689010777: "IFCSTRUCTURALREACTION", + 2986769608: "IFCSTRUCTURALRESULTGROUP", + 3657597509: "IFCSTRUCTURALSURFACEACTION", + 1975003073: "IFCSTRUCTURALSURFACECONNECTION", + 3979015343: "IFCSTRUCTURALSURFACEMEMBER", + 2218152070: "IFCSTRUCTURALSURFACEMEMBERVARYING", + 603775116: "IFCSTRUCTURALSURFACEREACTION", + 2830218821: "IFCSTYLEMODEL", + 3958052878: "IFCSTYLEDITEM", + 3049322572: "IFCSTYLEDREPRESENTATION", + 148013059: "IFCSUBCONTRACTRESOURCE", + 4095615324: "IFCSUBCONTRACTRESOURCETYPE", + 2233826070: "IFCSUBEDGE", + 2513912981: "IFCSURFACE", + 699246055: "IFCSURFACECURVE", + 2028607225: "IFCSURFACECURVESWEPTAREASOLID", + 3101698114: "IFCSURFACEFEATURE", + 2809605785: "IFCSURFACEOFLINEAREXTRUSION", + 4124788165: "IFCSURFACEOFREVOLUTION", + 2934153892: "IFCSURFACEREINFORCEMENTAREA", + 1300840506: "IFCSURFACESTYLE", + 3303107099: "IFCSURFACESTYLELIGHTING", + 1607154358: "IFCSURFACESTYLEREFRACTION", + 1878645084: "IFCSURFACESTYLERENDERING", + 846575682: "IFCSURFACESTYLESHADING", + 1351298697: "IFCSURFACESTYLEWITHTEXTURES", + 626085974: "IFCSURFACETEXTURE", + 2247615214: "IFCSWEPTAREASOLID", + 1260650574: "IFCSWEPTDISKSOLID", + 1096409881: "IFCSWEPTDISKSOLIDPOLYGONAL", + 230924584: "IFCSWEPTSURFACE", + 1162798199: "IFCSWITCHINGDEVICE", + 2315554128: "IFCSWITCHINGDEVICETYPE", + 2254336722: "IFCSYSTEM", + 413509423: "IFCSYSTEMFURNITUREELEMENT", + 1580310250: "IFCSYSTEMFURNITUREELEMENTTYPE", + 3071757647: "IFCTSHAPEPROFILEDEF", + 985171141: "IFCTABLE", + 2043862942: "IFCTABLECOLUMN", + 531007025: "IFCTABLEROW", + 812556717: "IFCTANK", + 5716631: "IFCTANKTYPE", + 3473067441: "IFCTASK", + 1549132990: "IFCTASKTIME", + 2771591690: "IFCTASKTIMERECURRING", + 3206491090: "IFCTASKTYPE", + 912023232: "IFCTELECOMADDRESS", + 3824725483: "IFCTENDON", + 2347447852: "IFCTENDONANCHOR", + 3081323446: "IFCTENDONANCHORTYPE", + 3663046924: "IFCTENDONCONDUIT", + 2281632017: "IFCTENDONCONDUITTYPE", + 2415094496: "IFCTENDONTYPE", + 2387106220: "IFCTESSELLATEDFACESET", + 901063453: "IFCTESSELLATEDITEM", + 4282788508: "IFCTEXTLITERAL", + 3124975700: "IFCTEXTLITERALWITHEXTENT", + 1447204868: "IFCTEXTSTYLE", + 1983826977: "IFCTEXTSTYLEFONTMODEL", + 2636378356: "IFCTEXTSTYLEFORDEFINEDFONT", + 1640371178: "IFCTEXTSTYLETEXTMODEL", + 280115917: "IFCTEXTURECOORDINATE", + 1742049831: "IFCTEXTURECOORDINATEGENERATOR", + 2552916305: "IFCTEXTUREMAP", + 1210645708: "IFCTEXTUREVERTEX", + 3611470254: "IFCTEXTUREVERTEXLIST", + 1199560280: "IFCTIMEPERIOD", + 3101149627: "IFCTIMESERIES", + 581633288: "IFCTIMESERIESVALUE", + 1377556343: "IFCTOPOLOGICALREPRESENTATIONITEM", + 1735638870: "IFCTOPOLOGYREPRESENTATION", + 1935646853: "IFCTOROIDALSURFACE", + 3825984169: "IFCTRANSFORMER", + 1692211062: "IFCTRANSFORMERTYPE", + 2595432518: "IFCTRANSITIONCURVESEGMENT2D", + 1620046519: "IFCTRANSPORTELEMENT", + 2097647324: "IFCTRANSPORTELEMENTTYPE", + 2715220739: "IFCTRAPEZIUMPROFILEDEF", + 2916149573: "IFCTRIANGULATEDFACESET", + 1229763772: "IFCTRIANGULATEDIRREGULARNETWORK", + 3593883385: "IFCTRIMMEDCURVE", + 3026737570: "IFCTUBEBUNDLE", + 1600972822: "IFCTUBEBUNDLETYPE", + 1628702193: "IFCTYPEOBJECT", + 3736923433: "IFCTYPEPROCESS", + 2347495698: "IFCTYPEPRODUCT", + 3698973494: "IFCTYPERESOURCE", + 427810014: "IFCUSHAPEPROFILEDEF", + 180925521: "IFCUNITASSIGNMENT", + 630975310: "IFCUNITARYCONTROLELEMENT", + 3179687236: "IFCUNITARYCONTROLELEMENTTYPE", + 4292641817: "IFCUNITARYEQUIPMENT", + 1911125066: "IFCUNITARYEQUIPMENTTYPE", + 4207607924: "IFCVALVE", + 728799441: "IFCVALVETYPE", + 1417489154: "IFCVECTOR", + 2799835756: "IFCVERTEX", + 2759199220: "IFCVERTEXLOOP", + 1907098498: "IFCVERTEXPOINT", + 1530820697: "IFCVIBRATIONDAMPER", + 3956297820: "IFCVIBRATIONDAMPERTYPE", + 2391383451: "IFCVIBRATIONISOLATOR", + 3313531582: "IFCVIBRATIONISOLATORTYPE", + 2769231204: "IFCVIRTUALELEMENT", + 891718957: "IFCVIRTUALGRIDINTERSECTION", + 926996030: "IFCVOIDINGFEATURE", + 2391406946: "IFCWALL", + 4156078855: "IFCWALLELEMENTEDCASE", + 3512223829: "IFCWALLSTANDARDCASE", + 1898987631: "IFCWALLTYPE", + 4237592921: "IFCWASTETERMINAL", + 1133259667: "IFCWASTETERMINALTYPE", + 3304561284: "IFCWINDOW", + 336235671: "IFCWINDOWLININGPROPERTIES", + 512836454: "IFCWINDOWPANELPROPERTIES", + 486154966: "IFCWINDOWSTANDARDCASE", + 1299126871: "IFCWINDOWSTYLE", + 4009809668: "IFCWINDOWTYPE", + 4088093105: "IFCWORKCALENDAR", + 1028945134: "IFCWORKCONTROL", + 4218914973: "IFCWORKPLAN", + 3342526732: "IFCWORKSCHEDULE", + 1236880293: "IFCWORKTIME", + 2543172580: "IFCZSHAPEPROFILEDEF", + 1033361043: "IFCZONE" +}; - this.fire("metaModelCreated", modelId); - return metaModel; +// dist/helpers/properties.ts +var PropsNames = { + aggregates: { + name: IFCRELAGGREGATES, + relating: "RelatingObject", + related: "RelatedObjects", + key: "children" + }, + spatial: { + name: IFCRELCONTAINEDINSPATIALSTRUCTURE, + relating: "RelatingStructure", + related: "RelatedElements", + key: "children" + }, + psets: { + name: IFCRELDEFINESBYPROPERTIES, + relating: "RelatingPropertyDefinition", + related: "RelatedObjects", + key: "hasPsets" + }, + materials: { + name: IFCRELASSOCIATESMATERIAL, + relating: "RelatingMaterial", + related: "RelatedObjects", + key: "hasMaterial" + }, + type: { + name: IFCRELDEFINESBYTYPE, + relating: "RelatingType", + related: "RelatedObjects", + key: "hasType" + } +}; +var Properties = class { + constructor(api) { + this.api = api; + } + getIfcType(type) { + return IfcTypesMap[type]; + } + getItemProperties(modelID, id, recursive = false) { + return __async(this, null, function* () { + return this.api.GetLine(modelID, id, recursive); + }); + } + getPropertySets(modelID, elementID, recursive = false) { + return __async(this, null, function* () { + return yield this.getProperty(modelID, elementID, recursive, PropsNames.psets); + }); + } + getTypeProperties(modelID, elementID, recursive = false) { + return __async(this, null, function* () { + return yield this.getProperty(modelID, elementID, recursive, PropsNames.type); + }); + } + getMaterialsProperties(modelID, elementID, recursive = false) { + return __async(this, null, function* () { + return yield this.getProperty(modelID, elementID, recursive, PropsNames.materials); + }); + } + getSpatialStructure(modelID, includeProperties) { + return __async(this, null, function* () { + yield this.getAllTypesOfModel(modelID); + const chunks = yield this.getSpatialTreeChunks(modelID); + const allLines = yield this.api.GetLineIDsWithType(modelID, IFCPROJECT); + const projectID = allLines.get(0); + const project = Properties.newIfcProject(projectID); + yield this.getSpatialNode(modelID, project, chunks, includeProperties); + this.cleanupTypes(); + return project; + }); + } + getAllItemsOfType(modelID, type, verbose) { + return __async(this, null, function* () { + let items = []; + const lines = yield this.api.GetLineIDsWithType(modelID, type); + for (let i = 0; i < lines.size(); i++) + items.push(lines.get(i)); + if (!verbose) + return items; + const result = []; + for (let i = 0; i < items.length; i++) { + result.push(yield this.api.GetLine(modelID, items[i])); + } + return result; + }); + } + getProperty(modelID, elementID, recursive = false, propName) { + return __async(this, null, function* () { + const propSetIds = yield this.getAllRelatedItemsOfType(modelID, elementID, propName); + const result = []; + for (let i = 0; i < propSetIds.length; i++) { + result.push(yield this.api.GetLine(modelID, propSetIds[i], recursive)); + } + return result; + }); + } + getChunks(modelID, chunks, propNames) { + return __async(this, null, function* () { + const relation = yield this.api.GetLineIDsWithType(modelID, propNames.name); + for (let i = 0; i < relation.size(); i++) { + const rel = yield this.api.GetLine(modelID, relation.get(i), false); + this.saveChunk(chunks, propNames, rel); + } + }); + } + static isRelated(id, rel, propNames) { + const relatedItems = rel[propNames.related]; + if (Array.isArray(relatedItems)) { + const values = relatedItems.map((item) => item.value); + return values.includes(id); } - - /** - * Removes a {@link MetaModel} from this MetaScene. - * - * Fires a "metaModelDestroyed" event with the value of the {@link MetaModel#id}. - * - * @param {String} id ID of the target {@link MetaModel}. - */ - destroyMetaModel(id) { - const metaModel = this.metaModels[id]; - if (!metaModel) { - return; + return relatedItems.value === id; + } + static newIfcProject(id) { + return { + expressID: id, + type: "IFCPROJECT", + children: [] + }; + } + getSpatialNode(modelID, node, treeChunks, includeProperties) { + return __async(this, null, function* () { + yield this.getChildren(modelID, node, treeChunks, PropsNames.aggregates, includeProperties); + yield this.getChildren(modelID, node, treeChunks, PropsNames.spatial, includeProperties); + }); + } + getChildren(modelID, node, treeChunks, propNames, includeProperties) { + return __async(this, null, function* () { + const children = treeChunks[node.expressID]; + if (children == void 0) + return; + const prop = propNames.key; + const nodes = []; + for (let i = 0; i < children.length; i++) { + const child = children[i]; + let node2 = this.newNode(child); + if (includeProperties) { + const properties = yield this.getItemProperties(modelID, node2.expressID); + node2 = __spreadValues(__spreadValues({}, properties), node2); } - this._removeMetaModel(metaModel); - this.fire("metaModelDestroyed", id); + yield this.getSpatialNode(modelID, node2, treeChunks, includeProperties); + nodes.push(node2); + } + node[prop] = nodes; + }); + } + newNode(id) { + const typeName = this.getNodeType(id); + return { + expressID: id, + type: typeName, + children: [] + }; + } + getNodeType(id) { + const typeID = this.types[id]; + return IfcElements2[typeID]; + } + getSpatialTreeChunks(modelID) { + return __async(this, null, function* () { + const treeChunks = {}; + yield this.getChunks(modelID, treeChunks, PropsNames.aggregates); + yield this.getChunks(modelID, treeChunks, PropsNames.spatial); + return treeChunks; + }); + } + saveChunk(chunks, propNames, rel) { + const relating = rel[propNames.relating].value; + const related = rel[propNames.related].map((r) => r.value); + if (chunks[relating] == void 0) { + chunks[relating] = related; + } else { + chunks[relating] = chunks[relating].concat(related); } + } + getRelated(rel, propNames, IDs) { + const element = rel[propNames.relating]; + if (!Array.isArray(element)) + IDs.push(element.value); + else + element.forEach((ele) => IDs.push(ele.value)); + } + getAllRelatedItemsOfType(modelID, id, propNames) { + return __async(this, null, function* () { + const lines = yield this.api.GetLineIDsWithType(modelID, propNames.name); + const IDs = []; + for (let i = 0; i < lines.size(); i++) { + const rel = yield this.api.GetLine(modelID, lines.get(i)); + const isRelated = Properties.isRelated(id, rel, propNames); + if (isRelated) + this.getRelated(rel, propNames, IDs); + } + return IDs; + }); + } + cleanupTypes() { + this.types = {}; + } + getAllTypesOfModel(modelID) { + return __async(this, null, function* () { + const result = {}; + const elements = Object.keys(IfcElements2).map((e) => parseInt(e)); + for (let i = 0; i < elements.length; i++) { + const element = elements[i]; + const lines = yield this.api.GetLineIDsWithType(modelID, element); + const size = lines.size(); + for (let i2 = 0; i2 < size; i2++) + result[lines.get(i2)] = element; + } + this.types = result; + }); + } +}; - _removeMetaModel(metaModel) { - const metaObjects = this.metaObjects; - const metaObjectsByType = this.metaObjectsByType; - let visit = (metaObject) => { - delete metaObjects[metaObject.id]; - const types = metaObjectsByType[metaObject.type]; - if (types && types[metaObject.id]) { - delete types[metaObject.id]; - if (--this._typeCounts[metaObject.type] === 0) { - delete this._typeCounts[metaObject.type]; - delete metaObjectsByType[metaObject.type]; - } - } - const children = metaObject.children; - if (children) { - for (let i = 0, len = children.length; i < len; i++) { - const childMetaObject = children[i]; - visit(childMetaObject); - } +// dist/web-ifc-api.ts +var WebIFCWasm; +if (typeof self !== "undefined" && self.crossOriginIsolated) { + WebIFCWasm = require_web_ifc_mt(); +} else { + WebIFCWasm = require_web_ifc(); +} +var IfcAPI2 = class { + constructor() { + this.wasmModule = void 0; + this.fs = void 0; + this.wasmPath = ""; + this.isWasmPathAbsolute = false; + this.ifcGuidMap = new Map(); + this.properties = new Properties(this); + } + Init(customLocateFileHandler) { + return __async(this, null, function* () { + if (WebIFCWasm) { + let locateFileHandler = (path, prefix) => { + if (path.endsWith(".wasm")) { + if (this.isWasmPathAbsolute) { + return this.wasmPath + path; } + return prefix + this.wasmPath + path; + } + return prefix + path; }; - visit(metaModel.rootMetaObject); - for (let propertySetId in metaModel.propertySets) { - if (metaModel.propertySets.hasOwnProperty(propertySetId)) { - delete this.propertySets[propertySetId]; - } - } - delete this.metaModels[metaModel.id]; - } - - /** - * Gets the {@link MetaObject#id}s of the {@link MetaObject}s that have the given {@link MetaObject#type}. - * - * @param {String} type The type. - * @returns {String[]} Array of {@link MetaObject#id}s. - */ - getObjectIDsByType(type) { - const metaObjects = this.metaObjectsByType[type]; - return metaObjects ? Object.keys(metaObjects) : []; + this.wasmModule = yield WebIFCWasm({ noInitialRun: true, locateFile: customLocateFileHandler || locateFileHandler }); + this.fs = this.wasmModule.FS; + } else { + console.error(`Could not find wasm module at './web-ifc' from web-ifc-api.ts`); + } + }); + } + OpenModel(data, settings) { + let s = __spreadValues({ + COORDINATE_TO_ORIGIN: false, + USE_FAST_BOOLS: false, + CIRCLE_SEGMENTS_LOW: 5, + CIRCLE_SEGMENTS_MEDIUM: 8, + CIRCLE_SEGMENTS_HIGH: 12, + BOOL_ABORT_THRESHOLD: 1e4 + }, settings); + let offsetInSrc = 0; + let result = this.wasmModule.OpenModel(s, (destPtr, destSize) => { + let srcSize = Math.min(data.byteLength - offsetInSrc, destSize); + let dest = this.wasmModule.HEAPU8.subarray(destPtr, destPtr + destSize); + let src = data.subarray(offsetInSrc, offsetInSrc + srcSize); + dest.set(src); + offsetInSrc += srcSize; + return srcSize; + }); + return result; + } + CreateModel(settings) { + let s = __spreadValues({ + COORDINATE_TO_ORIGIN: false, + USE_FAST_BOOLS: false, + CIRCLE_SEGMENTS_LOW: 5, + CIRCLE_SEGMENTS_MEDIUM: 8, + CIRCLE_SEGMENTS_HIGH: 12, + BOOL_ABORT_THRESHOLD: 1e4 + }, settings); + let result = this.wasmModule.CreateModel(s); + return result; + } + ExportFileAsIFC(modelID) { + this.wasmModule.ExportFileAsIFC(modelID); + let result = this.fs.readFile("/export.ifc"); + this.wasmModule["FS_unlink"]("/export.ifc"); + return result; + } + GetGeometry(modelID, geometryExpressID) { + return this.wasmModule.GetGeometry(modelID, geometryExpressID); + } + GetLine(modelID, expressID, flatten = false) { + let rawLineData = this.GetRawLineData(modelID, expressID); + let lineData = FromRawLineData[rawLineData.type](rawLineData); + if (flatten) { + this.FlattenLine(modelID, lineData); } - - /** - * Gets the {@link MetaObject#id}s of the {@link MetaObject}s within the given subtree. - * - * @param {String} id ID of the root {@link MetaObject} of the given subtree. - * @param {String[]} [includeTypes] Optional list of types to include. - * @param {String[]} [excludeTypes] Optional list of types to exclude. - * @returns {String[]} Array of {@link MetaObject#id}s. - */ - getObjectIDsInSubtree(id, includeTypes, excludeTypes) { - const list = []; - const metaObject = this.metaObjects[id]; - const includeMask = (includeTypes && includeTypes.length > 0) ? arrayToMap(includeTypes) : null; - const excludeMask = (excludeTypes && excludeTypes.length > 0) ? arrayToMap(excludeTypes) : null; - - function visit(metaObject) { - if (!metaObject) { - return; - } - var include = true; - if (excludeMask && excludeMask[metaObject.type]) { - include = false; - } else if (includeMask && (!includeMask[metaObject.type])) { - include = false; - } - if (include) { - list.push(metaObject.id); - } - const children = metaObject.children; - if (children) { - for (var i = 0, len = children.length; i < len; i++) { - visit(children[i]); - } - } + return lineData; + } + GetAndClearErrors(modelID) { + return this.wasmModule.GetAndClearErrors(modelID); + } + WriteLine(modelID, lineObject) { + Object.keys(lineObject).forEach((propertyName) => { + let property = lineObject[propertyName]; + if (property && property.expressID !== void 0) { + this.WriteLine(modelID, property); + lineObject[propertyName] = { + type: 5, + value: property.expressID + }; + } else if (Array.isArray(property) && property.length > 0) { + for (let i = 0; i < property.length; i++) { + if (property[i].expressID !== void 0) { + this.WriteLine(modelID, property[i]); + lineObject[propertyName][i] = { + type: 5, + value: property[i].expressID + }; + } } - - visit(metaObject); - return list; - } - - /** - * Iterates over the {@link MetaObject}s within the subtree. - * - * @param {String} id ID of root {@link MetaObject}. - * @param {Function} callback Callback fired at each {@link MetaObject}. - */ - withMetaObjectsInSubtree(id, callback) { - const metaObject = this.metaObjects[id]; - if (!metaObject) { - return; + } + }); + let rawLineData = { + ID: lineObject.expressID, + type: lineObject.type, + arguments: lineObject.ToTape() + }; + this.WriteRawLineData(modelID, rawLineData); + } + FlattenLine(modelID, line) { + Object.keys(line).forEach((propertyName) => { + let property = line[propertyName]; + if (property && property.type === 5) { + line[propertyName] = this.GetLine(modelID, property.value, true); + } else if (Array.isArray(property) && property.length > 0 && property[0].type === 5) { + for (let i = 0; i < property.length; i++) { + line[propertyName][i] = this.GetLine(modelID, property[i].value, true); } - metaObject.withMetaObjectsInSubtree(callback); + } + }); + } + GetRawLineData(modelID, expressID) { + return this.wasmModule.GetLine(modelID, expressID); + } + WriteRawLineData(modelID, data) { + return this.wasmModule.WriteLine(modelID, data.ID, data.type, data.arguments); + } + GetLineIDsWithType(modelID, type) { + return this.wasmModule.GetLineIDsWithType(modelID, type); + } + GetAllLines(modelID) { + return this.wasmModule.GetAllLines(modelID); + } + SetGeometryTransformation(modelID, transformationMatrix) { + if (transformationMatrix.length != 16) { + console.log(`Bad transformation matrix size: ${transformationMatrix.length}`); + return; } -} - -function arrayToMap(array) { - const map = {}; - for (var i = 0, len = array.length; i < len; i++) { - map[array[i]] = true; + this.wasmModule.SetGeometryTransformation(modelID, transformationMatrix); + } + GetCoordinationMatrix(modelID) { + return this.wasmModule.GetCoordinationMatrix(modelID); + } + GetVertexArray(ptr, size) { + return this.getSubArray(this.wasmModule.HEAPF32, ptr, size); + } + GetIndexArray(ptr, size) { + return this.getSubArray(this.wasmModule.HEAPU32, ptr, size); + } + getSubArray(heap, startPtr, sizeBytes) { + return heap.subarray(startPtr / 4, startPtr / 4 + sizeBytes).slice(0); + } + CloseModel(modelID) { + this.ifcGuidMap.delete(modelID); + this.wasmModule.CloseModel(modelID); + } + StreamAllMeshes(modelID, meshCallback) { + this.wasmModule.StreamAllMeshes(modelID, meshCallback); + } + StreamAllMeshesWithTypes(modelID, types, meshCallback) { + this.wasmModule.StreamAllMeshesWithTypes(modelID, types, meshCallback); + } + IsModelOpen(modelID) { + return this.wasmModule.IsModelOpen(modelID); + } + LoadAllGeometry(modelID) { + return this.wasmModule.LoadAllGeometry(modelID); + } + GetFlatMesh(modelID, expressID) { + return this.wasmModule.GetFlatMesh(modelID, expressID); + } + CreateIfcGuidToExpressIdMapping(modelID) { + const map = new Map(); + for (let x = 0; x < IfcElements.length; x++) { + const type = IfcElements[x]; + const lines = this.GetLineIDsWithType(modelID, type); + const size = lines.size(); + for (let y = 0; y < size; y++) { + const expressID = lines.get(y); + const info = this.GetLine(modelID, expressID); + const globalID = info.GlobalId.value; + map.set(expressID, globalID); + map.set(globalID, expressID); + } } - return map; -} + this.ifcGuidMap.set(modelID, map); + } + SetWasmPath(path, absolute = false) { + this.wasmPath = path; + this.isWasmPathAbsolute = absolute; + } +}; /** - * The 3D Viewer at the heart of the xeokit SDK. - * - * * A Viewer wraps a single {@link Scene} - * * Add {@link Plugin}s to a Viewer to extend its functionality. - * * {@link Viewer#metaScene} holds metadata about models in the - * Viewer's {@link MetaScene}. - * * Use {@link Viewer#cameraFlight} to fly or jump the {@link Scene}'s - * {@link Camera} to target positions, boundaries or {@link Entity}s. - * - * @public + * Default data access strategy for {@link WebIFCLoaderPlugin}. */ -class Viewer { - - /** - * @constructor - * @param {Object} cfg Viewer configuration. - * @param {String} [cfg.id] Optional ID for this Viewer, defaults to the ID of {@link Viewer#scene}, which xeokit automatically generates. - * @param {String} [cfg.canvasId] ID of an existing HTML canvas for the {@link Viewer#scene} - either this or canvasElement is mandatory. When both values are given, the element reference is always preferred to the ID. - * @param {HTMLCanvasElement} [cfg.canvasElement] Reference of an existing HTML canvas for the {@link Viewer#scene} - either this or canvasId is mandatory. When both values are given, the element reference is always preferred to the ID. - * @param {HTMLElement} [cfg.keyboardEventsElement] Optional reference to HTML element on which key events should be handled. Defaults to the HTML Document. - * @param {String} [cfg.spinnerElementId] ID of existing HTML element to show the {@link Spinner} - internally creates a default element automatically if this is omitted. - * @param {Number} [cfg.passes=1] The number of times the {@link Viewer#scene} renders per frame. - * @param {Boolean} [cfg.clearEachPass=false] When doing multiple passes per frame, specifies if to clear the canvas before each pass (true) or just before the first pass (false). - * @param {Boolean} [cfg.preserveDrawingBuffer=true] Whether or not to preserve the WebGL drawing buffer. This needs to be ````true```` for {@link Viewer#getSnapshot} to work. - * @param {Boolean} [cfg.transparent=true] Whether or not the canvas is transparent. - * @param {Boolean} [cfg.premultipliedAlpha=false] Whether or not you want alpha composition with premultiplied alpha. Highlighting and selection works best when this is ````false````. - * @param {Boolean} [cfg.gammaInput=true] When true, expects that all textures and colors are premultiplied gamma. - * @param {Boolean} [cfg.gammaOutput=false] Whether or not to render with pre-multiplied gama. - * @param {Number} [cfg.gammaFactor=2.2] The gamma factor to use when rendering with pre-multiplied gamma. - * @param {Number[]} [cfg.backgroundColor=[1,1,1]] Sets the canvas background color to use when ````transparent```` is false. - * @param {Boolean} [cfg.backgroundColorFromAmbientLight=true] When ````transparent```` is false, set this ````true```` - * to derive the canvas background color from {@link AmbientLight#color}, or ````false```` to set the canvas background to ````backgroundColor````. - * @param {String} [cfg.units="meters"] The measurement unit type. Accepted values are ````"meters"````, ````"metres"````, , ````"centimeters"````, ````"centimetres"````, ````"millimeters"````, ````"millimetres"````, ````"yards"````, ````"feet"```` and ````"inches"````. - * @param {Number} [cfg.scale=1] The number of Real-space units in each World-space coordinate system unit. - * @param {Number[]} [cfg.origin=[0,0,0]] The Real-space 3D origin, in current measurement units, at which the World-space coordinate origin ````[0,0,0]```` sits. - * @param {Boolean} [cfg.saoEnabled=false] Whether to enable Scalable Ambient Obscurance (SAO) effect. See {@link SAO} for more info. - * @param {Boolean} [cfg.antialias=true] Whether to enable anti-aliasing. - * @throws {String} Throws an exception when both canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement. - * @param {Boolean} [cfg.alphaDepthMask=true] Whether writing into the depth buffer is enabled or disabled when rendering transparent objects. - * @param {Boolean} [cfg.entityOffsetsEnabled=false] Whether to enable {@link Entity#offset}. For best performance, only set this ````true```` when you need to use {@link Entity#offset}. - * @param {Boolean} [cfg.pickSurfacePrecisionEnabled=false] Whether to enable full-precision accuracy when surface picking with {@link Scene#pick}. Note that when ````true````, this configuration will increase the amount of browser memory used by the Viewer. The ````pickSurfacePrecision```` option for ````Scene#pick```` only works if this is set ````true````. - * @param {Boolean} [cfg.logarithmicDepthBufferEnabled=false] Whether to enable logarithmic depth buffer. When this is true, - * you can set huge values for {@link Perspective#far} and {@link Ortho#far}, to push the far clipping plane back so - * that it does not clip huge models. - * @param {Boolean} [cfg.colorTextureEnabled=true] Whether to enable base color texture rendering. - * @param {Boolean} [cfg.pbrEnabled=false] Whether to enable physically-based rendering. - * @param {LocaleService} [cfg.localeService=null] Optional locale-based translation service. - */ - constructor(cfg) { - - /** - * The Viewer's current language setting. - * @property language - * @deprecated - * @type {String} - */ - this.language = "en"; - - /** - * The viewer's locale service. - * - * This is configured via the Viewer's constructor. - * - * By default, this service will be an instance of {@link LocaleService}, which will just return - * null translations for all given strings and phrases. - * - * @property localeService - * @type {LocaleService} - * @since 2.0 - */ - this.localeService = cfg.localeService || new LocaleService(); - - /** - * The Viewer's {@link Scene}. - * @property scene - * @type {Scene} - */ - this.scene = new Scene(this, { - canvasId: cfg.canvasId, - canvasElement: cfg.canvasElement, - keyboardEventsElement: cfg.keyboardEventsElement, - contextAttr: { - preserveDrawingBuffer: cfg.preserveDrawingBuffer !== false, - premultipliedAlpha: (!!cfg.premultipliedAlpha), - antialias: (cfg.antialias !== false) - }, - spinnerElementId: cfg.spinnerElementId, - transparent: (cfg.transparent !== false), - gammaInput: true, - gammaOutput: false, - backgroundColor: cfg.backgroundColor, - backgroundColorFromAmbientLight: cfg.backgroundColorFromAmbientLight, - ticksPerRender: 1, - ticksPerOcclusionTest: 20, - units: cfg.units, - scale: cfg.scale, - origin: cfg.origin, - saoEnabled: cfg.saoEnabled, - alphaDepthMask: (cfg.alphaDepthMask !== false), - entityOffsetsEnabled: (!!cfg.entityOffsetsEnabled), - pickSurfacePrecisionEnabled: (!!cfg.pickSurfacePrecisionEnabled), - logarithmicDepthBufferEnabled: (!!cfg.logarithmicDepthBufferEnabled), - pbrEnabled: (!!cfg.pbrEnabled), - colorTextureEnabled: (cfg.colorTextureEnabled !== false) - }); - - /** - * Metadata about the {@link Scene} and the models and objects within it. - * @property metaScene - * @type {MetaScene} - * @readonly - */ - this.metaScene = new MetaScene(this, this.scene); - - /** - * The Viewer's ID. - * @property id - * - * @type {String|Number} - */ - this.id = cfg.id || this.scene.id; - - /** - * The Viewer's {@link Camera}. This is also found on {@link Scene#camera}. - * @property camera - * @type {Camera} - */ - this.camera = this.scene.camera; - - /** - * The Viewer's {@link CameraFlightAnimation}, which - * is used to fly the {@link Scene}'s {@link Camera} to given targets. - * @property cameraFlight - * @type {CameraFlightAnimation} - */ - this.cameraFlight = new CameraFlightAnimation(this.scene, { - duration: 0.5 - }); - - /** - * The Viewer's {@link CameraControl}, which - * controls the {@link Scene}'s {@link Camera} with mouse, touch and keyboard input. - * @property cameraControl - * @type {CameraControl} - */ - this.cameraControl = new CameraControl(this.scene, { - // panToPointer: true, - doublePickFlyTo: true - }); - - this._plugins = []; - - /** - * Subscriptions to events sent with {@link fire}. - * @private - */ - this._eventSubs = {}; - } - - /** - * Returns the capabilities of this Viewer. - * - * @returns {{astcSupported: boolean, etc1Supported: boolean, pvrtcSupported: boolean, etc2Supported: boolean, dxtSupported: boolean, bptcSupported: boolean}} - */ - get capabilities() { - return this.scene.capabilities; - } +class WebIFCDefaultDataSource { - /** - * Subscribes to an event fired at this Viewer. - * - * @param {String} event The event - * @param {Function} callback Callback fired on the event - */ - on(event, callback) { - let subs = this._eventSubs[event]; - if (!subs) { - subs = []; - this._eventSubs[event] = subs; - } - subs.push(callback); + constructor() { } /** - * Fires an event at this Viewer. + * Gets the contents of the given IFC file in an arraybuffer. * - * @param {String} event Event name - * @param {Object} value Event parameters + * @param {String|Number} src Path or ID of an IFC file. + * @param {Function} ok Callback fired on success, argument is the IFC file in an arraybuffer. + * @param {Function} error Callback fired on error. */ - fire(event, value) { - const subs = this._eventSubs[event]; - if (subs) { - for (let i = 0, len = subs.length; i < len; i++) { - subs[i](value); + getIFC(src, ok, error) { + var defaultCallback = () => { + }; + ok = ok || defaultCallback; + error = error || defaultCallback; + const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/; + const dataUriRegexResult = src.match(dataUriRegex); + if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest + const isBase64 = !!dataUriRegexResult[2]; + var data = dataUriRegexResult[3]; + data = window.decodeURIComponent(data); + if (isBase64) { + data = window.atob(data); } - } - } - - /** - * Unsubscribes from an event fired at this Viewer. - * @param event - */ - off(event) { // TODO - - } - - /** - * Logs a message to the JavaScript developer console, prefixed with the ID of this Viewer. - * - * @param {String} msg The message - */ - log(msg) { - console.log(`[xeokit viewer ${this.id}]: ${msg}`); - } - - /** - * Logs an error message to the JavaScript developer console, prefixed with the ID of this Viewer. - * - * @param {String} msg The error message - */ - error(msg) { - console.error(`[xeokit viewer ${this.id}]: ${msg}`); - } - - /** - * Installs a Plugin. - * - * @private - */ - addPlugin(plugin) { - this._plugins.push(plugin); - } - - /** - * Uninstalls a Plugin, clearing content from it first. - * - * @private - */ - removePlugin(plugin) { - for (let i = 0, len = this._plugins.length; i < len; i++) { - const p = this._plugins[i]; - if (p === plugin) { - if (p.clear) { - p.clear(); + try { + const buffer = new ArrayBuffer(data.length); + const view = new Uint8Array(buffer); + for (var i = 0; i < data.length; i++) { + view[i] = data.charCodeAt(i); } - this._plugins.splice(i, 1); - return; - } - } - } - - /** - * Sends a message to installed Plugins. - * - * The message can optionally be accompanied by a value. - * @private - */ - sendToPlugins(name, value) { - for (let i = 0, len = this._plugins.length; i < len; i++) { - const p = this._plugins[i]; - if (p.send) { - p.send(name, value); + ok(buffer); + } catch (errMsg) { + error(errMsg); } + } else { + const request = new XMLHttpRequest(); + request.open('GET', src, true); + request.responseType = 'arraybuffer'; + request.onreadystatechange = function () { + if (request.readyState === 4) { + if (request.status === 200) { + ok(request.response); + } else { + error('getXKT error : ' + request.response); + } + } + }; + request.send(null); } } - - /** - * @private - * @deprecated - */ - clear() { - throw "Viewer#clear() no longer implemented - use '#sendToPlugins(\"clear\") instead"; - } - - /** - * @private - * @deprecated - */ - resetView() { - throw "Viewer#resetView() no longer implemented - use CameraMemento & ObjectsMemento classes instead"; - } - - /** - * Enter snapshot mode. - * - * Switches rendering to a hidden snapshot canvas. - * - * Exit snapshot mode using {@link Viewer#endSnapshot}. - */ - beginSnapshot() { - if (this._snapshotBegun) { - return; - } - this.scene._renderer.beginSnapshot(); - this._snapshotBegun = true; - } - - /** - * Gets a snapshot of this Viewer's {@link Scene} as a Base64-encoded image. - * - * #### Usage: - * - * ````javascript - * const imageData = viewer.getSnapshot({ - * width: 500, - * height: 500, - * format: "png" - * }); - * ```` - * @param {*} [params] Capture options. - * @param {Number} [params.width] Desired width of result in pixels - defaults to width of canvas. - * @param {Number} [params.height] Desired height of result in pixels - defaults to height of canvas. - * @param {String} [params.format="jpeg"] Desired format; "jpeg", "png" or "bmp". - * @param {Boolean} [params.includeGizmos=false] When true, will include gizmos like {@link SectionPlane} in the snapshot. - * @returns {String} String-encoded image data URI. - */ - getSnapshot(params = {}) { - - const needFinishSnapshot = (!this._snapshotBegun); - - if (!this._snapshotBegun) { - this.beginSnapshot(); - } - - if (!params.includeGizmos) { - this.sendToPlugins("snapshotStarting"); // Tells plugins to hide things that shouldn't be in snapshot - } - - const resize = (params.width !== undefined && params.height !== undefined); - const canvas = this.scene.canvas.canvas; - const saveWidth = canvas.clientWidth; - const saveHeight = canvas.clientHeight; - const saveCssWidth = canvas.style.width; - const saveCssHeight = canvas.style.height; - - const width = params.width ? Math.floor(params.width) : canvas.width; - const height = params.height ? Math.floor(params.height) : canvas.height; - - if (resize) { - canvas.style.width = width + "px"; - canvas.style.height = height + "px"; - } - - this.scene._renderer.renderSnapshot(); - - const imageDataURI = this.scene._renderer.readSnapshot(params); - - if (resize) { - canvas.style.width = saveCssWidth; - canvas.style.height = saveCssHeight; - canvas.width = saveWidth; - canvas.height = saveHeight; - - this.scene.glRedraw(); - } - - if (!params.includeGizmos) { - this.sendToPlugins("snapshotFinished"); - } - - if (needFinishSnapshot) { - this.endSnapshot(); - } - - return imageDataURI; - } - - /** - * Exits snapshot mode. - * - * Switches rendering back to the main canvas. - * - */ - endSnapshot() { - if (!this._snapshotBegun) { - return; - } - this.scene._renderer.endSnapshot(); - this.scene._renderer.render({force: true}); - this._snapshotBegun = false; - } - - /** Destroys this Viewer. - */ - destroy() { - const plugins = this._plugins.slice(); // Array will modify as we delete plugins - for (let i = 0, len = plugins.length; i < len; i++) { - const plugin = plugins[i]; - plugin.destroy(); - } - this.scene.destroy(); - } -} - -/** - * Manages global configurations for all {@link Viewer}s. - * - * ## Example - * - * In the example below, we'll disable xeokit's double-precision support, which gives a performance and memory boost - * on low-power devices, but also means that we can no longer render double-precision models without jittering. - * - * That's OK if we know that we're not going to view models that are geographically vast, or offset far from the World coordinate origin. - * - * [[Run this example](http://xeokit.github.io/xeokit-sdk/examples/#Configs_disableDoublePrecisionAndRAF)] - * - * ````javascript - * import {Configs, Viewer, XKTLoaderPlugin} from "../dist/xeokit-sdk.es.js"; - * - * // Access xeoit-sdk global configs. - * // We typically set configs only before we create any Viewers. - * const configs = new Configs(); - * - * // Disable 64-bit precision for extra speed. - * // Only set this config once, before you create any Viewers. - * configs.doublePrecisionEnabled = false; - * - * // Create a Viewer, to which our configs apply - * const viewer = new Viewer({ - * canvasId: "myCanvas" - * }); - * - * viewer.camera.eye = [-3.933, 2.855, 27.018]; - * viewer.camera.look = [4.400, 3.724, 8.899]; - * viewer.camera.up = [-0.018, 0.999, 0.039]; - * - * const xktLoader = new XKTLoaderPlugin(viewer); - * - * const model = xktLoader.load({ - * src: "../assets/models/xkt/v8/ifc/Duplex.ifc.xkt" - * }); - * ```` - */ -class Configs { - - /** - * Creates a Configs. - */ - constructor() { - - } - - /** - * Sets whether double precision mode is enabled for Viewers. - * - * When double precision mode is enabled (default), Viewers will accurately render models that contain - * double-precision coordinates, without jittering. - * - * Internally, double precision incurs extra performance and memory overhead, so if we're certain that - * we're not going to render models that rely on double-precision coordinates, then it's a good idea to disable - * it, especially on low-power devices. - * - * This should only be set once, before creating any Viewers. - * - * @returns {boolean} - */ - set doublePrecisionEnabled(doublePrecision) { - math.setDoublePrecisionEnabled(doublePrecision); - } - - /** - * Gets whether double precision mode is enabled for all Viewers. - * - * @returns {boolean} - */ - get doublePrecisionEnabled() { - return math.getDoublePrecisionEnabled(); - } } /** @@ -161621,7 +163123,7 @@ class LASDefaultDataSource { } } -const VERSION = "3.1.8" ; +const VERSION = "3.2.6" ; const DEFAULT_LAS_OPTIONS = { las: { shape: 'mesh', @@ -162860,9 +164362,11 @@ const tempVec3c = math.vec3(); * ## Overview * * * Loads small-to-medium sized models directly from [CityJSON 1.0.0](https://www.cityjson.org/specs/1.0.0/) files. - * * Not recommended for large models. For best performance with large CityJSON datasets, we recommend using {@link XKTLoaderPlugin}. * * Loads double-precision coordinates, enabling models to be viewed at global coordinates without accuracy loss. * * Allows to set the position, scale and rotation of each model as you load it. + * * Not recommended for large models. For best performance with large CityJSON datasets, we recommend + * converting them to ````.xkt```` format (eg. using [convert2xkt](https://github.com/xeokit/xeokit-convert)), then loading + * the ````.xkt```` using {@link XKTLoaderPlugin}. * * ## Limitations * @@ -163370,7 +164874,7 @@ class CityJSONLoaderPlugin extends Plugin { _parseGeometrySurfacesWithSharedMaterial(ctx, geometry, objectMaterial, meshIds) { - ctx.performanceModel; + const sceneModel = ctx.sceneModel; const sharedIndices = []; const geometryCfg = { positions: [], @@ -163416,7 +164920,7 @@ class CityJSONLoaderPlugin extends Plugin { const meshId = "" + ctx.nextId++; - performanceModel.createMesh({ + sceneModel.createMesh({ id: meshId, primitive: "triangles", positions: geometryCfg.positions, @@ -163577,4 +165081,4 @@ class CityJSONLoaderPlugin extends Plugin { } } -export { AlphaFormat, AmbientLight, AngleMeasurementsPlugin, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, BasicDepthPacking, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementsPlugin, EdgeMaterial, EmphasisMaterial, FastNavPlugin, FloatType, Fresnel, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsMemento, Path, PerformanceModel, PhongMaterial, Plugin, PointLight, QuadraticBezierCurve, Queue, RGBADepthPacking, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, VBOSceneModel, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, _SRGBAFormat, buildBoxGeometry, buildBoxLinesGeometry, buildCylinderGeometry, buildGridGeometry, buildPlaneGeometry, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, getKTX2TextureTranscoder, load3DSGeometry, loadOBJGeometry, math, sRGBEncoding, stats, utils }; +export { AlphaFormat, AmbientLight, AngleMeasurementsPlugin, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementsPlugin, EdgeMaterial, EmphasisMaterial, FastNavPlugin, FloatType, Fresnel, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, Mesh, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, Plugin, PointLight, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SectionPlane, SectionPlanesPlugin, ShortType, Skybox, SkyboxesPlugin, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, VBOSceneModel, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, buildBoxGeometry, buildBoxLinesGeometry, buildCylinderGeometry, buildGridGeometry, buildPlaneGeometry, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, getKTX2TextureTranscoder, load3DSGeometry, loadOBJGeometry, math, sRGBEncoding, stats, utils };